Kelp DAO | rsETH - Phantasmagoria's results

A collective DAO designed to unlock liquidity, DeFi and higher rewards for restaked assets through liquid restaking.

General Information

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

Kelp DAO

Findings Distribution

Researcher Performance

Rank: 108/185

Findings: 2

Award: $7.42

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTOracle.sol#L52-L76 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L109 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L141

Vulnerability details

Impact

In deposit() function _mintRsETH() uses following formula to calculate how much rseth should be minted

rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice();

The problem is that an attacker can manipulate price of rseth and other users when depositng may get 0 rseth.

Proof of Concept

By minting a small amount of rseth and then transferring a large amount of another asset, the attacker can significantly distort the calculated rseth price. Subsequently, when other users attempt to deposit their assets, they won't receive the correct amount of rseth due to the inflated price.

getTotalAssetDeposits() uses balanceOf() to fetch balances of the contracts

function getRSETHPrice() external view returns (uint256 rsETHPrice) {
        address rsETHTokenAddress = lrtConfig.rsETH();
        uint256 rsEthSupply = IRSETH(rsETHTokenAddress).totalSupply();

        if (rsEthSupply == 0) {
            return 1 ether;
        }

        uint256 totalETHInPool;
        address lrtDepositPoolAddr = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL);

        address[] memory supportedAssets = lrtConfig.getSupportedAssetList();
        uint256 supportedAssetCount = supportedAssets.length;

        for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
            address asset = supportedAssets[asset_idx];
            uint256 assetER = getAssetPrice(asset);

            uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset);
            totalETHInPool += totalAssetAmt * assetER;

            unchecked {
                ++asset_idx;
            }
        }

        return totalETHInPool / rsEthSupply;
    }

Tools Used

Manual Review

Consider not using balanceOf for price calculation

Assessed type

Oracle

#0 - c4-pre-sort

2023-11-16T22:17:26Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-11-16T22:17:35Z

raymondfam marked the issue as duplicate of #42

#2 - c4-judge

2023-12-01T17:06:28Z

fatherGoose1 marked the issue as satisfactory

Awards

2.7592 USDC - $2.76

Labels

bug
downgraded by judge
grade-b
insufficient quality report
QA (Quality Assurance)
duplicate-69
Q-58

External Links

Lines of code

https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L183-L197

Vulnerability details

Impact

transferAssetToNodeDelegator() function transfers asset lying in this DepositPool to node delegator contract. To transfer funds manager needs to specify ndcIndex. The problem is that transferAssetToNodeDelegator() doesn't check if delegator with specified index exists. If the manager provides an invalid index that doesn't correspond to an existing node delegator, the funds will be transferred to the address(0), essentially burning the assets.

Proof of Concept

function transferAssetToNodeDelegator(
        uint256 ndcIndex,
        address asset,
        uint256 amount
    )
        external
        nonReentrant
        onlyLRTManager
        onlySupportedAsset(asset)
    {
        address nodeDelegator = nodeDelegatorQueue[ndcIndex];
        if (!IERC20(asset).transfer(nodeDelegator, amount)) {
            revert TokenTransferFailed();
        }
    }

Tools Used

Manual Review

Add delegator existence check

Assessed type

Invalid Validation

#0 - c4-pre-sort

2023-11-16T07:38:43Z

raymondfam marked the issue as insufficient quality report

#1 - c4-pre-sort

2023-11-16T07:38:50Z

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:40Z

fatherGoose1 marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter