Summary
It verifies oracle address and selector by performing staticCall()
:
function verifyOracleImplementation(
address oracleImplementation,
bytes4 selector,
bytes1 encodeType
) internal view {
bool success;
if (encodeType == bytes1(0x01)) {
(success, ) = oracleImplementation.staticcall(
abi.encodeWithSelector(IChainlinkAggregator.decimals.selector)
);
} else if (encodeType == bytes1(0x02)) {
(success, ) = oracleImplementation.staticcall(abi.encodeWithSelector(0x0dfe1681));
} else {
@> (success, ) = oracleImplementation.staticcall(abi.encodeWithSelector(selector, 0));
}
require(success, "Whitelist: Invalid Oracle Implementation");
}
However this check is not consistent with actual LibUsdOracle logic. Because address(0)
is special value which is replaced with address(this
:
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/main/protocol/contracts/libraries/Oracle/LibUsdOracle.sol#L163-L174
function getTokenPriceFromExternal(
address token,
uint256 lookback
) internal view returns (uint256 tokenPrice) {
...
address target = oracleImpl.target;
@> if (target == address(0)) target = address(this);
(bool success, bytes memory data) = target.staticcall(
abi.encodeWithSelector(oracleImpl.selector, lookback)
);
if (!success) return 0;
assembly {
tokenPrice := mload(add(data, add(0x20, 0)))
}
}
Impact
Custom oracle selector is incorrectly validated. As a result it won't catch incorrect selector.
Tools Used
Manual Review
Recommendations
} else {
+ if (oracleImplementation == address(0)) oracleImplementation = address(this);
// verify you passed in a callable oracle selector
(success, ) = oracleImplementation.staticcall(abi.encodeWithSelector(selector, 0));
}