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: 29/185
Findings: 2
Award: $143.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: max10afternoon
Also found by: 0xMilenov, 0xbrett8571, 0xhacksmithh, 0xmystery, Aymen0909, Bauer, Daniel526, PENGUN, Pechenite, Shaheen, adriro, anarcheuz, btk, ck, ge6a, glcanvas, hals, turvy_fuzz
140.2525 USDC - $140.25
The impact of this vulnerability is that users may receive a different amount of rseth than initially anticipated, leading to potential discrepancies and affecting the overall user experience within the protocol.
In the getRsETHAmountToMint
function, the amount of rseth to mint is calculated based on the exchange rates between the deposited asset (LST) and rseth obtained from the oracle. The vulnerability lies in the dependency on external market conditions, specifically the oracle's reported prices.
function getRsETHAmountToMint(address asset, uint256 amount) public view override returns (uint256 rsethAmountToMint) { // setup oracle contract address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); // calculate rseth amount to mint based on asset amount and asset exchange rate rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice(); }
In this code snippet:
getAssetPrice(asset)
retrieves the current price of the deposited asset from the oracle.getRSETHPrice()
retrieves the current price of rseth from the oracle.
Consider a decentralized finance (DeFi) protocol utilizing the LRTDepositPool
contract. Users interact with the protocol by depositing LST (the deposited asset) and receiving an equivalent amount of rseth (a secondary asset) based on exchange rates obtained from an oracle. The exchange rates play a crucial role in determining the minted rseth
amount.LRTDepositPool
contract. At the time of deposit, the exchange rate between LST and rseth is favorable, with 1 LST being equivalent to 2 rseth.LST
and rseth
becomes less favorable. Now, 1 LST is equivalent to only 1.5 rseth.depositAsset
function. The getRsETHAmountToMint
function calculates the rseth amount based on the deposit amount and the exchange rates obtained from the oracle.// Assuming asset = LST, amount = 100 rsethAmountToMint = (100 * lrtOracle.getAssetPrice(LST)) / lrtOracle.getRSETHPrice();
rsethAmountToMint
is now lower than what User A might have expected based on the rate at the time of deposit.// Assuming the new exchange rate is 1.5 (instead of 2) rsethAmountToMint = (100 * 1) / 1.5; // Calculated rsethAmountToMint is now 66.67
Manual
A dynamic pricing mechanism should be implemented that considers the exchange rates at both the time of deposit and the time of minting. This ensures that the calculation is based on consistent and up-to-date values, reducing the impact of market fluctuations during the minting process.
Other
#0 - c4-pre-sort
2023-11-16T04:37:28Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-11-16T04:37:36Z
raymondfam marked the issue as duplicate of #39
#2 - c4-pre-sort
2023-11-17T06:43:10Z
raymondfam marked the issue as duplicate of #148
#3 - c4-judge
2023-11-29T19:10:09Z
fatherGoose1 marked the issue as satisfactory
🌟 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
The potential impact of this vulnerability is the execution failure of the transferAssetToNodeDelegator
function when an invalid index is provided. This could result in the loss of assets, as the function attempts to transfer funds to a Node Delegator using an out-of-bounds index. If the index is not properly validated, it may cause assets to be transferred to an unintended or non-existent destination, leading to a permanent loss of those assets or even an unintended transaction revert.
The transferAssetToNodeDelegator
function is designed to transfer assets to a specific Node Delegator based on the provided index. However, the code does not include a validation check to ensure that the given index is within the valid range of indices in the nodeDelegatorQueue
array. If the index exceeds the length of the array, an attempt to access an invalid index will result in an exception.
function transferAssetToNodeDelegator( uint256 ndcIndex, address asset, uint256 amount ) external nonReentrant onlyLRTManager onlySupportedAsset(asset) { // Vulnerability: Missing index validation address nodeDelegator = nodeDelegatorQueue[ndcIndex]; if (!IERC20(asset).transfer(nodeDelegator, amount)) { revert TokenTransferFailed(); } }
The vulnerability lies in the assumption that the provided index is always valid, which could lead to unintended consequences if the index is out of bounds.
Manual
Add a validation check to ensure that the provided index is within the valid range before attempting to access the nodeDelegatorQueue
array.
function transferAssetToNodeDelegator( uint256 ndcIndex, address asset, uint256 amount ) external nonReentrant onlyLRTManager onlySupportedAsset(asset) { // Mitigation: Validate the index before accessing the array require(ndcIndex < nodeDelegatorQueue.length, "Invalid index"); address nodeDelegator = nodeDelegatorQueue[ndcIndex]; if (!IERC20(asset).transfer(nodeDelegator, amount)) { revert TokenTransferFailed(); } }
Context
#0 - c4-pre-sort
2023-11-16T04:41:09Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2023-11-16T04:41:24Z
raymondfam marked the issue as duplicate of #69
#2 - c4-judge
2023-11-29T20:58:12Z
fatherGoose1 changed the severity to QA (Quality Assurance)
#3 - c4-judge
2023-11-29T21:02:08Z
fatherGoose1 marked the issue as grade-b