15,000 USDC
View results
Submission Details
Severity: gas

Move common code used to get oracle price feed into a separate helper function

Description

In DSCEngine there are 2 functions that retrieve the price from the Chainlink oracle and both have the same operations with regards to determining and rounding to 18 decimals of the feed returned price.

getUsdValue

function getUsdValue(address token, uint256 amount) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
(, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
// 1 ETH = $1000
// The returned value from CL will be 1000 * 1e8
return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
}

getTokenAmountFromUsd

function getTokenAmountFromUsd(address token, uint256 usdAmountInWei) public view returns (uint256) {
// price of ETH (token)
// $/ETH ETH ??
// $2000 / ETH. $1000 = 0.5 ETH
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
(, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
// ($10e18 * 1e18) / ($2000e8 * 1e10)
return (usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION);
}

Recommend Mitigation

Move the price determination function to the OracleLib and implement it while taking into consideration decimals.

Example implementation in libraries/OracleLib.sol:

diff --git a/src/libraries/OracleLib.sol b/src/libraries/OracleLib.sol
index 65c328a..f1345aa 100644
--- a/src/libraries/OracleLib.sol
+++ b/src/libraries/OracleLib.sol
@@ -17,6 +17,7 @@ library OracleLib {
error OracleLib__StalePrice();
uint256 private constant TIMEOUT = 3 hours; // 3 * 60 * 60 = 10800 seconds
+ uint256 private constant ADDITIONAL_FEED_PRECISION = 1e10;
function staleCheckLatestRoundData(AggregatorV3Interface priceFeed)
public
@@ -32,6 +33,16 @@ library OracleLib {
return (roundId, answer, startedAt, updatedAt, answeredInRound);
}
+ function getPrice(AggregatorV3Interface priceFeed)
+ public
+ view
+ returns (uint256)
+ {
+ (, int256 price,,,) = staleCheckLatestRoundData(priceFeed);
+
+ return uint256(price) * ADDITIONAL_FEED_PRECISION;
+ }
+
function getTimeout(AggregatorV3Interface /* chainlinkFeed */ ) public pure returns (uint256) {
return TIMEOUT;
}

and also reimplement the DSCEngine::getUsdValue and DSCEngine::getTokenAmountFromUsd as to use it, as such:

diff --git a/src/DSCEngine.sol b/src/DSCEngine.sol
index a7a6639..03a7925 100644
--- a/src/DSCEngine.sol
+++ b/src/DSCEngine.sol
@@ -342,9 +342,9 @@ contract DSCEngine is ReentrancyGuard {
// $/ETH ETH ??
// $2000 / ETH. $1000 = 0.5 ETH
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
- (, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
- // ($10e18 * 1e18) / ($2000e8 * 1e10)
- return (usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION);
+ uint256 price = priceFeed.getPrice();
+ // ($10e18 * 1e18) / $2000e18
+ return (usdAmountInWei * PRECISION) / price;
}
function getAccountCollateralValue(address user) public view returns (uint256 totalCollateralValueInUsd) {
@@ -360,10 +360,10 @@ contract DSCEngine is ReentrancyGuard {
function getUsdValue(address token, uint256 amount) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
- (, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
+ uint256 price = priceFeed.getPrice();
// 1 ETH = $1000
- // The returned value from CL will be 1000 * 1e8
- return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
+ // The returned value from CL will be 1000 * 1e18
+ return price * amount / PRECISION;
}
function getAccountInformation(address user)

Support

FAQs

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