QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: low
Invalid

ChainlinkOracle underflow when using price feeds with >18 decimals

Summary

The ChainlinkOracle assumes all price feeds have <= 18 decimals through the calculation normalizationFactor = 18 - priceFeed.decimals(). However, this assumption is not enforced in the code and could lead to underflow when integrating price feeds with more than 18 decimals (like NEAR with 24 decimals).

What's the impact?

The contract will revert when attempting to add price feeds with more than 18 decimals due to underflow in the normalization calculation.

This either limits the protocol's compatibility with higher decimal feeds or creates unexpected reverts if such feeds are attempted to be integrated.

PoC:

Add below contract inside pkg/pool-quantamm/test/foundryand then try to run testUnderflowWithHighDecimals :)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "forge-std/Test.sol";
import "../../contracts/mock/MockChainlinkOracles.sol";
contract OracleWrapperTest is Test {
TestChainlinkOracle internal testOracle;
// Test to demonstrate underflow with > 18 decimals
function testUnderflowWithHighDecimals() public {
// This test will show that constructor reverts when decimals > 24
vm.expectRevert();
testOracle = new TestChainlinkOracle(24); // NEAR has 24 decimals
}
// Test to show contract works with <= 18 decimals
function testWorksWithStandardDecimals() public {
// These should work fine
testOracle = new TestChainlinkOracle(18); // Works with 18 decimals
testOracle = new TestChainlinkOracle(8); // Works with 8 decimals
}
}
// Changed name to TestChainlinkOracle to avoid conflict
contract TestChainlinkOracle {
uint8 private immutable decimals_;
uint256 internal immutable normalizationFactor;
constructor(uint8 _decimals) {
decimals_ = _decimals;
// This will underflow if _decimals > 18
normalizationFactor = 18 - _decimals;
}
function decimals() external view returns (uint8) {
return decimals_;
}
}

Recommendation

If supporting only ≤18 decimal feeds is a design choice:

constructor(address _chainlinkFeed) {
require(_chainlinkFeed != address(0), "INVADDR");
priceFeed = AggregatorV3Interface(_chainlinkFeed);
uint8 decimals = priceFeed.decimals();
require(decimals <= 18, "Oracle decimals must be <= 18");
normalizationFactor = 18 - decimals;
}

If support for >18 decimal feeds is needed:

constructor(address _chainlinkFeed) {
require(_chainlinkFeed != address(0), "INVADDR");
priceFeed = AggregatorV3Interface(_chainlinkFeed);
uint8 decimals = priceFeed.decimals();
// Handle both cases where decimals can be greater or less than 18
if (decimals > 18) {
normalizationFactor = decimals - 18;
isDecimalsGreaterThan18 = true;
} else {
normalizationFactor = 18 - decimals;
isDecimalsGreaterThan18 = false;
}
}
function _getData() internal view override returns (int216, uint40) {
(, int256 data,, uint256 timestamp,) = priceFeed.latestRoundData();
require(data > 0, "INVLDDATA");
// Adjust calculation based on decimal comparison
data = isDecimalsGreaterThan18 ?
data / int256(10 ** normalizationFactor) :
data * int256(10 ** normalizationFactor);
return (int216(data), uint40(timestamp));
}
Updates

Lead Judging Commences

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Appeal created

0xtheblackpanther Submitter
7 months ago
n0kto Lead Judge
6 months ago
n0kto Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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