DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: medium
Valid

LibUsdOracle incorrectly assumes that USDC/USD and USDT/USD Chainlink price feeds have 1 hour heartbeat

Summary

If oracleImpl.encodeType == bytes1(0x02) then it means that it firstly fetches price from Token/Stablecoin on Uniswap, and then fetches Stablecoin/USD from Chainlink where Stablecoin is USDC or USDT. Problem is that it invalidates answer most of the time because of incorrect timeout.

Vulnerability Details

Here it fetches stablecoin price:

function getTokenPriceFromExternal(
address token,
uint256 lookback
) internal view returns (uint256 tokenPrice) {
...
} else if (oracleImpl.encodeType == bytes1(0x02)) {
// assumes a dollar stablecoin is passed in
// if the encodeType is type 2, use a uniswap oracle implementation.
address chainlinkToken = IUniswapV3PoolImmutables(oracleImpl.target).token0();
chainlinkToken = chainlinkToken == token
? IUniswapV3PoolImmutables(oracleImpl.target).token1()
: token;
tokenPrice = LibUniswapOracle.getTwap(
lookback == 0 ? LibUniswapOracle.FIFTEEN_MINUTES : uint32(lookback),
oracleImpl.target,
chainlinkToken,
token,
uint128(10) ** uint128(IERC20Decimals(token).decimals())
);
// USDC/USD
// call chainlink oracle from the OracleImplmentation contract
Implementation memory chainlinkOracleImpl = s.sys.oracleImplementation[chainlinkToken];
address chainlinkOraclePriceAddress = chainlinkOracleImpl.target;
if (chainlinkOraclePriceAddress == address(0)) {
// use the chainlink registry
chainlinkOraclePriceAddress = ChainlinkPriceFeedRegistry(chainlinkRegistry).getFeed(
chainlinkToken,
0x0000000000000000000000000000000000000348
); // 0x0348 is the address for USD
}
uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
@> LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
);
return tokenPrice.mul(chainlinkTokenPrice).div(1e6);
}
...

However USDC and USDT price feeds have 1 day heartbeat:

  1. https://data.chain.link/feeds/ethereum/mainnet/usdc-usd

  2. https://data.chain.link/feeds/ethereum/mainnet/usdt-usd

Impact

Most of the time price of Stablecoin will be unavailable, i.e. 20 hours a day. It will return 0 price most of the time.

Tools Used

Manual Review

Recommendations

Use 4 day timeout:

uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
- LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
+ LibChainlinkOracle.FOUR_DAY_TIMEOUT,
lookback
);
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Using 4 hour heartbeat for USDC/USD chainlink price feed which has a 24 h heartbeat

Appeal created

golanger85 Auditor
11 months ago
T1MOH Submitter
11 months ago
inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Using 4 hour heartbeat for USDC/USD chainlink price feed which has a 24 h heartbeat

Support

FAQs

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