1.LibUsdOracle::getUsdPrice()
Summary
The LibUsdOracle::getUsdPrice()
function will return values with 6 and 18 decimal points in different situations
Vulnerability Details
function getUsdPrice(address token, uint256 lookback) internal view returns (uint256) {
if (token == C.WETH) {
@> uint256 ethUsdPrice = LibEthUsdOracle.getEthUsdPrice(lookback);
if (ethUsdPrice == 0) return 0;
return uint256(1e24).div(ethUsdPrice);
}
if (token == C.WSTETH) {
@> uint256 wstethUsdPrice = LibWstethUsdOracle.getWstethUsdPrice(lookback);
if (wstethUsdPrice == 0) return 0;
return uint256(1e24).div(wstethUsdPrice);
}
@> uint256 tokenPrice = getTokenPriceFromExternal(token, lookback);
if (tokenPrice == 0) return 0;
return uint256(1e24).div(tokenPrice);
}
LibEthUsdOracle.getEthUsdPrice()
and LibWstethUsdOracle.getWstethUsdPrice()
return values are 6 decimal places, but LibUsdOracle::getTokenPriceFromExternal()
may return values of 6 or 18 decimal places, which eventually leads to LibUsdOracle::getUsdPrice()
returning two results of different precision. Although this method is currently only used for OracleFacet
to obtain prices, if there is a need for expansion in the future, it is recommended to unify the decimal precision of the return value
function getTokenPriceFromExternal(
address token,
uint256 lookback
) internal view returns (uint256 tokenPrice) {
AppStorage storage s = LibAppStorage.diamondStorage();
Implementation memory oracleImpl = s.sys.oracleImplementation[token];
if (oracleImpl.encodeType == bytes1(0x01)) {
address chainlinkOraclePriceAddress = oracleImpl.target;
if (chainlinkOraclePriceAddress == address(0)) {
chainlinkOraclePriceAddress = ChainlinkPriceFeedRegistry(chainlinkRegistry).getFeed(
token,
0x0000000000000000000000000000000000000348
);
}
@> return
uint256(1e24).div(
@> LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
)
);
} else if (oracleImpl.encodeType == bytes1(0x02)) {
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())
);
Implementation memory chainlinkOracleImpl = s.sys.oracleImplementation[chainlinkToken];
address chainlinkOraclePriceAddress = chainlinkOracleImpl.target;
if (chainlinkOraclePriceAddress == address(0)) {
chainlinkOraclePriceAddress = ChainlinkPriceFeedRegistry(chainlinkRegistry).getFeed(
chainlinkToken,
0x0000000000000000000000000000000000000348
);
}
@> uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
);
@> return tokenPrice.mul(chainlinkTokenPrice).div(1e6);
}
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)))
}
}
Code Snippet
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/9bc4330af27b39a4919951d1c635eea58ae65d1b/protocol/contracts/libraries/Oracle/LibUsdOracle.sol#L49-L65
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/9bc4330af27b39a4919951d1c635eea58ae65d1b/protocol/contracts/libraries/Oracle/LibUsdOracle.sol#L100-L175
Impact
LibUsdOracle::getUsdPrice()
returning two results of different precision. Although this method is currently only used for OracleFacet
to obtain prices, if there is a need for expansion in the future, it is recommended to unify the decimal precision of the return value
Tools Used
Manual Review
Recommendations
LibUsdOracle::getUsdPrice()
returning two results of different precision. Although this method is currently only used for OracleFacet
to obtain prices, if there is a need for expansion in the future, it is recommended to unify the decimal precision of the return value
2.ReseedL2Migration::init()
Summary
The contract corresponding to the address of C.BEAN_WSTETH_WELL
in the ReseedL2Migration::init()
method has not been deployed
Vulnerability Details
@> IERC20 beanwsteth = IERC20(C.BEAN_WSTETH_WELL);
uint256 beanwstethBalance = beanwsteth.balanceOf(address(this));
beanwsteth.transfer(BCM, beanwstethBalance);
Code Snippet
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/9bc4330af27b39a4919951d1c635eea58ae65d1b/protocol/contracts/beanstalk/init/reseed/L1/ReseedL2Migration.sol#L40
Impact
The contract corresponding to the address of C.BEAN_WSTETH_WELL
in the ReseedL2Migration::init()
method has not been deployed
Tools Used
Manual Review
Recommendations
Deploy the corresponding contract