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: 97/185
Findings: 2
Award: $7.42
š Selected for report: 0
š Solo Findings: 0
š Selected for report: Krace
Also found by: 0xDING99YA, 0xrugpull_detector, Aamir, AlexCzm, Aymen0909, Banditx0x, Bauer, CatsSecurity, GREY-HAWK-REACH, Madalad, Phantasmagoria, QiuhaoLi, Ruhum, SBSecurity, SandNallani, SpicyMeatball, T1MOH, TheSchnilch, adam-idarrha, adriro, almurhasan, ast3ros, ayden, bronze_pickaxe, btk, chaduke, ck, crack-the-kelp, critical-or-high, deth, gumgumzum, jasonxiale, joaovwfreire, ke1caM, m_Rassska, mahdirostami, mahyar, max10afternoon, osmanozdemir1, peanuts, pep7siup, peter, ptsanev, qpzm, rouhsamad, rvierdiiev, spark, twcctop, ubl4nk, wisdomn_, zach, zhaojie
4.6614 USDC - $4.66
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L119-L144 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L151-L157 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L95-L110 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTOracle.sol#L49-L79 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L47-L51 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L71-L89
1 ether
(as there are no rsETH tokens minted yet) but LRTOracle@getAssetPrice still returning the current price of the deposited LST.O(nAssets x nDelegators) = O(n²)
increasing gas cost any time a new asset or delegator is added.sequenceDiagram participant User participant LRTDepositPool participant LRTOracle participant LST ERC20 participant RSETH ERC20 participant NodeDelegator participant EigenLayerStrategy participant ChainlinkPriceOracle participant Aggregator User->>LRTDepositPool: depositAsset(asset, amount) activate User activate LRTDepositPool LRTDepositPool->>LST ERC20: transferFrom(msg.sender, LRTDepositPool, amount) activate LST ERC20 deactivate LST ERC20 LST ERC20-->>LRTDepositPool: LRTDepositPool->>LRTDepositPool: _mintRsETH(asset, amount) LRTDepositPool->>LRTDepositPool: getRsETHAmountToMint(asset, amount) LRTDepositPool->>+LRTOracle: getAssetPrice(asset) LRTOracle->>+ChainlinkPriceOracle: getAssetPrice(asset) ChainlinkPriceOracle->>+Aggregator: latestAnswer() Aggregator-->>-ChainlinkPriceOracle: assetPrice ChainlinkPriceOracle-->>-LRTOracle: assetPrice LRTOracle-->>-LRTDepositPool: assetPrice LRTDepositPool->>+LRTOracle: getRSETHPrice() LRTOracle->>+RSETH ERC20: totalSupply() RSETH ERC20-->>-LRTOracle: rsETHTotalSupply alt rsETHTotalSupply = 0 LRTOracle-->>LRTDepositPool: 1 ether else loop assets LRTOracle->>+ChainlinkPriceOracle: getAssetPrice(asset) ChainlinkPriceOracle->>+Aggregator: latestAnswer() Aggregator-->>-ChainlinkPriceOracle: assetPrice ChainlinkPriceOracle-->>-LRTOracle: assetPrice LRTOracle->>LRTDepositPool: getTotalAssetDeposits(asset) LRTDepositPool->>LRTDepositPool: getAssetDistributionData(asset) LRTDepositPool->>+LST ERC20: balanceOf(LRTDepositPool) LST ERC20-->>-LRTDepositPool: assetLyingInDepositPool loop nodeDelegators LRTDepositPool->>+LST ERC20: balanceOf(delegator) LST ERC20-->>-LRTDepositPool: assetLyingInNDCs LRTDepositPool->>+NodeDelegator: getAssetBalance(asset) NodeDelegator->>+EigenLayerStrategy: userUnderlyingView(delegator) EigenLayerStrategy-->>-NodeDelegator: assetStakedInEigenLayer NodeDelegator-->>-LRTDepositPool: assetStakedInEigenLayer end LRTDepositPool-->>LRTOracle: assetLyingInDepositPool + assetLyingInNDCs + assetStakedInEigenLayer LRTOracle->>LRTOracle: totalETHInPool += assetPrice * (assetLyingInDepositPool + assetLyingInNDCs + assetStakedInEigenLayer) end LRTOracle-->>LRTDepositPool: rsETHPrice = totalETHInPool / rsETHTotalSupply end deactivate LRTOracle LRTDepositPool-->>LRTDepositPool: rsETHAmountToMint = amount * assetPrice / rsETHPrice LRTDepositPool->>RSETH ERC20: mint(msg.sender, rsETHAmountToMint) activate RSETH ERC20 deactivate RSETH ERC20 RSETH ERC20-->>LRTDepositPool: LRTDepositPool-->>User: deactivate LRTDepositPool deactivate User
Assuming these prices : 1.09 rETH / ETH
, 0.99 stETH / ETH
, 1.05 cbETH / ETH
Bob
initiates the first deposit to the pool with 1 ether
amount of rETH
rsETH
tokens minted yet, the rsETH price returned from LRTOracle@getRSETHPrice
is 1 ether
Bob
gets backs 1 ether * 1.09 ether / 1 ether = 1.09 ether
of rsETH
Bob
initiates a second deposit with 1 ether
amount of rETH
rsETH
tokens minted, the rsETH price returned from LRTOracle@getRSETHPrice
will be equal to (rsETHPriceInETH * (firstDepositAmount + secondDepositAmount)) / (rsETHTotalSupply) = (1.09 ether * (1 ether + 1 ether)) / 1.09 ether = 2 ether
Bob
gets backs 1 ether * 1.09 ether / 2 ether = 0.545 ether
of rsETH
Attacker
initiates N
deposits with 1 wei
amount of stETH
and gets back (1 wei * 0.99 ether) / 1 ether = 0
rsETHAttacker
follows that with a deposit of 2 wei
amount of stETH
and gets back (2 wei * 0.99 ether) / 1 ether = 1
rsETHBob
deposits 1 ether
amount of cbETH
(((N wei + 2 wei) * 0.99 ether) + (1 ether * 1.05 ether)) / 1 wei
if live balances are used((N wei + 2 wei) * 0.99 ether) / 1 wei
if all deposits are tracked separatelyBob
will get back a lot less rsETH tokens than expected
(1 ether * 1.05 ether) / (((N wei + 2 wei) * 0.99 ether) + (1 ether * 1.05 ether))
if live balances are still used(1 ether * 1.05 ether) / ((N wei + 2 wei) * 0.99 ether)
if all deposits are tracked separatelyYou'll need to add a .env
file with a MAINNET_RPC_URL
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import { Test, console2 } from "forge-std/Test.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ChainlinkPriceOracle } from "src/oracles/ChainlinkPriceOracle.sol"; import { LRTConfig } from "src/LRTConfig.sol"; import { LRTConstants } from "src/utils/LRTConstants.sol"; import { LRTDepositPool } from "src/LRTDepositPool.sol"; import { LRTOracle } from "src/LRTOracle.sol"; import { NodeDelegator } from "src/NodeDelegator.sol"; import { RSETH } from "src/RSETH.sol"; import { ILRTDepositPool } from "src/interfaces/ILRTDepositPool.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; contract MockAggregator { uint256 public latestAnswer; constructor(uint256 initialAnswer) { latestAnswer = initialAnswer; } function updateAnswer(uint256 newAnswer) external { latestAnswer = newAnswer; } } contract LRTDepositPoolForkTest is Test { address constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; address constant CBETH = 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704; address constant RETH = 0xae78736Cd615f374D3085123A210448E74Fc6393; address constant STETH_ORACLE = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812; address constant CBETH_ORACLE = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b; address constant RETH_ORACLE = 0x536218f9E9Eb48863970252233c8F271f554C2d0; address constant STETH_EIGEN_STRATEGY = 0x93c4b944D05dfe6df7645A86cd2206016c51564D; address constant CBETH_EIGEN_STRATEGY = 0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc; address constant RETH_EIGEN_STRATEGY = 0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2; address constant EIGEN_STRATEGY_MANAGER = 0x858646372CC42E1A627fcE94aa7A7033e7CF075A; ProxyAdmin proxyAdmin; address admin; address bob; address lrtConfigContractAddress; RSETH rsETHContract; LRTConfig lrtConfigContract; LRTDepositPool lrtDepositPoolContract; LRTOracle lrtOracleContract; ChainlinkPriceOracle chainlinkPriceOracleContract; function setUp() public { uint256 forkId = vm.createFork(vm.envString("MAINNET_RPC_URL")); vm.selectFork(forkId); admin = makeAddr('admin'); bob = makeAddr('bob'); vm.prank(0xfFEFA70B6DEaAb975ef15A6474ce9C4214d82B02); IERC20(STETH).transfer(bob, 100 ether); deal(CBETH, bob, 100 ether); deal(RETH, bob, 100 ether); vm.startPrank(admin); proxyAdmin = new ProxyAdmin(); LRTConfig implementation = new LRTConfig(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), address(proxyAdmin), "" ); lrtConfigContractAddress = address(proxy); lrtConfigContract = LRTConfig(lrtConfigContractAddress); _setUpRSETH(); lrtConfigContract.initialize(admin, STETH, RETH, CBETH, address(rsETHContract)); lrtConfigContract.grantRole(LRTConstants.MANAGER, admin); lrtConfigContract.setContract(LRTConstants.EIGEN_STRATEGY_MANAGER, EIGEN_STRATEGY_MANAGER); lrtConfigContract.updateAssetStrategy(STETH, STETH_EIGEN_STRATEGY); lrtConfigContract.updateAssetStrategy(CBETH, CBETH_EIGEN_STRATEGY); lrtConfigContract.updateAssetStrategy(RETH, RETH_EIGEN_STRATEGY); _setUpLRTDepositPool(); _setUpChainlinkPriceOracle(); _setUpNodeDelegators(10); _setUpLRTOracle(); vm.stopPrank(); } function _setUpRSETH() internal { RSETH implementation = new RSETH(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), address(proxyAdmin), "" ); rsETHContract = RSETH(address(proxy)); rsETHContract.initialize(admin, lrtConfigContractAddress); } function _setUpLRTDepositPool() internal { LRTDepositPool implementation = new LRTDepositPool(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), address(proxyAdmin), "" ); lrtDepositPoolContract = LRTDepositPool(address(proxy)); lrtDepositPoolContract.initialize(lrtConfigContractAddress); lrtConfigContract.setContract(LRTConstants.LRT_DEPOSIT_POOL, address(proxy)); rsETHContract.grantRole(keccak256("MINTER_ROLE"), address(lrtDepositPoolContract)); } function _setUpLRTOracle() internal { LRTOracle implementation = new LRTOracle(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), address(proxyAdmin), "" ); lrtOracleContract = LRTOracle(address(proxy)); lrtOracleContract.initialize(lrtConfigContractAddress); lrtOracleContract.updatePriceOracleFor(STETH, address(chainlinkPriceOracleContract)); lrtOracleContract.updatePriceOracleFor(CBETH, address(chainlinkPriceOracleContract)); lrtOracleContract.updatePriceOracleFor(RETH, address(chainlinkPriceOracleContract)); lrtConfigContract.setContract(LRTConstants.LRT_ORACLE, address(proxy)); } function _setUpChainlinkPriceOracle() internal { ChainlinkPriceOracle implementation = new ChainlinkPriceOracle(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), address(proxyAdmin), "" ); chainlinkPriceOracleContract = ChainlinkPriceOracle(address(proxy)); chainlinkPriceOracleContract.initialize(lrtConfigContractAddress); chainlinkPriceOracleContract.updatePriceFeedFor(STETH, STETH_ORACLE); chainlinkPriceOracleContract.updatePriceFeedFor(CBETH, CBETH_ORACLE); chainlinkPriceOracleContract.updatePriceFeedFor(RETH, RETH_ORACLE); } function _setUpNodeDelegators(uint256 n) internal { address[] memory delegators = new address[](n); for (uint256 i = 0; i < n; i++) { NodeDelegator implementation = new NodeDelegator(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), address(proxyAdmin), "" ); delegators[i] = address(proxy); NodeDelegator delegator = NodeDelegator(delegators[i]); delegator.initialize(lrtConfigContractAddress); } lrtDepositPoolContract.addNodeDelegatorContractToQueue(delegators); } function testDeposit1Wei() public { vm.startPrank(bob); IERC20(RETH).approve(address(lrtDepositPoolContract), 1); IERC20(CBETH).approve(address(lrtDepositPoolContract), 1 ether); lrtDepositPoolContract.depositAsset(RETH, 1 wei); lrtDepositPoolContract.depositAsset(CBETH, 1 ether); vm.stopPrank(); assertApproxEqAbs(rsETHContract.balanceOf(bob), 1 ether, 0.05 ether); } function testDeposit1Ether() public { vm.startPrank(bob); IERC20(RETH).approve(address(lrtDepositPoolContract), 1 ether); IERC20(CBETH).approve(address(lrtDepositPoolContract), 1 ether); lrtDepositPoolContract.depositAsset(RETH, 1 ether); lrtDepositPoolContract.depositAsset(CBETH, 1 ether); vm.stopPrank(); assertApproxEqAbs(rsETHContract.balanceOf(bob), 2 ether, 0.05 ether); } function testDepositAfterDirectTransfer() public { vm.startPrank(bob); IERC20(RETH).approve(address(lrtDepositPoolContract), 1); IERC20(CBETH).approve(address(lrtDepositPoolContract), 1 ether); IERC20(RETH).transfer(address(lrtDepositPoolContract), 1 ether); lrtDepositPoolContract.depositAsset(RETH, 1 wei); lrtDepositPoolContract.depositAsset(CBETH, 1 ether); vm.stopPrank(); assertApproxEqAbs(rsETHContract.balanceOf(bob), 1 ether, 0.05 ether); } function testDepositPrecisionLoss() public { vm.startPrank(bob); IERC20(STETH).approve(address(lrtDepositPoolContract), 1 ether); IERC20(CBETH).approve(address(lrtDepositPoolContract), 1 ether); lrtDepositPoolContract.depositAsset(STETH, 1 wei); lrtDepositPoolContract.depositAsset(STETH, 1 wei); lrtDepositPoolContract.depositAsset(STETH, 1 wei); lrtDepositPoolContract.depositAsset(STETH, 1 wei); lrtDepositPoolContract.depositAsset(STETH, 2 wei); lrtDepositPoolContract.depositAsset(CBETH, 1 ether); vm.stopPrank(); assertApproxEqAbs(rsETHContract.balanceOf(bob), 1 ether, 0.05 ether); } }
[ā °] Compiling... [ā ] Compiling 4 files with 0.8.21 [ā ] Solc 0.8.21 finished in 26.54s Compiler run successful! Running 4 tests for test/LRTDepositPoolForkTest.t.sol:LRTDepositPoolForkTest [FAIL. Reason: Assertion failed.] testDeposit1Ether() (gas: 1440461) Logs: Error: a ~= b not satisfied [uint] Left: 1626350399672417519 Right: 2000000000000000000 Max Delta: 50000000000000000 Delta: 373649600327582481 [FAIL. Reason: Assertion failed.] testDeposit1Wei() (gas: 1440429) Logs: Error: a ~= b not satisfied [uint] Left: 1 Right: 1000000000000000000 Max Delta: 50000000000000000 Delta: 999999999999999999 [FAIL. Reason: Assertion failed.] testDepositAfterDirectTransfer() (gas: 1445580) Logs: Error: a ~= b not satisfied [uint] Left: 1 Right: 1000000000000000000 Max Delta: 50000000000000000 Delta: 999999999999999999 [FAIL. Reason: Assertion failed.] testDepositPrecisionLoss() (gas: 2650042) Logs: Error: a ~= b not satisfied [uint] Left: 1 Right: 1000000000000000000 Max Delta: 50000000000000000 Delta: 999999999999999999 Test result: FAILED. 0 passed; 4 failed; 0 skipped; finished in 23.48s Ran 1 test suites: 0 tests passed, 4 failed, 0 skipped (4 total tests) Failing tests: Encountered 4 failing tests in test/LRTDepositPoolForkTest.t.sol:LRTDepositPoolForkTest [FAIL. Reason: Assertion failed.] testDeposit1Ether() (gas: 1440461) [FAIL. Reason: Assertion failed.] testDeposit1Wei() (gas: 1440429) [FAIL. Reason: Assertion failed.] testDepositAfterDirectTransfer() (gas: 1445580) [FAIL. Reason: Assertion failed.] testDepositPrecisionLoss() (gas: 2650042) Encountered a total of 4 failing tests, 0 tests succeeded
Manual Review
Other
#0 - c4-pre-sort
2023-11-16T04:35:50Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-11-16T04:35:58Z
raymondfam marked the issue as duplicate of #62
#2 - c4-judge
2023-11-29T21:21:38Z
fatherGoose1 marked the issue as satisfactory
#3 - c4-judge
2023-12-01T19:00:05Z
fatherGoose1 changed the severity to 2 (Med Risk)
#4 - imsrybr0
2023-12-01T22:18:12Z
Hi @fatherGoose1,
This was marked as a duplicate of #62 however it includes both #62 and #42 which essentially have the same root cause (.i.e : the usage of live balances in the rsETH price calculation).
testDeposit1Ether
test.testDeposit1Wei
and testDepositAfterDirectTransfer
tests.Additionally, this also includes a Precision Loss issue, the effects of which are partially hidden by the current implementation but may carry on after the issues above are fixed.
As described in the Second Scenario
and testDepositPrecisionLoss
, this would allow an attacker to leverage the fact that an LST token price is lower than 1 ether
(.e.g STETH) to initiate many 1 wei
deposits that don't lead to any rsETH
tokens being minted, then follow that with a 2 wei
deposit to mint 1 wei
of rsETH
token driving the price down significantly for subsequent depositors.
Can you please check this again ?
Thank you
#5 - c4-judge
2023-12-04T15:31:41Z
fatherGoose1 changed the severity to 3 (High Risk)
#6 - fatherGoose1
2023-12-04T16:54:39Z
As described in the Second Scenario and testDepositPrecisionLoss, this would allow an attacker to leverage the fact that an LST token price is lower than 1 ether (.e.g STETH) to initiate many 1 wei deposits that don't lead to any rsETH tokens being minted, then follow that with a 2 wei deposit to mint 1 wei of rsETH token driving the price down significantly for subsequent depositors.
I struggle to see how this would drive the price down significantly. Each 1 wei deposit will cost upwards of $15 on ETH mainnet in gas fees. It seems infeasible to perform enough 1 wei deposits to significantly alter the exchange rate.
This will remain a duplicate to #62 as the report spends most of it's length explaining the same root calculation issue.
#7 - imsrybr0
2023-12-04T17:48:01Z
Not sure if I can still answer on this as the judgement is already decided. Not trying to challenge it, just providing more context regarding the precision loss issue as I failed to convey the idea in the original issue and QA but think it might be useful for the sponsor to know while fixing the issues.
Please let me know if I should delete this comment.
I struggle to see how this would drive the price down significantly. Each 1 wei deposit will cost upwards of $15 on ETH mainnet in gas fees. It seems infeasible to perform enough 1 wei deposits to significantly alter the exchange rate.
LRTOracle@getRSETHPrice
will return 1 etherAssuming live balances are not used anymore and deposits are tracked separately :
LRTOracle@getRSETHPrice
will still return 1 ether for the next depositLRTOracle@getRSETHPrice
will return 6 wei * 0.99 ether / 1 wei = 5.94 ether for the next depositLRTDepositPool@getRsETHAmountToMint
will return 1 ether * 1.05 ether / 5.94 ether = 0.176767676767676767 etherSo Bob gets ~0.18 ether of rsETH for depositing 1 ether of CBETH.
Thank you
#8 - fatherGoose1
2023-12-05T17:44:56Z
This is tricky because, as you claim in previous comment, this submission overlaps with both #42 and #62. What you describe in the most recent comment is similar to a donation attack via precision loss (dupe #42). Reviewing your POC, it seems more closely tied to #42 than #62, therefore I will alter the duplication.
#9 - c4-judge
2023-12-05T17:45:03Z
fatherGoose1 marked the issue as not a duplicate
#10 - c4-judge
2023-12-05T17:45:13Z
fatherGoose1 marked the issue as duplicate of #42
š 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
In NodeDelegator@depositAssetIntoStrategy, when the deposited LST balance is close to the remaining available deposits (maxTotalDeposits - depositedSoFar
) for the corresponding EigenLayer Strategy, the deposit will fail if it is front ran by other regular deposits or a malicious user sending enough LST tokens directly to the NodeDelegator to tip it over the limit.
This would require the admin to transfer enough LSTs back from the NodeDelegator
to the LRTDepositPool
to go back below the limit after each failure before reinitiating another.
This is mainly based on the assumption that revenue sharing will be based on the rsETH amounts held by each user and the fact that :
This means that any rewards claimed by NodeDelegators might be distributed across all rsETH holders regardless of whether their deposited LST tokens were forwarded to the EigenLayer Strategies or not.
For reference :
Pair | Deviation | Heartbeat | Decimals |
---|---|---|---|
RETH / ETH | 2% | 86400s | 18 |
CBETH / ETH | 1% | 86400s | 18 |
STETH / ETH | 0.5% | 86400s | 18 |
latestRoundData
with sanity checks (.e.g for stale price,
)#0 - c4-pre-sort
2023-11-18T00:26:36Z
raymondfam marked the issue as insufficient quality report
#1 - c4-judge
2023-12-01T16:36:53Z
fatherGoose1 marked the issue as grade-c
#2 - imsrybr0
2023-12-03T14:54:46Z
HI @fatherGoose1,
Can you please check this again in the lights of :
Thank you
#3 - fatherGoose1
2023-12-04T17:33:06Z
This report is on the border between C and B. Given your findings' overlap with a couple of issues downgraded to QA, I will award it a B.
Please format your QA reports in a more readable way moving forward.
#4 - c4-judge
2023-12-04T17:33:12Z
fatherGoose1 marked the issue as grade-b