Open code423n4 opened 1 year ago
0xSorryNotSorry marked the issue as primary issue
tokens with gt 18 decimals are not supported
ElliotFriedman marked the issue as sponsor disputed
Not mentioned in the documentation, so valid QA
alcueca changed the severity to QA (Quality Assurance)
alcueca marked the issue as grade-a
Lines of code
https://github.com/code-423n4/2023-07-moonwell/blob/main/src/core/Oracles/ChainlinkOracle.sol#L85
Vulnerability details
Impact
The issue lies in the
getPrice
function inside theChainlinkOracle
contract. The function is intended to retrieve the price of the underlying ERC20 token of a given MToken and it adjusts the price based on the token's decimals before returning the final value. The final returned price is scaled by the quantitydecimalDelta
which is calculated as the difference between 18 and the number of decimals of the underlying ERC20 token18 - uint256(token.decimals())
. The issue arises when thegetPrice
function handles underlying ERC20 tokens with more than 18 decimals (which can happen for some tokens), in this case the operationuint256(18).sub(uint256(token.decimals()))
will revert (because of underflow check in the SafeMath library) , this means that the protocol will never be able to get the correct price of such tokens and thus all the lending/borrowing markets functionalities will not work.Proof of Concept
The issue occurs in the
getPrice
function below :As it can be seen after receiving the
price
value fromgetChainlinkPrice
, the function calculates the value ofdecimalDelta
which corresponds to the following subtraction :18 - uint256(token.decimals())
, assuming that we always have18 - uint256(token.decimals()) > 0
.For the calculation the function uses the
sub
method from theSafeMath
library which reverts in case of underflows, this means that if the underlying ERC20 token has more than 18 decimals, we will havetoken.decimals() > 18
which leads thegetPrice
function to always revert due to the underflow protection present in thesub
function.This issue will make it impossible to have any lending/borrow market for all the tokens with more than 18 decimals, as it's impossible for the protocol function to retrieve their prices from the oracle.
Tools Used
Manual review
Recommended Mitigation Steps
To solve this issue there are 2 options :
Make sure that all the underlying ERC20 tokens listed in the protocol have less (or equal) than 18 decimals (While this approach guarantees the protocol's compatibility, it might limit its use if any profitable ERC20 token with more than 18 decimals becomes available).
Modify the
getPrice
function to handle the case wheretoken.decimals() > 18
and allowing the protocol to adapt and avoid encountering a revert situation.Assessed type
Oracle