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

The `LibUsdOracle::getUsdPrice()` function will return values ​​with 6 and 18 decimal points in different situations

1.LibUsdOracle::getUsdPrice()

Summary

The LibUsdOracle::getUsdPrice() function will return values ​​with 6 and 18 decimal points in different situations

Vulnerability Details

// LibUsdOracle::getUsdPrice()
function getUsdPrice(address token, uint256 lookback) internal view returns (uint256) {
if (token == C.WETH) {
@> uint256 ethUsdPrice = LibEthUsdOracle.getEthUsdPrice(lookback); // 1e6
if (ethUsdPrice == 0) return 0;
return uint256(1e24).div(ethUsdPrice);
}
if (token == C.WSTETH) {
@> uint256 wstethUsdPrice = LibWstethUsdOracle.getWstethUsdPrice(lookback); // 1e6
if (wstethUsdPrice == 0) return 0;
return uint256(1e24).div(wstethUsdPrice);
}
// 1e18 * 1e6 = 1e24.
@> uint256 tokenPrice = getTokenPriceFromExternal(token, lookback); // The return value of the `getTokenPriceFromExternal()` method can have 18 decimal places.
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 the encode type is type 1, use the default chainlink implementation instead.
// `target` refers to the address of the price aggergator implmenation
if (oracleImpl.encodeType == bytes1(0x01)) {
// if the address in the oracle implementation is 0, use the chainlink registry to lookup address
address chainlinkOraclePriceAddress = oracleImpl.target;
if (chainlinkOraclePriceAddress == address(0)) {
// use the chainlink registry
chainlinkOraclePriceAddress = ChainlinkPriceFeedRegistry(chainlinkRegistry).getFeed(
token,
0x0000000000000000000000000000000000000348
); // 0x0348 is the address for USD
}
@> return // 18
uint256(1e24).div(
@> LibChainlinkOracle.getTokenPrice( // 6
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
)
);
} 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( //18
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( //6
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
);
@> return tokenPrice.mul(chainlinkTokenPrice).div(1e6); // 18
}
// If the oracle implementation address is not set, use the current contract.
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))) //unknown
}
}

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

// BEAN:WstETH
@> 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

Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

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

`getUsdPrice` returns mixed decimals

Support

FAQs

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