Open code423n4 opened 1 year ago
https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CTokenV3Collateral.sol#L56 https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CusdcV3Wrapper.sol#L46 https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CusdcV3Wrapper.sol#L236
CTokenV3Collateral._underlyingRefPerTok uses erc20Decimals which is the decimals of CusdcV3Wrapper. But it should use the decimals of the underlying Comet.
CTokenV3Collateral._underlyingRefPerTok
erc20Decimals
CusdcV3Wrapper
CTokenV3Collateral._underlyingRefPerTokcomputes the actual quantity of whole reference units per whole collateral tokens. And it passeserc20Decimalstoshiftl_toFix` https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CTokenV3Collateral.sol#L56
computes the actual quantity of whole reference units per whole collateral tokens. And it passes
to
function _underlyingRefPerTok() internal view virtual override returns (uint192) { return shiftl_toFix(ICusdcV3Wrapper(address(erc20)).exchangeRate(), -int8(erc20Decimals)); }
However, the correct decimals should be the decimals of underlying Comet since it is used in CusdcV3Wrapper.exchangeRate https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CusdcV3Wrapper.sol#L236
CusdcV3Wrapper.exchangeRate
function exchangeRate() public view returns (uint256) { (uint64 baseSupplyIndex, ) = getUpdatedSupplyIndicies(); return presentValueSupply(baseSupplyIndex, safe104(10**underlyingComet.decimals())); }
Manual Review
function _underlyingRefPerTok() internal view virtual override returns (uint192) { - return shiftl_toFix(ICusdcV3Wrapper(address(erc20)).exchangeRate(), -int8(erc20Decimals)); + return shiftl_toFix(ICusdcV3Wrapper(address(erc20)).exchangeRate(), -int8(comet.decimals())); }
Decimal
thereksfour marked the issue as primary issue
tbrent marked the issue as sponsor confirmed
https://github.com/reserve-protocol/protocol/pull/889
thereksfour marked the issue as satisfactory
thereksfour marked the issue as selected for report
Lines of code
https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CTokenV3Collateral.sol#L56 https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CusdcV3Wrapper.sol#L46 https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CusdcV3Wrapper.sol#L236
Vulnerability details
Impact
CTokenV3Collateral._underlyingRefPerTok
useserc20Decimals
which is the decimals ofCusdcV3Wrapper
. But it should use the decimals of the underlying Comet.Proof of Concept
CTokenV3Collateral._underlyingRefPerTok
computes the actual quantity of whole reference units per whole collateral tokens. And it passes
erc20Decimalsto
shiftl_toFix` https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CTokenV3Collateral.sol#L56However, the correct decimals should be the decimals of underlying Comet since it is used in
CusdcV3Wrapper.exchangeRate
https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/compoundv3/CusdcV3Wrapper.sol#L236Tools Used
Manual Review
Recommended Mitigation Steps
Assessed type
Decimal