Misalignment Due to Hardcoded Decimal Assumption in Chainlink Oracle Integration #397
Labels
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
edited-by-warden
grade-b
Q-37
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
🤖_primary
AI based primary recommendation
🤖_55_group
AI based duplicate group recommendation
sponsor acknowledged
Technically the issue is correct, but we're not going to resolve it for XYZ reasons
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Oracle/RenzoOracle.sol#L79-L80
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Oracle/RenzoOracle.sol#L96-L97
Vulnerability details
Impact
The impact of this issue stems from
HAL-01
of the Halborn audit for an inadequate mitigation. Currently,RenzoOracle.sol
assumes that all Chainlink oracles will return prices with a decimal precision of 18. This assumption is hardcoded into the contract’s logic for price calculations. If Chainlink or any other used oracle service changes the decimal precision for any price feed, the smart contract will still perform calculations assuming 18 decimals, which can lead to significant financial discrepancies. This could result in incorrect asset valuations, under or over-issuance of tokens, and potentially exploitable conditions if the discrepancy is identified by malicious actors. The financial stakes and trust in the protocol could be severely compromised.Specifically, the following two calls will be affected when referencing/calling:
renzoOracle.lookupTokenValue
by RestakeManager.calculateTVLs()renzoOracle.lookupTokenAmountFromValue
by WithdrawQueue.withdraw()Proof of Concept
The
setOracleAddress
function explicitly checks and enforces that the decimals for a newly set oracle address are 18:https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Oracle/RenzoOracle.sol#L60-L62
However, if the decimals of an oracle were to change after this initial setting (which is possible if Chainlink updates an oracle contract), the
lookupTokenValue
andlookupTokenAmountFromValue
functions do not check or adapt to this change, as they use a hardcoded scale factor based on 18 decimals:https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Oracle/RenzoOracle.sol#L79-L80
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Oracle/RenzoOracle.sol#L96-L97
As an example how Chainlink could possibly change
decimal()
(say from 18 to 8 or some other integer), let's dive into the verified contract of STETH / ETH price feed. As seen in the current code snippet,decimals()
of the price feed contract is dependent oncurrentPhase.aggregator.decimals()
:https://etherscan.io/address/0x86392dC19c0b719886221c78AB11eb8Cf5c52812#code#L431
And notably, the contract owner is allowed to propose and confirm/change the aggregator:
https://etherscan.io/address/0x86392dC19c0b719886221c78AB11eb8Cf5c52812#code#L481
Consequently,
currentPhase
will be changed by invokingsetAggregator()
in the code block above:https://etherscan.io/address/0x86392dC19c0b719886221c78AB11eb8Cf5c52812#code#L495
In conclusion, while the hardcoding approach has some gas saving benefit, it does not justify a high/critical impact ahead albeit at a low likelihood.
Tools Used
Manual
Recommended Mitigation Steps
Modify the contract to retrieve and use the decimal value from the oracle dynamically within each function that requires price data. This can ensure that any changes in decimal precision are handled correctly at runtime.
For instance,
lookupTokenValue()
may be refactored as follows:https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Oracle/RenzoOracle.sol#L71-L81
Assessed type
Decimal
The text was updated successfully, but these errors were encountered: