Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: medium
Valid

TokenManager doesn't work correctly with ERC20 wrappers of native tokens

Summary

TokenManager.sol documentation says that it should accept either ERC20 or a native token but the check in tillInfunction for native tokens is wrong - initializing TokenManager with the address of the wrapped token(as done in the tests provided) and passing that address as tokenAddressin params means that the tillInfunction will never work with the wrapped(WETH) token and will always wrap the native token(ETH) first.

Vulnerability Details

The check in https://github.com/Cyfrin/2024-08-tadle/blob/main/src/core/TokenManager.sol#L79-L80 for checking if transferring a native token means that it'll never work with the wrapped token because it checks if if (_tokenAddress == wrappedNativeToken),with wrappedNativeTokenaddress being the address of the wrapped token i.e having native token to be ETH, wrappedNativeToken will be WETH so when depositing a native token, if the _tokenAddressis 0x0, as it's supposed to be according to part of the documentation, transferring the native token will never work because it'll try to transfer it as a normal ERC20 token.

Otherwise, if the _tokenAddressis the address of the wrapped native token, as it is done in the provided tests, it'll always transfer the native token first and then wrap it. In this case, it's impossible to deposit the ERC20 wrapped token, as the code always requires to have the native token available.

Excerpt of the tillIn code in TokenManager.sol:

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);
}
IWrappedNativeToken(wrappedNativeToken).deposit{value: _amount}();
_safe_transfer(wrappedNativeToken, capitalPoolAddr, _amount);
} else {
/// @notice token is ERC20 token
_transfer(
_tokenAddress,
_accountAddress,
capitalPoolAddr,
_amount,
capitalPoolAddr
);
}

Impact

This breaks one of the main functionalities of the contract to accept native tokens and wrapped ERC20 tokens.

Tools Used

Manual review

Recommendations

If 0x0 is supposed to be internally viewed as the native ETH token, fix the check to that and use that in offer params, but the convention is to use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee:

if (_tokenAddress == 0x0000000000000000000000000000000000000000)
Updates

Lead Judging Commences

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-TokenManager-tillin-wrapper-inconsistent

Valid medium severity, given it is noted in contest READ.ME that any standard ERC20 tokens should be supported. Although arguably could be low severity, given users can simply unwrap WETH to native ETH and perform the deposits via `tillIn()`, I will leave open for discussions, but taking READ.ME as the source of truth, I believe medium severity is appropriate, given it is explicitly noted that this token should be compatible#9##. The fix would be to utilize a zero address or equivalent to represent native ETH when wrapping to WETH. > Tokens: - ETH - WETH - ERC20 (any token that follows the ERC20 standard)

Support

FAQs

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