Platform: Code4rena
Start Date: 10/11/2023
Pot Size: $28,000 USDC
Total HM: 5
Participants: 185
Period: 5 days
Judge: 0xDjango
Id: 305
League: ETH
Rank: 145/185
Findings: 1
Award: $2.76
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: m_Rassska
Also found by: 0x1337, 0xAadi, 0xHelium, 0xLeveler, 0xblackskull, 0xbrett8571, 0xepley, 0xffchain, 0xluckhu, 0xmystery, 0xrugpull_detector, 0xvj, ABAIKUNANBAEV, Aamir, AerialRaider, Amithuddar, Bauchibred, Bauer, CatsSecurity, Cryptor, Daniel526, Draiakoo, Eigenvectors, ElCid, GREY-HAWK-REACH, Inspecktor, Juntao, King_, LinKenji, Madalad, MaslarovK, Matin, MatricksDeCoder, McToady, Noro, PENGUN, Pechenite, Phantasmagoria, RaoulSchaffranek, SBSecurity, SandNallani, Shaheen, Soul22, Stormreckson, T1MOH, Tadev, TeamSS, TheSchnilch, Topmark, Tumelo_Crypto, Udsen, Yanchuan, ZanyBonzy, _thanos1, adeolu, adriro, alexfilippov314, almurhasan, amaechieth, anarcheuz, ayden, baice, bareli, boredpukar, bronze_pickaxe, btk, cartlex_, catellatech, chaduke, cheatc0d3, circlelooper, codynhat, crack-the-kelp, critical-or-high, debo, deepkin, desaperh, dipp, eeshenggoh, evmboi32, ge6a, gesha17, glcanvas, gumgumzum, hals, hihen, hunter_w3b, jasonxiale, joaovwfreire, ke1caM, leegh, lsaudit, marchev, merlinboii, niser93, osmanozdemir1, paritomarrr, passion, pep7siup, phoenixV110, pipidu83, poneta, ro1sharkm, rouhsamad, rvierdiiev, sakshamguruji, seerether, shealtielanz, soliditytaker, spark, squeaky_cactus, stackachu, supersizer0x, tallo, taner2344, turvy_fuzz, twcctop, ubl4nk, wisdomn_, xAriextz, zach, zhaojie, zhaojohnson, ziyou-
2.7592 USDC - $2.76
According to Chainlink's documentation, lastestAnswer()
is deprecated and should no be used.
Furthermore, the use of this function does not allow Kelp DAO to check the freshness of the price gotten.
This function will not revert if no answer was reached by the oracle and will return 0 instead.
This will affect Kelp if LRTOracle
uses ChainlinkPriceOracle
as the "PriceFetcher".
If no answer is found by the oracle, getAssetPrice(asset)
will return 0. The main area of concern is with getRSETHPrice()
function:
If assetER = 0
then the return value of the getRSETHPrice()
function will also be 0, reverting that specific deposit in LRTDepositPool
as it is impossible to divide by 0:
https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTDepositPool.sol#L109
see: https://docs.chain.link/data-feeds/api-reference#latestanswer
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import { BaseTest } from "./BaseTest.t.sol"; import { LRTDepositPool } from "src/LRTDepositPool.sol"; import { RSETHTest, ILRTConfig, UtilLib, LRTConstants } from "./RSETHTest.t.sol"; import { ILRTDepositPool } from "src/interfaces/ILRTDepositPool.sol"; import "forge-std/console.sol"; import { LRTOracle } from "src/LRTOracle.sol"; import {IPriceFetcher} from "src/interfaces/IPriceFetcher.sol"; import { TransparentUpgradeableProxy } from "lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; contract LRTDepositPoolTest is BaseTest, RSETHTest { LRTDepositPool public lrtDepositPool; LRTOracle public lrtOracle; address public rETHAddress; IPriceFetcher public priceFetcher; ILRTDepositPool public depositPool; function setUp() public virtual override(RSETHTest, BaseTest) { super.setUp(); rETHAddress = address(rETH); // deploy LRTDepositPool ProxyAdmin proxyAdmin = new ProxyAdmin(); LRTDepositPool contractImpl = new LRTDepositPool(); TransparentUpgradeableProxy contractProxy = new TransparentUpgradeableProxy( address(contractImpl), address(proxyAdmin), "" ); LRTOracle lrtOracleImpl = new LRTOracle(); TransparentUpgradeableProxy lrtOracleProxy = new TransparentUpgradeableProxy( address(lrtOracleImpl), address(proxyAdmin), "" ); lrtDepositPool = LRTDepositPool(address(contractProxy)); // initialize RSETH. LRTCOnfig is already initialized in RSETHTest rseth.initialize(address(admin), address(lrtConfig)); vm.startPrank(admin); // add rsETH to LRT config lrtConfig.setRSETH(address(rseth)); // add oracle to LRT config lrtOracle = LRTOracle(address(lrtOracleProxy)); lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(lrtOracle)); // add minter role for rseth to lrtDepositPool rseth.grantRole(rseth.MINTER_ROLE(), address(lrtDepositPool)); vm.stopPrank(); } function test_OracleBug() external { vm.mockCall(address(priceFetcher), abi.encodeWithSelector(IPriceFetcher.getAssetPrice.selector), abi.encode(1 ether)); //Assume LST token price is 1 ether vm.mockCall(address(depositPool), abi.encodeWithSelector(ILRTDepositPool.getTotalAssetDeposits.selector), abi.encode(0)); // assume first deposit. lrtOracle.initialize(address(lrtConfig)); lrtDepositPool.initialize(address(lrtConfig)); vm.startPrank(alice); deal(address(rETH), alice, 1000 ether); rETH.approve(address(lrtDepositPool), 1000 ether); lrtDepositPool.depositAsset(rETHAddress, 3 ether); vm.mockCall(address(priceFetcher), abi.encodeWithSelector(IPriceFetcher.getAssetPrice.selector), abi.encode(0)); //If chainlink oracle does not find an answer it will return 0 vm.mockCall(address(depositPool), abi.encodeWithSelector(ILRTDepositPool.getTotalAssetDeposits.selector), abi.encode(9 ether)); vm.expectRevert(); lrtDepositPool.depositAsset(rETHAddress, 3 ether); //alice deposits again and it will revert } }
Manual Review
Use latestRoundData()
function instead.
Oracle
#0 - c4-pre-sort
2023-11-16T00:30:16Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2023-11-16T00:30:30Z
raymondfam marked the issue as duplicate of #34
#2 - c4-pre-sort
2023-11-17T06:07:29Z
raymondfam marked the issue as sufficient quality report
#3 - c4-pre-sort
2023-11-17T06:07:34Z
raymondfam marked the issue as not a duplicate
#4 - c4-pre-sort
2023-11-17T06:07:46Z
raymondfam marked the issue as duplicate of #215
#5 - c4-judge
2023-11-29T19:26:08Z
fatherGoose1 marked the issue as unsatisfactory: Invalid
#6 - c4-judge
2023-12-04T17:45:53Z
fatherGoose1 changed the severity to QA (Quality Assurance)
#7 - c4-judge
2023-12-08T18:51:43Z
fatherGoose1 marked the issue as grade-b