Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: low
Invalid

[M-3] `TokenManager::tillIn` will lose user's funds if user mistakenly sends msg.value > params.amount

Summary

The TokenManager::tillIn function, which is responsible for receiving funds into the capital pool, contains a vulnerability that can result in the loss of user funds. The function receives an amount parameter used to transfer ERC20, but native token is sent as msg.value. Although there is a safeguard to prevent accepting msg.value less than amount, any excess msg.value sent above amount is not accounted for, leading to a loss of funds.

Vulnerability Details

The TokenManager::tillIn function is designed to receive funds and update internal accounting accordingly. The function ensures that msg.value is at least equal to amount, but it fails to account for cases where msg.value exceeds amount. Here is the relevant code snippet:

@> if (msg.value < _amount) {
revert Errors.NotEnoughMsgValue(msg.value, _amount);
}
@> IWrappedNativeToken(wrappedNativeToken).deposit{value: _amount}();
_safe_transfer(wrappedNativeToken, capitalPoolAddr, _amount);

The issue arises because the function only updates the capitalPoolBalance with the value of amount, ignoring any excess funds provided in msg.value. As a result:

  1. A user might mistakenly send more native tokens than intended by setting msg.value higher than amount.

  2. The function only credits the capitalPoolBalance with the amount parameter, causing any extra funds in msg.value to be effectively lost and unaccounted for.

Impact

This vulnerability can lead to the loss of user funds. Users who mistakenly send more native tokens than specified in the amount parameter will lose the excess funds, as they are not credited to the capital pool or refunded.

The following test case, which can be included in the TokenManager.t.sol, demonstrates the issue:

function testLossOfFundsWithExcessMsgValue() public {
address confusedUser = address(preMarktes); // preMarkets address is used to illustrate because only related addresses can call the function tillIn - this was done for the sake of simplicity. The same concept would apply if an user send native token through any external function that calls tillIn
uint256 STARTING_BALANCE = 10e18;
uint256 AMOUNT = 1e18;
uint256 EXCESS_VALUE = 2e18;
deal(address(confusedUser), STARTING_BALANCE);
uint256 capitalPoolBalanceBefore = weth9.balanceOf(
address(capitalPool)
);
uint256 confusedUserBalanceBefore = confusedUser.balance;
vm.startPrank(address(confusedUser));
tokenManager.tillIn{value: EXCESS_VALUE}(
address(confusedUser),
address(weth9),
AMOUNT,
false
);
vm.stopPrank();
uint256 capitalPoolBalanceAfter = weth9.balanceOf(address(capitalPool));
uint256 confusedUserBalanceAfter = confusedUser.balance;
uint256 deltaCapitalPool = capitalPoolBalanceAfter -
capitalPoolBalanceBefore;
uint256 deltaConfusedUser = confusedUserBalanceBefore -
confusedUserBalanceAfter;
assert(deltaConfusedUser > deltaCapitalPool);
}

Tools Used

Manual code review.

Recommendations

To prevent the loss of user funds, the function should be updated to handle cases where msg.value exceeds amount. Two alternatives are illustrated below:

  1. Revert transactions when msg.value != _amount

+ if (msg.value != _amount) {
- if (msg.value < _amount) {
revert Errors.NotEnoughMsgValue(msg.value, _amount);
}
IWrappedNativeToken(wrappedNativeToken).deposit{value: _amount}();
_safe_transfer(wrappedNativeToken, capitalPoolAddr, _amount);
  1. Call deposit with {value: msg.value}

if (msg.value < _amount) {
revert Errors.NotEnoughMsgValue(msg.value, _amount);
}
+ IWrappedNativeToken(wrappedNativeToken).deposit{value: msg.value}();
+ _safe_transfer(wrappedNativeToken, capitalPoolAddr, msg.value);
- IWrappedNativeToken(wrappedNativeToken).deposit{value: _amount}();
- _safe_transfer(wrappedNativeToken, capitalPoolAddr, _amount);
Updates

Lead Judging Commences

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

[invalid] finding-TokenManager-tillin-excess

Invalid, these are by default, invalid based on codehawks [general guidelines](https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity#findings-that-may-be-invalid). The check implemented is simply a sufficiency check, it is users responsibility to only send an appropriate amount of native tokens where amount == msg.value when native token is intended to be used as collateral (which will subsequently be deposited as wrapped token). All excess ETH can be rescued using the `Rescuable.sol` contract. > Users sending ETH/native tokens > If contracts allow users to send tokens acc111identally.

Support

FAQs

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