HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: low
Invalid

Standard ERC20 tokens without decimals() function cannot be registered

Summary

Standard ERC20 tokens without decimals() function cannot be registered

Vulnerability Details

According to docs, compatible tokens must have 6-18 decimals and NOT be rebasable/fee-on-tranfer. When trying to register a collateralToken, _registerCollateralToken() will call * *_collateralTokenContract.decimals() to deploy the corresponding wToken. However this function is NOT mandatory in ERC20 tokens as indicated by EIP20, and other contracts MUST NOT expect this function to be present in the ERC20 token they are dealing with: https://eips.ethereum.org/EIPS/eip-20#decimals

_collateralTokenContract.decimals() will revert when called on a token that does not implement decimals() function.

Impact

Tokens that fulfill the protocol compatibility criteria (6-18 decimals, NOT rebase/fee-on-transfer and registered in Aave) without decimals() function cannot be registered as collateral tokens, taking into account decimals() function is NOT mandatory and contracts interacting with ERC20 tokens must not expect them to implement decimals() function (according to EIP20)

Tools Used

Manual review

Recommendations

Do not revert in case decimals() function is NOT present. As `registerCollateralToken()` can only be called by owner, use an additional parameter in case decimals() function does not exist:

- function _registerCollateralToken(address _collateralToken) internal returns (address) {
+ function _registerCollateralToken(address _collateralToken, uint8 _decimals) internal returns (address) {
// Verify that the collateral token is not yet registered.
if (_collateralTokenToWToken[_collateralToken] != address(0)) {
revert CollateralTokenAlreadyRegistered();
}
// Retrieve the aToken address associated with the provided collateral token from Aave V3. Reverts if
// the collateral token is not supported by Aave V3.
// Note: aTokens have the same number of decimals as the collateral token: https://discord.com/channels/602826299974877205/636902500041228309/1249607036417867810
address _aToken = _getAToken(_collateralToken);
if (_aToken == address(0)) {
revert UnsupportedCollateralToken();
}
IERC20Metadata _collateralTokenContract = IERC20Metadata(_collateralToken);
// Deploy a token that represents a wrapped version of the collateral token to be used as proxy collateral in DIVA Protocol.
// The symbol and name of the wToken are derived from the original collateral token, prefixed with 'w' (e.g., wUSDT or wUSDC).
// This naming convention helps in identifying the token as a wrapped version of the original collateral token.
// The wToken decimals are aligned with those of the collateral token and the aToken.
// This contract is set as the owner and has exclusive rights to mint and burn the wToken.
WToken _wTokenContract = new WToken(
string(abi.encodePacked("w", _collateralTokenContract.symbol())),
- _collateralTokenContract.decimals(),
+ _decimals >= 6 ? _decimals : _collateralTokenContract.decimals(),
address(this) // wToken owner
);
address _wToken = address(_wTokenContract);
// Map collateral token to its corresponding wToken.
_collateralTokenToWToken[_collateralToken] = _wToken;
// Map wToken to its corresponding collateral token to facilitate reverse lookups.
_wTokenToCollateralToken[_wToken] = _collateralToken;
// Set unlimited approval for the wToken transfer to DIVA Protocol and the collateral token transfer to Aave V3. This setup reduces
// the need for repeated approval transactions, thereby saving on gas costs.
// The unlimited approvals are deemed safe as the `AaveDIVAWrapper` is a pass-through entity that does not hold excess wTokens or collateral tokens.
// Should a vulnerability be discovered in DIVA Protocol or Aave, users can simply stop interacting with the `AaveDIVAWrapper` contract.
//
// Note that granting an infinite allowance for wToken does not reduce the allowance on `transferFrom` as it uses a newer OpenZeppelin ERC20 implementation.
// However, this behavior may differ for collateral tokens like USDC, DAI, or WETH used in Aave. These tokens decrement the allowance with each use of
// `transferFrom`, even if an unlimited allowance is set. Consequently, though very unlikely, AaveDIVAWrapper could eventually exhaust its allowance.
// The `approveCollateralTokenForAave` function has been implemented to manually reset the allowance to unlimited.
_wTokenContract.approve(_diva, type(uint256).max);
_collateralTokenContract.approve(_aaveV3Pool, type(uint256).max);
emit CollateralTokenRegistered(_collateralToken, _wToken);
return _wToken;
}
Updates

Lead Judging Commences

bube Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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