Description
Mitigation of M-03: Fully Alleviated
The sponsor introduced numerous changes to the MCAGRateFeed
to support the new price staleness threshold mechanism. In detail, they introduced a _stalenessThreshold
variable that is set during the contract's constructor
and can be adjusted by the contract's KUMA_MANAGER_ROLE
role via its dedicated MCAGRateFeed::setStalenessThreshold
function.
The MCAGRateFeed::getRate
function was updated to utilize this variable by storing the updatedAt
variable yielded by the MCAGAggregator::latestRoundDate
function, subtracting it from the current block.timestamp
, and ultimately yielding an error if the delta is greater than the threshold.
The changes were introduced in an exemplary manner, introducing a new event that signifies when the threshold has been changed, sanitizing its value as non-zero at all times, and containing an explicit getter function for it.
As a matter of optimization, the code of MCAGRateFeed::setStalenessThreshold
could be refactored to an internal underscore-prefixed function that is used by the contract's constructor
as well, minimizing code duplication.
A snippet of the contract with the remediated code showcased can be found below:
/**
* @param riskCategory Unique risk category identifier computed with keccack256(abi.encode(currency, country, term))
* @return rate Oracle rate in 27 decimals.
*/
function getRate(bytes32 riskCategory) external view override returns (uint256) {
MCAGAggregatorInterface oracle = _oracles[riskCategory];
/**
* MITIGATION BLOCK OF M-03 START
*/
(, int256 answer,, uint256 updatedAt,) = oracle.latestRoundData();
if (block.timestamp - updatedAt > _stalenessThreshold) {
revert Errors.ORACLE_ANSWER_IS_STALE();
}
/**
* MITIGATION BLOCK END
*/
if (answer < 0) {
return _MIN_RATE_COUPON;
}
uint256 rate = uint256(answer);
uint8 oracleDecimal = oracle.decimals();
if (_DECIMALS < oracleDecimal) {
rate = uint256(answer) / (10 ** (oracleDecimal - _DECIMALS));
} else if (_DECIMALS > oracleDecimal) {
rate = uint256(answer) * 10 ** (_DECIMALS - oracleDecimal);
}
if (rate < _MIN_RATE_COUPON) {
return _MIN_RATE_COUPON;
}
return rate;
}
We consider this change sufficient to protect against outdated prices based on the fact that the KUMA Protocol team adequately configures the contract's _stalenessThreshold
value.
The tests of the KUMA Protocol had to be updated to support the new construction mechanism of MCAGRateFeed
and two new tests were introduced to the codebase's MCAGRateFeedTest.t.sol
file that validate the setter function of the MCAGRateFeed::setStalenessThreshold
as well as the getRate
function behave as expected.