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: 176/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
ID | Description | Severity |
---|---|---|
L-01 | Admin can use renounceRole for self | Low |
L-02 | transferAssetToNodeDelegator() function can be used when contract is paused. | Low |
L-03 | burnFrom function burn tokens without an allowance. | Low |
NC-01 | updateAssetStrategy() doesn't used in constructor. | Non-critical |
NC-02 | Lack of check in getAssetCurrentLimit() . | Non-critical |
renounceRole
for self.LRTConfig.sol
and RSETH.sol
contracts inherited from AccessControlUpgradeable.sol
.
Admin can renounce role to self, for example, if there is only one account with DEFAULT_ADMIN_ROLE
role, after admin renounce it, some important functionality can't be used.
Consider to override renounceRole
so the admin can't renounce DEFAULT_ADMIN_ROLE
for self.
transferAssetToNodeDelegator()
function can be used when contract is paused.Manager still can use transferAssetToNodeDelegator()
function when LRTDepositPool.sol
contract is paused due to lack of whenNotPaused
modifier.
e.g. transferBackToLRTDepositPool()
function does the opposite operation and it has whenNotPaused
modifier.
Consider to add whenNotPaused
modifier to transferAssetToNodeDelegator()
function.
function transferAssetToNodeDelegator( uint256 ndcIndex, address asset, uint256 amount ) external nonReentrant ++ whenNotPaused onlyLRTManager onlySupportedAsset(asset) { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; if (!IERC20(asset).transfer(nodeDelegator, amount)) { revert TokenTransferFailed(); } }
burnFrom
function burn tokens without an allowance.burnFrom
function can burn user tokens without an allowance. Despite this function can be called by trusted BURNER_ROLE
this function can be unexpectedly called by mistake.
function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused { _burn(account, amount); }
Consider implement the next changes:
function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused { ++ _spendAllowance(account, msg.sender, amount); _burn(account, amount); }
updateAssetStrategy()
doesn't used in constructor.updateAssetStrategy()
function used in LRTConfig
to set strategy
for supportedAsset
.
When LRTConfig.sol
contract is deployed it sets supported assets and their limits in the constructor, however it doesn't set strategy.
When depositAssetIntoStrategy()
function is used it will revert since default strategy is equal to address(0) if admin forget to set strategy for asset.
IEigenStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy(IStrategy(strategy), token, balance);
Consider to implement the following changes:
updateAssetStrategy()
in the constructor to set strategy for supported assets that are added in the constructor as well.depositAssetIntoStrategy()
function to check that strategy isn't equal to address(0).getAssetCurrentLimit()
.In getAssetCurrentLimit()
there is no check that lrtConfig.depositLimitByAsset(asset) >= getTotalAssetDeposits(asset)
function getAssetCurrentLimit(address asset) public view override returns (uint256) { return lrtConfig.depositLimitByAsset(asset) - getTotalAssetDeposits(asset); }
Due to this depositAsset()
can revert with a reason unknown to the user.
Consider to add the following check:
function getAssetCurrentLimit(address asset) public view override returns (uint256) { ++ if (getTotalAssetDeposits(asset) > lrtConfig.depositLimitByAsset(asset)) revert Error(); return lrtConfig.depositLimitByAsset(asset) - getTotalAssetDeposits(asset); }
#0 - c4-pre-sort
2023-11-17T23:58:29Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-12-01T16:43:37Z
fatherGoose1 marked the issue as grade-b