Created
November 13, 2023 20:00
-
-
Save Alireza-Razavi/d1b622b1bb9df8a38710f65c69808a09 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"comment": "Audit report for **2023-11-kelp** generated by *ubl4nk_bot*.", | |
"footnote": "Thanks for reading this report :)", | |
"findings": [ | |
{ | |
"description": "Some tokens, such as [USDT](https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#code#L199), have a different implementation for the approve function: when the address is cast to a compliant `IERC20` interface and the approve function is used, it will always revert due to the interface mismatch.", | |
"severity": "Medium", | |
"title": "`approve` will always revert as the `IERC20` interface mismatch", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n45: IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max);\n```", | |
"loc": [ | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L45)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some `IERC20` tokens (e.g. BNB, OMG, USDT) do not implement the standard properly, but they are still accepted by most code that accepts `ERC20` tokens.\n\nFor example, USDT `transfer` functions on L1 do not return booleans: when casted to `IERC20`, their function signatures do not match, and therefore the calls made will revert.", | |
"severity": "Medium", | |
"title": "Non-compliant `IERC20` tokens may revert with `transfer`", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n194: if (!IERC20(asset).transfer(nodeDelegator, amount)) {\n```", | |
"loc": [ | |
"[194](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L194)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n86: if (!IERC20(asset).transfer(lrtDepositPool, amount)) {\n```", | |
"loc": [ | |
"[86](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L86)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Not all IERC20 implementations `revert()` when there's a failure in `approve()`. The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything", | |
"severity": "Medium", | |
"title": "Return values of `approve()` not checked", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n45: IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max);\n```", | |
"loc": [ | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L45)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Not all `ERC20` implementations are totally compliant, and some (e.g `LEND`) may fail while transfering a zero amount.", | |
"severity": "Medium", | |
"title": "Some `ERC20` can revert on a zero value transfer", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n194: if (!IERC20(asset).transfer(nodeDelegator, amount)) {\n```", | |
"loc": [ | |
"[194](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L194)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n86: if (!IERC20(asset).transfer(lrtDepositPool, amount)) {\n```", | |
"loc": [ | |
"[86](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L86)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some tokens take a transfer fee (e.g. `STA`, `PAXG`), some do not currently charge a fee but may do so in the future (e.g. `USDT`, `USDC`).\n\nShould a fee-on-transfer token be added as an asset and deposited, it could be abused, as the accounting is wrong. In the current implementation the following function calls do not work well with fee-on-transfer tokens as the amount variable is the pre-fee amount, including the fee, whereas the final balance do not include the fee anymore.", | |
"severity": "Medium", | |
"title": "Some functions do not work correctly with fee-on-transfer tokens", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n136: if (!IERC20(asset).transferFrom(msg.sender, address(this), depositAmount)) {\n```", | |
"loc": [ | |
"[136](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L136)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.", | |
"severity": "Medium", | |
"title": "Centralization Risk for trusted owners", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n73: function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {\n\n98: external\n\n113: external\n\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L73)", | |
"[98](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L98)", | |
"[113](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L113)", | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n162: function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin {\n\n202: function updateMaxNodeDelegatorCount(uint256 maxNodeDelegatorCount_) external onlyLRTAdmin {\n\n208: function pause() external onlyLRTManager {\n\n213: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L162)", | |
"[202](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L202)", | |
"[208](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L208)", | |
"[213](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L213)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n92: external\n\n102: function pause() external onlyLRTManager {\n\n107: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[92](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L92)", | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L102)", | |
"[107](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L107)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n127: function pause() external onlyLRTManager {\n\n132: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L127)", | |
"[132](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L132)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n47: function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {\n\n54: function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {\n\n60: function pause() external onlyLRTManager {\n\n66: function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n73: function updateLRTConfig(address _lrtConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L47)", | |
"[54](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L54)", | |
"[60](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L60)", | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L66)", | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L73)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n37: function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {\n\n45: function updatePriceFeedFor(address asset, address priceFeed) external onlyLRTManager onlySupportedAsset(asset) {\n```", | |
"loc": [ | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L37)", | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L45)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n9: import { IAccessControl } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol\";\n\n21: if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) {\n\n29: if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {\n\n47: function updateLRTConfig(address lrtConfigAddr) external virtual onlyLRTAdmin {\n```", | |
"loc": [ | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L9)", | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L21)", | |
"[29](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L29)", | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L47)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some tokens do not return a bool (e.g. USDT, OMG) on transfer. As there are some conditions that rely on this `bool` value, these tokens may cause issues, as the return value of the following conditions will always be `false`.", | |
"severity": "Medium", | |
"title": "`transfer`/`transferFrom` may never return `true` for some tokens", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n136: if (!IERC20(asset).transferFrom(msg.sender, address(this), depositAmount)) {\n\n194: if (!IERC20(asset).transfer(nodeDelegator, amount)) {\n```", | |
"loc": [ | |
"[136](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L136)", | |
"[194](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L194)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n86: if (!IERC20(asset).transfer(lrtDepositPool, amount)) {\n```", | |
"loc": [ | |
"[86](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L86)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Adding a zero address check for each address type parameter can prevent errors.", | |
"severity": "Low", | |
"title": "Missing zero address check in functions with address parameters", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit missing zero check for `asset`\n73: function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {\n\n/// @audit missing zero check for `assetAddress`\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n/// @audit missing zero check for `contractAddress`\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L73)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit missing zero check for `_asset`\n151: function _mintRsETH(address _asset, uint256 _amount) private returns (uint256 rsethAmountToMint) {\n```", | |
"loc": [ | |
"[151](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L151)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n/// @audit missing zero check for `to`\n47: function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {\n\n/// @audit missing zero check for `account`\n54: function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L47)", | |
"[54](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L54)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Calling `approve()` without first calling `approve(0)` if the current approval is non-zero will revert with some tokens, such as Tether (USDT). While Tether is known to do this, it applies to other tokens as well, which are trying to protect against [this attack vector](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit). `safeApprove()` itself also implements this protection. Always reset the approval to zero before changing it to a new value (`SafeERC20.forceApprove()` does this for you), or use `safeIncreaseAllowance()`/`safeDecreaseAllowance()`", | |
"severity": "Low", | |
"title": "`approve()`/`safeApprove()` may revert if the current approval is not zero", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n45: IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max);\n```", | |
"loc": [ | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L45)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "There is no limit specified on the amount of gas used, so the recipient can use up all of the remaining gas (`gasleft()`), causing it to revert. Therefore, when calling an external contract, it is necessary to specify a limited amount of gas to forward.", | |
"severity": "Low", | |
"title": "Array is `push()`ed but not `pop()`ed", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n86: supportedAssetList.push(asset);\n```", | |
"loc": [ | |
"[86](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L86)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n170: nodeDelegatorQueue.push(nodeDelegatorContracts[i]);\n```", | |
"loc": [ | |
"[170](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L170)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some functions use a deprecated version of Chainlink functions, consider following the [documentation](https://docs.chain.link/data-feeds/api-reference) to use the supported alternatives.", | |
"severity": "Low", | |
"title": "Avoid the use of deprecated Chainlink functions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n38: return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();\n```", | |
"loc": [ | |
"[38](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L38)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "Low", | |
"title": "Check division by zero is prevented", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n109: rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice();\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L109)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n78: return totalETHInPool / rsEthSupply;\n```", | |
"loc": [ | |
"[78](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L78)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "A copy-paste error or a typo may end up bricking protocol functionality, or sending tokens to an address with no known private key. Consider implementing a two-step procedure for updating protocol addresses, where the recipient is set as pending, and must \"accept\" the assignment by making an affirmative call. A straight forward way of doing this would be to have the target contracts implement [EIP-165](https://eips.ethereum.org/EIPS/eip-165), and to have the \"set\" functions ensure that the recipient is of the right interface type.", | |
"severity": "Low", | |
"title": "Consider implementing two-step procedure for updating protocol addresses", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n73: function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {\n\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L73)", | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Calling external functions within loops can easily result in insufficient gas. This greatly increases the likelihood of transaction failures, DOS attacks, and other unexpected actions. It is recommended to limit the number of loops within loops that call external functions, and to limit the gas line for each external call.", | |
"severity": "Low", | |
"title": "External function calls within loops", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `.balanceOf(...)`\n83: assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]);\n\n/// @audit `.getAssetBalance(...)`\n84: assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset);\n```", | |
"loc": [ | |
"[83](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L83)", | |
"[84](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L84)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `.getTotalAssetDeposits(...)`\n70: uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset);\n```", | |
"loc": [ | |
"[70](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L70)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n/// @audit `.underlyingToken(...)`\n110: assets[i] = address(IStrategy(strategies[i]).underlyingToken());\n\n/// @audit `.userUnderlyingView(...)`\n111: assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));\n```", | |
"loc": [ | |
"[110](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L110)", | |
"[111](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L111)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Governance functions (such as upgrading contracts, setting critical parameters) should be controlled using time locks to introduce a delay between a proposal and its execution. This gives users time to exit before a potentially dangerous or malicious operation is applied.", | |
"severity": "Low", | |
"title": "Governance functions should be controlled by time locks", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Not all `IERC20` implementations are totally compliant, and some (e.g `UNI`, `COMP`) may fail if the valued passed to `approve` is larger than `uint96`. If the approval amount is `type(uint256).max`, which may cause issues with systems that expect the value passed to approve to be reflected in the allowances mapping.", | |
"severity": "Low", | |
"title": "Large approvals may not work with some `ERC20` tokens", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n45: IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max);\n```", | |
"loc": [ | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L45)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Division by large numbers may result in the result being zero, due to solidity not supporting fractions. Consider requiring a minimum amount for the numerator to ensure that it is always larger than the denominator.", | |
"severity": "Low", | |
"title": "Loss of precision in divisions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n109: rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice();\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L109)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n78: return totalETHInPool / rsEthSupply;\n```", | |
"loc": [ | |
"[78](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L78)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "There are some missing checks in these functions, and this could lead to unexpected scenarios. Consider always adding a sanity check for state variables.", | |
"severity": "Low", | |
"title": "Missing checks for state variable assignments", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit `rsETH_`\n67: rsETH = rsETH_;\n\n/// @audit `depositLimit`\n87: depositLimitByAsset[asset] = depositLimit;\n\n/// @audit `depositLimit`\n102: depositLimitByAsset[asset] = depositLimit;\n\n/// @audit `strategy`\n121: assetStrategy[asset] = strategy;\n\n/// @audit `rsETH_`\n146: rsETH = rsETH_;\n\n/// @audit `val`\n161: tokenMap[key] = val;\n\n/// @audit `val`\n177: contractMap[key] = val;\n```", | |
"loc": [ | |
"[67](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L67)", | |
"[87](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L87)", | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L102)", | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L121)", | |
"[146](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L146)", | |
"[161](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L161)", | |
"[177](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L177)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `maxNodeDelegatorCount_`\n203: maxNodeDelegatorCount = maxNodeDelegatorCount_;\n```", | |
"loc": [ | |
"[203](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L203)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `priceOracle`\n97: assetPriceOracle[asset] = priceOracle;\n```", | |
"loc": [ | |
"[97](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L97)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n/// @audit `priceFeed`\n47: assetPriceFeed[asset] = priceFeed;\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L47)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "There are some missing limits in these functions, and this could lead to unexpected scenarios. Consider adding a min/max limit for the following values, when appropriate.", | |
"severity": "Low", | |
"title": "Missing limits when setting min/max amounts", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit `depositLimit`\n80: function _addNewSupportedAsset(address asset, uint256 depositLimit) private {\n\n/// @audit `depositLimit`\n94: function updateAssetDepositLimit(\n address asset,\n uint256 depositLimit\n )\n external\n onlyRole(LRTConstants.MANAGER)\n onlySupportedAsset(asset)\n {\n```", | |
"loc": [ | |
"[80](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L80)", | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L94)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `maxNodeDelegatorCount_`\n202: function updateMaxNodeDelegatorCount(uint256 maxNodeDelegatorCount_) external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[202](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L202)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Check for zero-address to avoid the risk of setting `address(0)` for state variables after an update.", | |
"severity": "Low", | |
"title": "Consider some checks for `address(0)` when setting address state variables", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit `rsETH_`\n67: rsETH = rsETH_;\n\n/// @audit `rsETH_`\n146: rsETH = rsETH_;\n```", | |
"loc": [ | |
"[67](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L67)", | |
"[146](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L146)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Each upgradable contract should include a state variable (usually named `__gap`) to provide reserved space in storage. This allows the team to freely add new state variables in the future upgrades without compromising the storage compatibility with existing deployments.", | |
"severity": "Low", | |
"title": "Check storage gap for upgradable contracts", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n12: contract LRTConfig is ILRTConfig, AccessControlUpgradeable {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L12)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n19: contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n18: contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L18)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n14: contract RSETH is\n Initializable,\n LRTConfigRoleChecker,\n ERC20Upgradeable,\n```", | |
"loc": [ | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L14)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Solidity version 0.8.20 or above uses the new [Shanghai EVM](https://blog.soliditylang.org/2023/05/10/solidity-0.8.20-release-announcement/#important-note) which introduces the PUSH0 opcode. This op code may not yet be implemented on all evm-chains or Layer2s, so deployment on these chains will fail. Consider using an earlier solidity version.", | |
"severity": "Low", | |
"title": "Solidity version 0.8.20 or above may not work on other chains due to PUSH0", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L2)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "Low", | |
"title": "Tokens may be minted to `address(0)`", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n47: function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {\n _mint(to, amount);\n }\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L47)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Initializers could be front-run, allowing an attacker to either set their own values, take ownership of the contract, and in the best case forcing a re-deployment", | |
"severity": "Low", | |
"title": "Initializers could be front-run", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n41: function initialize(\n```", | |
"loc": [ | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L41)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n31: function initialize(address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L31)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n29: function initialize(address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[29](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L29)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n26: function initialize(address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[26](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L26)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n32: function initialize(address admin, address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L32)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n27: function initialize(address lrtConfig_) external initializer {\n```", | |
"loc": [ | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L27)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Doing so will significantly increase centralization, but will help to prevent hackers from using stolen tokens.", | |
"severity": "NonCritical", | |
"title": "Consider adding a block/deny-list", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n12: contract LRTConfig is ILRTConfig, AccessControlUpgradeable {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L12)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n19: contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n18: contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L18)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n14: contract RSETH is\n Initializable,\n LRTConfigRoleChecker,\n ERC20Upgradeable,\n PausableUpgradeable,\n AccessControlUpgradeable\n {\n```", | |
"loc": [ | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L14)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n17: contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L17)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n13: abstract contract LRTConfigRoleChecker {\n```", | |
"loc": [ | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L13)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Consider adding `Pausable` to the following contracts so it's possible to stop them in case of an emergency.", | |
"severity": "NonCritical", | |
"title": "Consider adding emergency-stop functionality", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n12: contract LRTConfig is ILRTConfig, AccessControlUpgradeable {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L12)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n17: contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L17)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Formal verification is the act of proving or disproving the correctness of intended algorithms underlying a system with respect to a certain formal specification/property/invariant, using formal methods of mathematics.\n\nSome tools that are currently available to perform these tests on smart contracts are [SMTChecker](https://docs.soliditylang.org/en/latest/smtchecker.html) and [Certora Prover](https://www.certora.com/).", | |
"severity": "NonCritical", | |
"title": "Consider adding formal verification proofs", | |
"instances": [ | |
{ | |
"content": "```solidity\n\nGlobal finding\n```", | |
"loc": [ | |
"[1](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Putting constants on the left side of comparison statements is a best practice known as [Yoda conditions](https://en.wikipedia.org/wiki/Yoda_conditions). Although solidity's static typing system prevents accidental assignments within conditionals, adopting this practice can improve code readability and consistency, especially when working across multiple languages.", | |
"severity": "NonCritical", | |
"title": "Constants should be put on the left side of comparisons", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n129: if (depositAmount == 0) {\n```", | |
"loc": [ | |
"[129](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L129)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n56: if (rsEthSupply == 0) {\n```", | |
"loc": [ | |
"[56](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L56)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n12: if (address_ == address(0)) revert ZeroAddressNotAllowed();\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L12)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "The [style guide](https://docs.soliditylang.org/en/v0.8.16/style-guide.html#order-of-layout) says that, within a contract, the ordering should be `1) Type declarations`, `2) State variables`, `3) Events`, `4) Modifiers`, and `5) Functions`, but the contract(s) below do not follow this ordering", | |
"severity": "NonCritical", | |
"title": "Contract does not follow the Solidity Style Guide's suggested layout ordering", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit function `constructor` came earlier\n28: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[28](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L28)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n/// @audit function `latestAnswer` came earlier\n18: mapping(address asset => address priceFeed) public override assetPriceFeed;\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L18)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "All `external`/`public` functions should extend an `interface`. This is useful to make sure that the whole API is extracted.\n\n*Note:* It is possible that the interface is out-of-scope and has not been seen by the bot.", | |
"severity": "NonCritical", | |
"title": "Contract should expose an `interface`", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n41: function initialize(\n\n73: function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {\n\n94: function updateAssetDepositLimit(\n\n109: function updateAssetStrategy(\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L41)", | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L73)", | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L94)", | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L109)", | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)", | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n31: function initialize(address lrtConfigAddr) external initializer {\n\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n\n56: function getAssetCurrentLimit(address asset) public view override returns (uint256) {\n\n62: function getNodeDelegatorQueue() external view override returns (address[] memory) {\n\n71: function getAssetDistributionData(address asset)\n\n95: function getRsETHAmountToMint(\n\n119: function depositAsset(\n\n162: function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin {\n\n183: function transferAssetToNodeDelegator(\n\n202: function updateMaxNodeDelegatorCount(uint256 maxNodeDelegatorCount_) external onlyLRTAdmin {\n\n208: function pause() external onlyLRTManager {\n\n213: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L31)", | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)", | |
"[56](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L56)", | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L62)", | |
"[71](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L71)", | |
"[95](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L95)", | |
"[119](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L119)", | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L162)", | |
"[183](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L183)", | |
"[202](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L202)", | |
"[208](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L208)", | |
"[213](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L213)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n29: function initialize(address lrtConfigAddr) external initializer {\n\n45: function getAssetPrice(address asset) public view onlySupportedAsset(asset) returns (uint256) {\n\n52: function getRSETHPrice() external view returns (uint256 rsETHPrice) {\n\n88: function updatePriceOracleFor(\n\n102: function pause() external onlyLRTManager {\n\n107: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[29](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L29)", | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L45)", | |
"[52](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L52)", | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L88)", | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L102)", | |
"[107](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L107)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n26: function initialize(address lrtConfigAddr) external initializer {\n\n38: function maxApproveToEigenStrategyManager(address asset)\n\n51: function depositAssetIntoStrategy(address asset)\n\n74: function transferBackToLRTDepositPool(\n\n94: function getAssetBalances()\n\n121: function getAssetBalance(address asset) external view override returns (uint256) {\n\n127: function pause() external onlyLRTManager {\n\n132: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[26](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L26)", | |
"[38](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L38)", | |
"[51](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L51)", | |
"[74](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L74)", | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L94)", | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L121)", | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L127)", | |
"[132](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L132)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n32: function initialize(address admin, address lrtConfigAddr) external initializer {\n\n47: function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {\n\n54: function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {\n\n60: function pause() external onlyLRTManager {\n\n66: function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n73: function updateLRTConfig(address _lrtConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L32)", | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L47)", | |
"[54](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L54)", | |
"[60](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L60)", | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L66)", | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L73)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n27: function initialize(address lrtConfig_) external initializer {\n\n37: function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {\n\n45: function updatePriceFeedFor(address asset, address priceFeed) external onlyLRTManager onlySupportedAsset(asset) {\n```", | |
"loc": [ | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L27)", | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L37)", | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L45)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n47: function updateLRTConfig(address lrtConfigAddr) external virtual onlyLRTAdmin {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L47)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Keeping each contract in a separate file makes it easier to work with multiple people, makes the code easier to maintain, and is a common practice on most projects. The following files each contains more than one contract/library/interface.", | |
"severity": "NonCritical", | |
"title": "Contracts should each be defined in separate files", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n/// @audit another contract is defined in this file\n11: interface AggregatorInterface {\n\n/// @audit another contract is defined in this file\n17: contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)", | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L17)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "While 100% code coverage does not guarantee that there are no bugs, it often will catch easy-to-find bugs, and will ensure that there are fewer regressions when the code invariably has to be modified. Furthermore, in order to get full coverage, code authors will often have to re-organize their code so that it is more modular, so that each component can be tested separately, which reduces interdependencies between modules and layers, and makes for code that is easier to reason about and audit.", | |
"severity": "NonCritical", | |
"title": "Contracts should have full test coverage", | |
"instances": [ | |
{ | |
"content": "```solidity\n\nGlobal finding\n```", | |
"loc": [ | |
"[1](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "This should especially be done if the new value is not required to be different from the old value.", | |
"severity": "NonCritical", | |
"title": "Events that mark critical parameter changes should contain both the old and the new value", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n88: emit AddedNewSupportedAsset(asset, depositLimit);\n\n103: emit AssetDepositLimitUpdate(asset, depositLimit);\n\n162: emit SetToken(key, val);\n\n178: emit SetContract(key, val);\n```", | |
"loc": [ | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L88)", | |
"[103](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L103)", | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L162)", | |
"[178](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L178)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n37: emit UpdatedLRTConfig(lrtConfigAddr);\n\n143: emit AssetDeposit(asset, depositAmount, rsethAmountMinted);\n\n171: emit NodeDelegatorAddedinQueue(nodeDelegatorContracts[i]);\n\n204: emit MaxNodeDelegatorCountUpdated(maxNodeDelegatorCount);\n```", | |
"loc": [ | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L37)", | |
"[143](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L143)", | |
"[171](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L171)", | |
"[204](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L204)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n34: emit UpdatedLRTConfig(lrtConfigAddr);\n\n98: emit AssetPriceOracleUpdate(asset, priceOracle);\n```", | |
"loc": [ | |
"[34](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L34)", | |
"[98](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L98)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n32: emit UpdatedLRTConfig(lrtConfigAddr);\n\n65: emit AssetDepositIntoStrategy(asset, strategy, balance);\n```", | |
"loc": [ | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L32)", | |
"[65](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L65)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n41: emit UpdatedLRTConfig(lrtConfigAddr);\n\n76: emit UpdatedLRTConfig(_lrtConfig);\n```", | |
"loc": [ | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L41)", | |
"[76](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L76)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n31: emit UpdatedLRTConfig(lrtConfig_);\n\n48: emit AssetPriceFeedUpdate(asset, priceFeed);\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L31)", | |
"[48](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L48)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n50: emit UpdatedLRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[50](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L50)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Consider adding parameters to the error to indicate which user or values caused the failure.", | |
"severity": "NonCritical", | |
"title": "Custom errors has no error details", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n7: error ZeroAddressNotAllowed();\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L7)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Refactoring duplicate `require()`/`revert()` checks into a modifier or function can make the code more concise, readable and maintainable, and less likely to make errors or omissions when modifying the `require()` or `revert()`.", | |
"severity": "NonCritical", | |
"title": "Duplicated `require()`/`revert()` checks should be refactored", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit duplicated on line 159\n119: revert ValueAlreadyInUse();\n```", | |
"loc": [ | |
"[119](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L119)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit duplicated on line 195\n137: revert TokenTransferFailed();\n```", | |
"loc": [ | |
"[137](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L137)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "The IR-based code generator was introduced with an aim to not only allow code generation to be more transparent and auditable but also to enable more powerful optimization passes that span across functions. You can enable it on the command line using `--via-ir` or with the option `{\"viaIR\": true}`. This will take longer to compile, but you can just simple test it before deploying and if you got a better benchmark then you can add --via-ir to your deploy command More on: https://docs.soliditylang.org/en/v0.8.17/ir-breaking-changes.html", | |
"severity": "NonCritical", | |
"title": "Enable IR-based code generation", | |
"instances": [ | |
{ | |
"content": "```solidity\n\nGlobal finding\n```", | |
"loc": [ | |
"[1](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "When an action is triggered based on a user's action, not being able to filter based on who triggered the action makes event processing a lot more cumbersome. Including the `msg.sender` the events of these types of action will make events much more useful to end users, especially when `msg.sender` is not `tx.origin`.", | |
"severity": "NonCritical", | |
"title": "Events are emitted without the sender information", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n88: emit AddedNewSupportedAsset(asset, depositLimit);\n\n103: emit AssetDepositLimitUpdate(asset, depositLimit);\n\n162: emit SetToken(key, val);\n\n178: emit SetContract(key, val);\n```", | |
"loc": [ | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L88)", | |
"[103](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L103)", | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L162)", | |
"[178](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L178)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n37: emit UpdatedLRTConfig(lrtConfigAddr);\n\n143: emit AssetDeposit(asset, depositAmount, rsethAmountMinted);\n\n204: emit MaxNodeDelegatorCountUpdated(maxNodeDelegatorCount);\n```", | |
"loc": [ | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L37)", | |
"[143](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L143)", | |
"[204](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L204)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n34: emit UpdatedLRTConfig(lrtConfigAddr);\n\n98: emit AssetPriceOracleUpdate(asset, priceOracle);\n```", | |
"loc": [ | |
"[34](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L34)", | |
"[98](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L98)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n32: emit UpdatedLRTConfig(lrtConfigAddr);\n\n65: emit AssetDepositIntoStrategy(asset, strategy, balance);\n```", | |
"loc": [ | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L32)", | |
"[65](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L65)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n41: emit UpdatedLRTConfig(lrtConfigAddr);\n\n76: emit UpdatedLRTConfig(_lrtConfig);\n```", | |
"loc": [ | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L41)", | |
"[76](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L76)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n31: emit UpdatedLRTConfig(lrtConfig_);\n\n48: emit AssetPriceFeedUpdate(asset, priceFeed);\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L31)", | |
"[48](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L48)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n50: emit UpdatedLRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[50](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L50)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Ensure that events follow the best practice of check-effects-interaction, and are emitted before external calls.", | |
"severity": "NonCritical", | |
"title": "Events may be emitted out of order due to reentrancy", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `.transferFrom(..)` is called before emit\n143: emit AssetDeposit(asset, depositAmount, rsethAmountMinted);\n```", | |
"loc": [ | |
"[143](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L143)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n/// @audit `.assetStrategy(..)` is called before emit\n65: emit AssetDepositIntoStrategy(asset, strategy, balance);\n\n/// @audit `.getContract(..)` is called before emit\n65: emit AssetDepositIntoStrategy(asset, strategy, balance);\n\n/// @audit `.balanceOf(..)` is called before emit\n65: emit AssetDepositIntoStrategy(asset, strategy, balance);\n```", | |
"loc": [ | |
"[65](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L65)", | |
"[65](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L65)", | |
"[65](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L65)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "According to the [solidity style guide](https://docs.soliditylang.org/en/v0.8.17/style-guide.html#order-of-functions), functions should be laid out in the following order: `constructor()`, `receive()`, `fallback()`, `external`, `public`, `internal`, `private`, but the cases below do not follow this pattern", | |
"severity": "NonCritical", | |
"title": " Function ordering does not follow the Solidity Style Guide", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n94: function updateAssetDepositLimit(\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n109: function updateAssetStrategy(\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n/// @audit private function `_addNewSupportedAsset` came earlier from this external function\n/// @audit private function `_setToken` came earlier from this external function\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L94)", | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L109)", | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)", | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n62: function getNodeDelegatorQueue() external view override returns (address[] memory) {\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n/// @audit public function `getAssetDistributionData` came earlier from this external function\n/// @audit public function `getRsETHAmountToMint` came earlier from this external function\n119: function depositAsset(\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n/// @audit public function `getAssetDistributionData` came earlier from this external function\n/// @audit public function `getRsETHAmountToMint` came earlier from this external function\n/// @audit private function `_mintRsETH` came earlier from this external function\n162: function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin {\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n/// @audit public function `getAssetDistributionData` came earlier from this external function\n/// @audit public function `getRsETHAmountToMint` came earlier from this external function\n/// @audit private function `_mintRsETH` came earlier from this external function\n183: function transferAssetToNodeDelegator(\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n/// @audit public function `getAssetDistributionData` came earlier from this external function\n/// @audit public function `getRsETHAmountToMint` came earlier from this external function\n/// @audit private function `_mintRsETH` came earlier from this external function\n202: function updateMaxNodeDelegatorCount(uint256 maxNodeDelegatorCount_) external onlyLRTAdmin {\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n/// @audit public function `getAssetDistributionData` came earlier from this external function\n/// @audit public function `getRsETHAmountToMint` came earlier from this external function\n/// @audit private function `_mintRsETH` came earlier from this external function\n208: function pause() external onlyLRTManager {\n\n/// @audit public function `getTotalAssetDeposits` came earlier from this external function\n/// @audit public function `getAssetCurrentLimit` came earlier from this external function\n/// @audit public function `getAssetDistributionData` came earlier from this external function\n/// @audit public function `getRsETHAmountToMint` came earlier from this external function\n/// @audit private function `_mintRsETH` came earlier from this external function\n213: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L62)", | |
"[119](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L119)", | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L162)", | |
"[183](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L183)", | |
"[202](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L202)", | |
"[208](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L208)", | |
"[213](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L213)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit public function `getAssetPrice` came earlier from this external function\n52: function getRSETHPrice() external view returns (uint256 rsETHPrice) {\n\n/// @audit public function `getAssetPrice` came earlier from this external function\n88: function updatePriceOracleFor(\n\n/// @audit public function `getAssetPrice` came earlier from this external function\n102: function pause() external onlyLRTManager {\n\n/// @audit public function `getAssetPrice` came earlier from this external function\n107: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[52](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L52)", | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L88)", | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L102)", | |
"[107](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L107)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n/// @audit a function was seen before constructor\n21: constructor() {\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L21)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some lines use `// x` and some use `//x`. The instances below point out the usages that don't follow the majority, within each file", | |
"severity": "NonCritical", | |
"title": "Inconsistent spacing in comments", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n126: //////////////////////////////////////////////////////////////*/\n\n141: //////////////////////////////////////////////////////////////*/\n```", | |
"loc": [ | |
"[126](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L126)", | |
"[141](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L141)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n42: //////////////////////////////////////////////////////////////*/\n\n114: //////////////////////////////////////////////////////////////*/\n```", | |
"loc": [ | |
"[42](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L42)", | |
"[114](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L114)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n39: //////////////////////////////////////////////////////////////*/\n\n83: //////////////////////////////////////////////////////////////*/\n```", | |
"loc": [ | |
"[39](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L39)", | |
"[83](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L83)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n5: //tokens\n\n6: //rETH token\n\n8: //stETH token\n\n10: //cbETH token\n\n13: //contracts\n\n18: //Roles\n```", | |
"loc": [ | |
"[5](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L5)", | |
"[6](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L6)", | |
"[8](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L8)", | |
"[10](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L10)", | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L13)", | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L18)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "As a best practice, any `interface` should have an `I` as a prefix in their contract name.", | |
"severity": "NonCritical", | |
"title": "Interfaces should have an `I` prefix in the contract name", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n11: interface AggregatorInterface {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "This includes: large code bases, or code with lots of inline-assembly, complicated math, or complicated interactions between multiple contracts. Invariant fuzzers such as Echidna require the test writer to come up with invariants which should not be violated under any circumstances, and the fuzzer tests various inputs and function calls to ensure that the invariants always hold. Even code with 100% code coverage can still have bugs due to the order of the operations a user performs, and invariant fuzzers may help significantly.", | |
"severity": "NonCritical", | |
"title": "Large or complicated code bases should implement invariant tests", | |
"instances": [ | |
{ | |
"content": "```solidity\n\nGlobal finding\n```", | |
"loc": [ | |
"[1](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Use a scientific notation rather than decimal literals (e.g. `1e6` instead of `1000000`), for better code readability.", | |
"severity": "NonCritical", | |
"title": "Large multiples of ten should use scientific notation", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n61: _addNewSupportedAsset(stETH, 100_000 ether);\n\n62: _addNewSupportedAsset(rETH, 100_000 ether);\n\n63: _addNewSupportedAsset(cbETH, 100_000 ether);\n```", | |
"loc": [ | |
"[61](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L61)", | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L62)", | |
"[63](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L63)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Magic numbers are hard-coded values in code that can make it difficult for developers and maintainers to understand the code, and can also cause confusion or errors. To improve the readability and maintainability of code, it is recommended to replace magic numbers with constants that have good readability.", | |
"severity": "NonCritical", | |
"title": "Magic numbers should be replaced with constants", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n// @audit `100_000`\n61: _addNewSupportedAsset(stETH, 100_000 ether);\n\n// @audit `100_000`\n62: _addNewSupportedAsset(rETH, 100_000 ether);\n\n// @audit `100_000`\n63: _addNewSupportedAsset(cbETH, 100_000 ether);\n```", | |
"loc": [ | |
"[61](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L61)", | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L62)", | |
"[63](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L63)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n// @audit `10`\n35: maxNodeDelegatorCount = 10;\n```", | |
"loc": [ | |
"[35](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L35)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "e.g. `@dev` or `@notice`, and it must appear above the contract definition braces in order to be identified by the compiler as NatSpec.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec from contract declarations", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n11: interface AggregatorInterface {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n4: library LRTConstants {\n```", | |
"loc": [ | |
"[4](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L4)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some contract definitions have an incomplete NatSpec: add a `@author` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@author` from contract declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n12: contract LRTConfig is ILRTConfig, AccessControlUpgradeable {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L12)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n19: contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n18: contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L18)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n11: interface AggregatorInterface {\n\n17: contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)", | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L17)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n13: abstract contract LRTConfigRoleChecker {\n```", | |
"loc": [ | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L13)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n4: library LRTConstants {\n```", | |
"loc": [ | |
"[4](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L4)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n6: library UtilLib {\n```", | |
"loc": [ | |
"[6](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L6)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some contract definitions have an incomplete NatSpec: add a `@dev` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@dev` from contract declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n12: contract LRTConfig is ILRTConfig, AccessControlUpgradeable {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L12)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n19: contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n18: contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L18)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n14: contract RSETH is\n```", | |
"loc": [ | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L14)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n11: interface AggregatorInterface {\n\n17: contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)", | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L17)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n13: abstract contract LRTConfigRoleChecker {\n```", | |
"loc": [ | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L13)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n4: library LRTConstants {\n```", | |
"loc": [ | |
"[4](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L4)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n6: library UtilLib {\n```", | |
"loc": [ | |
"[6](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L6)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some event definitions have an incomplete NatSpec: add a `@dev` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@dev` from event declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n17: event UpdatedLRTConfig(address indexed lrtConfig);\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L17)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some function definitions have an incomplete NatSpec: add a `@dev` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@dev` from function declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n24: constructor() {\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[24](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L24)", | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n25: constructor() {\n\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n\n56: function getAssetCurrentLimit(address asset) public view override returns (uint256) {\n\n95: function getRsETHAmountToMint(\n\n119: function depositAsset(\n```", | |
"loc": [ | |
"[25](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L25)", | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)", | |
"[56](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L56)", | |
"[95](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L95)", | |
"[119](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L119)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n23: constructor() {\n```", | |
"loc": [ | |
"[23](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L23)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n20: constructor() {\n\n94: function getAssetBalances()\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L20)", | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L94)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n25: constructor() {\n\n47: function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {\n\n54: function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {\n```", | |
"loc": [ | |
"[25](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L25)", | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L47)", | |
"[54](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L54)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n12: function latestAnswer() external view returns (uint256);\n\n21: constructor() {\n\n37: function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L12)", | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L21)", | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L37)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some modifier definitions have an incomplete NatSpec: add a `@dev` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@dev` from modifier declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n28: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[28](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L28)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n20: modifier onlyLRTManager() {\n\n27: modifier onlyLRTAdmin() {\n\n35: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L20)", | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L27)", | |
"[35](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L35)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": "Error declarations should have NatSpec descriptions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n7: error ZeroAddressNotAllowed();\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L7)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": "Event declarations should have NatSpec descriptions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n17: event UpdatedLRTConfig(address indexed lrtConfig);\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L17)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI). It is clearly stated in the Solidity official documentation. In complex projects such as DeFi, the interpretation of all functions and their arguments and returns is important for code readability and auditability.", | |
"severity": "NonCritical", | |
"title": "NatSpec documentation for function is missing", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n12: function latestAnswer() external view returns (uint256);\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L12)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": "Modifier declarations should have NatSpec descriptions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n28: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[28](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L28)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n20: modifier onlyLRTManager() {\n\n27: modifier onlyLRTAdmin() {\n\n35: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L20)", | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L27)", | |
"[35](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L35)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": "Public variable declarations should have NatSpec descriptions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n13: mapping(bytes32 tokenKey => address tokenAddress) public tokenMap;\n\n14: mapping(bytes32 contractKey => address contractAddress) public contractMap;\n\n15: mapping(address token => bool isSupported) public isSupportedAsset;\n\n16: mapping(address token => uint256 amount) public depositLimitByAsset;\n\n17: mapping(address token => address strategy) public override assetStrategy;\n\n19: address[] public supportedAssetList;\n\n21: address public rsETH;\n```", | |
"loc": [ | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L13)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L16)", | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L17)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L19)", | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L21)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n20: uint256 public maxNodeDelegatorCount;\n\n22: address[] public nodeDelegatorQueue;\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L20)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n20: mapping(address asset => address priceOracle) public override assetPriceOracle;\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L20)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n21: bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n22: bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L21)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n18: mapping(address asset => address priceFeed) public override assetPriceFeed;\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L18)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n7: bytes32 public constant R_ETH_TOKEN = keccak256(\"R_ETH_TOKEN\");\n\n9: bytes32 public constant ST_ETH_TOKEN = keccak256(\"ST_ETH_TOKEN\");\n\n11: bytes32 public constant CB_ETH_TOKEN = keccak256(\"CB_ETH_TOKEN\");\n\n14: bytes32 public constant LRT_ORACLE = keccak256(\"LRT_ORACLE\");\n\n15: bytes32 public constant LRT_DEPOSIT_POOL = keccak256(\"LRT_DEPOSIT_POOL\");\n\n16: bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256(\"EIGEN_STRATEGY_MANAGER\");\n\n19: bytes32 public constant MANAGER = keccak256(\"MANAGER\");\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L7)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L9)", | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L11)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L16)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L19)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some contract definitions have an incomplete NatSpec: add a `@notice` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@notice` from contract declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n11: interface AggregatorInterface {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n4: library LRTConstants {\n```", | |
"loc": [ | |
"[4](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L4)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some event definitions have an incomplete NatSpec: add a `@notice` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@notice` from event declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n17: event UpdatedLRTConfig(address indexed lrtConfig);\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L17)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some function definitions have an incomplete NatSpec: add a `@notice` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@notice` from function declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n24: constructor() {\n\n41: function initialize(\n\n73: function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {\n\n80: function _addNewSupportedAsset(address asset, uint256 depositLimit) private {\n\n94: function updateAssetDepositLimit(\n\n109: function updateAssetStrategy(\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n156: function _setToken(bytes32 key, address val) private {\n\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n172: function _setContract(bytes32 key, address val) private {\n```", | |
"loc": [ | |
"[24](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L24)", | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L41)", | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L73)", | |
"[80](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L80)", | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L94)", | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L109)", | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)", | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[156](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L156)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)", | |
"[172](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L172)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n25: constructor() {\n\n31: function initialize(address lrtConfigAddr) external initializer {\n\n62: function getNodeDelegatorQueue() external view override returns (address[] memory) {\n\n71: function getAssetDistributionData(address asset)\n\n151: function _mintRsETH(address _asset, uint256 _amount) private returns (uint256 rsethAmountToMint) {\n\n208: function pause() external onlyLRTManager {\n\n213: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[25](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L25)", | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L31)", | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L62)", | |
"[71](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L71)", | |
"[151](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L151)", | |
"[208](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L208)", | |
"[213](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L213)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n23: constructor() {\n\n29: function initialize(address lrtConfigAddr) external initializer {\n\n88: function updatePriceOracleFor(\n\n102: function pause() external onlyLRTManager {\n\n107: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[23](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L23)", | |
"[29](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L29)", | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L88)", | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L102)", | |
"[107](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L107)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n20: constructor() {\n\n26: function initialize(address lrtConfigAddr) external initializer {\n\n121: function getAssetBalance(address asset) external view override returns (uint256) {\n\n127: function pause() external onlyLRTManager {\n\n132: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L20)", | |
"[26](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L26)", | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L121)", | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L127)", | |
"[132](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L132)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n25: constructor() {\n\n32: function initialize(address admin, address lrtConfigAddr) external initializer {\n\n60: function pause() external onlyLRTManager {\n```", | |
"loc": [ | |
"[25](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L25)", | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L32)", | |
"[60](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L60)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n12: function latestAnswer() external view returns (uint256);\n\n21: constructor() {\n\n27: function initialize(address lrtConfig_) external initializer {\n\n45: function updatePriceFeedFor(address asset, address priceFeed) external onlyLRTManager onlySupportedAsset(asset) {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L12)", | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L21)", | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L27)", | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L45)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n11: function checkNonZeroAddress(address address_) internal pure {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L11)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some modifier definitions have an incomplete NatSpec: add a `@notice` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@notice` from modifier declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n28: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[28](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L28)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n20: modifier onlyLRTManager() {\n\n27: modifier onlyLRTAdmin() {\n\n35: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L20)", | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L27)", | |
"[35](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L35)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some event definitions have an incomplete NatSpec: add a `@param` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@param` from event declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n17: event UpdatedLRTConfig(address indexed lrtConfig);\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L17)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some function definitions have an incomplete NatSpec: add a `@param` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@param` from function declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit missing @param for `tokenKey`\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n/// @audit missing @param for `contractKey`\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n/// @audit missing @param for `tokenKey`\n/// @audit missing @param for `assetAddress`\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n/// @audit missing @param for `contractKey`\n/// @audit missing @param for `contractAddress`\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit missing @param for `priceOracle`\n88: function updatePriceOracleFor(\n address asset,\n address priceOracle\n )\n external\n onlyLRTManager\n onlySupportedAsset(asset)\n {\n```", | |
"loc": [ | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L88)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some modifier definitions have an incomplete NatSpec: add a `@param` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@param` from modifier declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n28: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[28](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L28)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n35: modifier onlySupportedAsset(address asset) {\n```", | |
"loc": [ | |
"[35](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L35)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some function definitions have an incomplete NatSpec: add a `@return` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@return` from function declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n12: function latestAnswer() external view returns (uint256);\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L12)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Some contract definitions have an incomplete NatSpec: add a `@title` notation to improve the code documentation.", | |
"severity": "NonCritical", | |
"title": "Missing NatSpec `@title` from contract declaration", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n11: interface AggregatorInterface {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L11)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n4: library LRTConstants {\n```", | |
"loc": [ | |
"[4](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L4)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Since the variables are automatically set to 0 when created, it is redundant to initialize it with 0 again.", | |
"severity": "NonCritical", | |
"title": "There is no need to initialize variables with 0", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n109: for (uint256 i = 0; i < strategiesLength;) {\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L109)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Putting all the system-wide constants in a single file improves code readability, makes it easier to understand the basic configuration and limitations of the system, and makes maintenance easier.", | |
"severity": "NonCritical", | |
"title": "Put all system-wide constants in one file", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n21: bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n22: bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L21)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n7: bytes32 public constant R_ETH_TOKEN = keccak256(\"R_ETH_TOKEN\");\n\n9: bytes32 public constant ST_ETH_TOKEN = keccak256(\"ST_ETH_TOKEN\");\n\n11: bytes32 public constant CB_ETH_TOKEN = keccak256(\"CB_ETH_TOKEN\");\n\n14: bytes32 public constant LRT_ORACLE = keccak256(\"LRT_ORACLE\");\n\n15: bytes32 public constant LRT_DEPOSIT_POOL = keccak256(\"LRT_DEPOSIT_POOL\");\n\n16: bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256(\"EIGEN_STRATEGY_MANAGER\");\n\n19: bytes32 public constant MANAGER = keccak256(\"MANAGER\");\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L7)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L9)", | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L11)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L16)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L19)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Because the return variable (or its default value) has been assigned, explicit return at the end of the function is unnecessary, as it is returned automatically.", | |
"severity": "NonCritical", | |
"title": "Redundant `return` statement in a function with named return variables", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n52: function getRSETHPrice() external view returns (uint256 rsETHPrice) {\n```", | |
"loc": [ | |
"[52](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L52)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Not only is wasteful in terms of gas, but this is especially problematic when an event is emitted and the old and new values set are the same, as listeners might not expect this kind of scenario.", | |
"severity": "NonCritical", | |
"title": "Setters should prevent re-setting the same value", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n102: depositLimitByAsset[asset] = depositLimit;\n\n121: assetStrategy[asset] = strategy;\n\n146: rsETH = rsETH_;\n\n161: tokenMap[key] = val;\n\n177: contractMap[key] = val;\n```", | |
"loc": [ | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L102)", | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L121)", | |
"[146](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L146)", | |
"[161](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L161)", | |
"[177](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L177)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n203: maxNodeDelegatorCount = maxNodeDelegatorCount_;\n```", | |
"loc": [ | |
"[203](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L203)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n97: assetPriceOracle[asset] = priceOracle;\n```", | |
"loc": [ | |
"[97](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L97)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n47: assetPriceFeed[asset] = priceFeed;\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L47)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Consider adding some comments on critical state variables to explain what they are supposed to do: this will help for future code reviews.", | |
"severity": "NonCritical", | |
"title": "State variables should include comments", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n20: uint256 public maxNodeDelegatorCount;\n\n22: address[] public nodeDelegatorQueue;\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L20)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L22)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "This is a best-practice to protect against reentrancy in other modifiers.", | |
"severity": "NonCritical", | |
"title": "The `nonReentrant` modifier should occur before all other modifiers", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n119: function depositAsset(\n address asset,\n uint256 depositAmount\n )\n external\n whenNotPaused\n nonReentrant\n```", | |
"loc": [ | |
"[119](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L119)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n51: function depositAssetIntoStrategy(address asset)\n external\n override\n whenNotPaused\n nonReentrant\n\n74: function transferBackToLRTDepositPool(\n address asset,\n uint256 amount\n )\n external\n whenNotPaused\n nonReentrant\n```", | |
"loc": [ | |
"[51](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L51)", | |
"[74](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L74)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "The [solidity style guide](https://docs.soliditylang.org/en/v0.8.17/style-guide.html#maximum-line-length) recommends a maximum line length of 120 characters. Lines of code that are longer than 120 should be wrapped.", | |
"severity": "NonCritical", | |
"title": "Lines are too long", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n8: import { AccessControlUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol\";\n```", | |
"loc": [ | |
"[8](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L8)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n13: import { IERC20 } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\";\n\n14: import { PausableUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/security/PausableUpgradeable.sol\";\n\n15: import { ReentrancyGuardUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol\";\n```", | |
"loc": [ | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L13)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L15)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n15: import { PausableUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/security/PausableUpgradeable.sol\";\n```", | |
"loc": [ | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L15)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n13: import { PausableUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/security/PausableUpgradeable.sol\";\n\n14: import { ReentrancyGuardUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol\";\n\n67: IEigenStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy(IStrategy(strategy), token, balance);\n```", | |
"loc": [ | |
"[13](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L13)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L14)", | |
"[67](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L67)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n7: import { ERC20Upgradeable, Initializable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol\";\n\n8: import { AccessControlUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol\";\n\n9: import { PausableUpgradeable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/security/PausableUpgradeable.sol\";\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L7)", | |
"[8](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L8)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L9)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n9: import { Initializable } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\";\n```", | |
"loc": [ | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L9)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n9: import { IAccessControl } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol\";\n```", | |
"loc": [ | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L9)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": "Typos", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `eigen`\n70: /// @return assetStakedInEigenLayer asset amount staked in eigen layer through all NDCs\n\n/// @audit `rseth`\n94: /// @return rsethAmountToMint Amount of rseth to mint\n\n/// @audit `rseth`\n108: // calculate rseth amount to mint based on asset amount and asset exchange rate\n\n/// @audit `rseth`\n146: /// @dev private function to mint rseth. It calculates rseth amount to mint based on asset amount and asset exchange\n\n/// @audit `rseth`\n149: /// @param _amount Asset amount to mint rseth\n\n/// @audit `rseth`\n150: /// @return rsethAmountToMint Amount of rseth minted\n\n/// @audit `rseth`\n155: // mint rseth for user\n```", | |
"loc": [ | |
"[70](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L70)", | |
"[94](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L94)", | |
"[108](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L108)", | |
"[146](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L146)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L149)", | |
"[150](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L150)", | |
"[155](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L155)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `eigen`\n50: /// @dev calculates based on stakedAsset value received from eigen layer\n```", | |
"loc": [ | |
"[50](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L50)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n/// @audit `eigen`\n35: /// @notice Approves the maximum amount of an asset to the eigen strategy manager\n\n/// @audit `eigen`\n91: /// @notice Fetches balance of all assets staked in eigen layer through this contract\n```", | |
"loc": [ | |
"[35](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L35)", | |
"[91](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L91)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "The variable is being cast to its own type.", | |
"severity": "NonCritical", | |
"title": "Unnecessary cast", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n/// @audit no need to cast `lrtConfig` into address\n21: if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) {\n\n/// @audit no need to cast `lrtConfig` into address\n29: if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L21)", | |
"[29](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L29)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "The identifier is imported but never used within the file.", | |
"severity": "NonCritical", | |
"title": "Unused import", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `INodeDelegator`\n12: import { INodeDelegator } from \"./interfaces/INodeDelegator.sol\";\n\n/// @audit `IERC20`\n14: import { IERC20 } from \"/home/myubuntu/Desktop/2023-11-kelp/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol\";\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L12)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L14)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Declaring named returns, but not using them, is confusing to the reader. Consider either completely removing them (by declaring just the type without a name), or remove the return statement and do a variable assignment. This would improve the readability of the code, and it may also help reduce regressions during future code refactors.", | |
"severity": "NonCritical", | |
"title": "Unused named return", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `totalAssetDeposit` not used\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `rsETHPrice` not used\n52: function getRSETHPrice() external view returns (uint256 rsETHPrice) {\n```", | |
"loc": [ | |
"[52](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L52)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "While it doesn't save any gas because the compiler knows that developers often make this mistake, it's still best to use the right tool for the task at hand. There is a difference between `constant` variables and `immutable` variables, and they should each be used in their appropriate contexts. `constants` should be used for literal values written into the code, and `immutable` variables should be used for expressions, or values calculated in, or passed into the constructor.", | |
"severity": "NonCritical", | |
"title": "Expressions for constant values should use `immutable` rather than `constant`", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n21: bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n22: bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L21)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n7: bytes32 public constant R_ETH_TOKEN = keccak256(\"R_ETH_TOKEN\");\n\n9: bytes32 public constant ST_ETH_TOKEN = keccak256(\"ST_ETH_TOKEN\");\n\n11: bytes32 public constant CB_ETH_TOKEN = keccak256(\"CB_ETH_TOKEN\");\n\n14: bytes32 public constant LRT_ORACLE = keccak256(\"LRT_ORACLE\");\n\n15: bytes32 public constant LRT_DEPOSIT_POOL = keccak256(\"LRT_DEPOSIT_POOL\");\n\n16: bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256(\"EIGEN_STRATEGY_MANAGER\");\n\n19: bytes32 public constant MANAGER = keccak256(\"MANAGER\");\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L7)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L9)", | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L11)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L16)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L19)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": "Use `@inheritdoc` for overridden functions", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n\n56: function getAssetCurrentLimit(address asset) public view override returns (uint256) {\n\n62: function getNodeDelegatorQueue() external view override returns (address[] memory) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)", | |
"[56](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L56)", | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L62)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n121: function getAssetBalance(address asset) external view override returns (uint256) {\n```", | |
"loc": [ | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L121)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n73: function updateLRTConfig(address _lrtConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L73)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Upgrading to a newer Solidity release can optimize gas usage, take advantage of new features and improve overall contract efficiency. Where possible, based on compatibility requirements, it is recommended to use newer/latest solidity version to take advantage of the latest optimizations and features.", | |
"severity": "NonCritical", | |
"title": "Use the latest solidity version for deployment (`0.8.23`)", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L2)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "Starting with Solidity version [0.8.8](https://docs.soliditylang.org/en/v0.8.20/contracts.html#function-overriding), using the `override` keyword when the function solely overrides an interface function, and the function doesn't exist in multiple base contracts, is unnecessary.", | |
"severity": "NonCritical", | |
"title": "Use of `override` is unnecessary", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n127: function getLSTToken(bytes32 tokenKey) external view override returns (address) {\n\n131: function getContract(bytes32 contractKey) external view override returns (address) {\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L127)", | |
"[131](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L131)", | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n\n56: function getAssetCurrentLimit(address asset) public view override returns (uint256) {\n\n62: function getNodeDelegatorQueue() external view override returns (address[] memory) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)", | |
"[56](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L56)", | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L62)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n121: function getAssetBalance(address asset) external view override returns (uint256) {\n```", | |
"loc": [ | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L121)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n73: function updateLRTConfig(address _lrtConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L73)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "The functions below have the same implementation as is seen in other files. The functions should be refactored into functions of a common base contract.", | |
"severity": "NonCritical", | |
"title": "Common functions should be refactored to a common base contract", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit seen in src/NodeDelegator.sol\n208: function pause() external onlyLRTManager {\n\n/// @audit seen in src/NodeDelegator.sol\n213: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[208](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L208)", | |
"[213](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L213)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit seen in src/LRTDepositPool.sol\n102: function pause() external onlyLRTManager {\n\n/// @audit seen in src/LRTDepositPool.sol\n107: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L102)", | |
"[107](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L107)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n/// @audit seen in src/LRTDepositPool.sol\n127: function pause() external onlyLRTManager {\n\n/// @audit seen in src/LRTDepositPool.sol\n132: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L127)", | |
"[132](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L132)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n/// @audit seen in src/LRTDepositPool.sol\n60: function pause() external onlyLRTManager {\n\n/// @audit seen in src/LRTDepositPool.sol\n66: function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[60](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L60)", | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L66)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "It is recommended by the [Solidity Style Guide](https://docs.soliditylang.org/en/v0.8.20/style-guide.html#underscore-prefix-for-non-external-functions-and-variables)", | |
"severity": "NonCritical", | |
"title": "Names of `private`/`internal` functions should be prefixed with an underscore", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n11: function checkNonZeroAddress(address address_) internal pure {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L11)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "NonCritical", | |
"title": " `require()` / `revert()` statements should have descriptive reason strings", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n22: revert ILRTConfig.CallerNotLRTConfigManager();\n\n30: revert ILRTConfig.CallerNotLRTConfigAdmin();\n\n37: revert ILRTConfig.AssetNotSupported();\n```", | |
"loc": [ | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L22)", | |
"[30](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L30)", | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L37)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"description": "As the [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html#naming-styles) suggests: `arguments`, `local variables` and `mutable state variables` should be named in mixedCase style.", | |
"severity": "NonCritical", | |
"title": "Variables should be named in mixedCase style", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n/// @audit `DEFAULT_ADMIN_ROLE`\n28: bytes32 DEFAULT_ADMIN_ROLE = 0x00;\n```", | |
"loc": [ | |
"[28](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L28)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 1020, | |
"description": "Using `do-while` loops instead of `for` loops can be more gas-efficient. Even if you add an `if` condition to account for the case where the loop doesn't execute at all, a `do-while` loop can still be cheaper in terms of gas.", | |
"severity": "Gas", | |
"title": "Optimize Gas by Using Do-While Loops", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n82: for (uint256 i; i < ndcsCount;) {\n\n168: for (uint256 i; i < length;) {\n```", | |
"loc": [ | |
"[82](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L82)", | |
"[168](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L168)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {\n```", | |
"loc": [ | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L66)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n109: for (uint256 i = 0; i < strategiesLength;) {\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L109)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "By using `--via-ir` or `{\"viaIR\": true}`, the compiler is able to use more advanced [multi-function optimizations](https://docs.soliditylang.org/en/v0.8.17/ir-breaking-changes.html#solidity-ir-based-codegen-changes), for extra gas savings.", | |
"severity": "Gas", | |
"title": "Consider activating via-ir for deploying", | |
"instances": [ | |
{ | |
"content": "```solidity\n\nGlobal finding\n```", | |
"loc": [ | |
"[1](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 40, | |
"description": "The expression `type(int).min/(-1)` is the only case where division causes an overflow. Therefore, uncheck can be used to [save gas](https://gist.github.com/DadeKuma/3bc597338ae774b8b3bd43280d55271f) in scenarios where it is certain that such an overflow will not occur.", | |
"severity": "Gas", | |
"title": "Divisions can be `unchecked` to save gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n109: rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice();\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L109)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n78: return totalETHInPool / rsEthSupply;\n```", | |
"loc": [ | |
"[78](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L78)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 339, | |
"description": "\n", | |
"severity": "Gas", | |
"title": "Operator `+=` costs more gas than `<x> = <x> + <y>` for state variables", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n83: assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]);\n\n84: assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset);\n```", | |
"loc": [ | |
"[83](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L83)", | |
"[84](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L84)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n71: totalETHInPool += totalAssetAmt * assetER;\n```", | |
"loc": [ | |
"[71](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L71)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "Saves deployment costs.", | |
"severity": "Gas", | |
"title": "Duplicated `require()`/`revert()` checks should be refactored to a modifier or function to save gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit duplicated on line 159\n119: revert ValueAlreadyInUse();\n```", | |
"loc": [ | |
"[119](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L119)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit duplicated on line 195\n137: revert TokenTransferFailed();\n```", | |
"loc": [ | |
"[137](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L137)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 375, | |
"description": "Emitting an event has an overhead of 375 gas, which will be incurred on every iteration of the loop. It is cheaper to emit only once after the loop has finished.", | |
"severity": "Gas", | |
"title": "Events should be emitted outside of loops", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n171: emit NodeDelegatorAddedinQueue(nodeDelegatorContracts[i]);\n```", | |
"loc": [ | |
"[171](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L171)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 126, | |
"description": "Payable functions cost less gas to execute, because the compiler does not have to add extra checks to ensure that no payment is provided. Initializers can be safely marked as payable, because only the deployer or the factory contract would call the function without carrying any funds.", | |
"severity": "Gas", | |
"title": "Initializers can be marked as payable to save deployment gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n41: function initialize(\n```", | |
"loc": [ | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L41)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n31: function initialize(address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L31)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n29: function initialize(address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[29](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L29)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n26: function initialize(address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[26](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L26)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n32: function initialize(address admin, address lrtConfigAddr) external initializer {\n```", | |
"loc": [ | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L32)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n27: function initialize(address lrtConfig_) external initializer {\n```", | |
"loc": [ | |
"[27](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L27)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 378, | |
"description": "The result of the hash should be stored in an immutable variable, and the variable should be used instead. If the hash is being used as a part of a function selector, the cast to `bytes4` should also only be done once.", | |
"severity": "Gas", | |
"title": "`keccak256()` hash of literals should only be computed once", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n21: bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n22: bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L21)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n7: bytes32 public constant R_ETH_TOKEN = keccak256(\"R_ETH_TOKEN\");\n\n9: bytes32 public constant ST_ETH_TOKEN = keccak256(\"ST_ETH_TOKEN\");\n\n11: bytes32 public constant CB_ETH_TOKEN = keccak256(\"CB_ETH_TOKEN\");\n\n14: bytes32 public constant LRT_ORACLE = keccak256(\"LRT_ORACLE\");\n\n15: bytes32 public constant LRT_DEPOSIT_POOL = keccak256(\"LRT_DEPOSIT_POOL\");\n\n16: bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256(\"EIGEN_STRATEGY_MANAGER\");\n\n19: bytes32 public constant MANAGER = keccak256(\"MANAGER\");\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L7)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L9)", | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L11)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L16)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L19)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 210, | |
"description": "The instances below point to the second+ access of a value inside a mapping/array, within a function. Caching a mapping's value in a local `storage` or `calldata` variable when the value is accessed [multiple times](https://gist.github.com/IllIllI000/ec23a57daa30a8f8ca8b9681c8ccefb0), saves ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations. Caching an array's struct avoids recalculating the array offsets into memory/calldata", | |
"severity": "Gas", | |
"title": "Multiple accesses of the same mapping/array key/index should be cached", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit `isSupportedAsset[asset]` is also accessed on line 82\n85: isSupportedAsset[asset] = true;\n\n/// @audit `assetStrategy[asset]` is also accessed on line 118\n121: assetStrategy[asset] = strategy;\n\n/// @audit `tokenMap[key]` is also accessed on line 158\n161: tokenMap[key] = val;\n\n/// @audit `contractMap[key]` is also accessed on line 174\n177: contractMap[key] = val;\n```", | |
"loc": [ | |
"[85](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L85)", | |
"[121](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L121)", | |
"[161](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L161)", | |
"[177](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L177)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `nodeDelegatorQueue[i]` is also accessed on line 83\n84: assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset);\n```", | |
"loc": [ | |
"[84](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L84)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "The solidity language continues to pursue more efficient gas optimization schemes. Adopting a newer version of solidity can be more gas efficient.", | |
"severity": "Gas", | |
"title": "Newer versions of solidity are more gas efficient", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L2)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 18, | |
"description": "The compiler uses opcodes `GT` and `ISZERO` for code that uses `>`, but only requires `LT` for `>=`. A similar behavior applies for `>`, which uses opcodes `LT` and `ISZERO`, but only requires `GT` for `<=`. It can save 3 gas for each. It should be converted to the `<=`/`>=` equivalent when comparing against integer literals.", | |
"severity": "Gas", | |
"title": "Operator `>=`/`<=` costs less gas than operator `>`/`<`", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n82: for (uint256 i; i < ndcsCount;) {\n\n132: if (depositAmount > getAssetCurrentLimit(asset)) {\n\n164: if (nodeDelegatorQueue.length + length > maxNodeDelegatorCount) {\n\n168: for (uint256 i; i < length;) {\n```", | |
"loc": [ | |
"[82](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L82)", | |
"[132](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L132)", | |
"[164](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L164)", | |
"[168](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L168)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {\n```", | |
"loc": [ | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L66)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n109: for (uint256 i = 0; i < strategiesLength;) {\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L109)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 132, | |
"description": "`public`/`external` function names and `public` member variable names can be optimized to save gas. See this [link](https://gist.github.com/IllIllI000/a5d8b486a8259f9f77891a919febd1a9) for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, [per sorted position shifted](https://medium.com/joyso/solidity-how-does-function-name-affect-gas-consumption-in-smart-contract-47d270d8ac92)", | |
"severity": "Gas", | |
"title": "Optimize names to save gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n/// @audit `initialize`, `addNewSupportedAsset`, `updateAssetDepositLimit`, `updateAssetStrategy`, `getLSTToken`, `getContract`, `getSupportedAssetList`, `setRSETH`, `setToken`, `setContract`\n12: contract LRTConfig is ILRTConfig, AccessControlUpgradeable {\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L12)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `initialize`, `getTotalAssetDeposits`, `getAssetCurrentLimit`, `getNodeDelegatorQueue`, `getAssetDistributionData`, `getRsETHAmountToMint`, `depositAsset`, `addNodeDelegatorContractToQueue`, `transferAssetToNodeDelegator`, `updateMaxNodeDelegatorCount`, `pause`, `unpause`\n19: contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `initialize`, `getAssetPrice`, `getRSETHPrice`, `updatePriceOracleFor`, `pause`, `unpause`\n19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {\n```", | |
"loc": [ | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L19)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n/// @audit `initialize`, `maxApproveToEigenStrategyManager`, `depositAssetIntoStrategy`, `transferBackToLRTDepositPool`, `getAssetBalances`, `getAssetBalance`, `pause`, `unpause`\n18: contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {\n```", | |
"loc": [ | |
"[18](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L18)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n/// @audit `initialize`, `mint`, `burnFrom`, `pause`, `unpause`, `updateLRTConfig`\n14: contract RSETH is\n```", | |
"loc": [ | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L14)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n/// @audit `initialize`, `getAssetPrice`, `updatePriceFeedFor`\n17: contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {\n```", | |
"loc": [ | |
"[17](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L17)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "Getters for public state variables are automatically generated so there is no need to code them manually and waste gas.", | |
"severity": "Gas", | |
"title": "Redundant state variable getters", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n135: function getSupportedAssetList() external view override returns (address[] memory) {\n return supportedAssetList;\n```", | |
"loc": [ | |
"[135](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L135)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n62: function getNodeDelegatorQueue() external view override returns (address[] memory) {\n return nodeDelegatorQueue;\n```", | |
"loc": [ | |
"[62](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L62)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 265, | |
"description": "State variable reads and writes are more expensive than local variable reads and writes. Therefore, it is recommended to replace state variable reads and writes within loops with a local variable. Gas savings should be multiplied by the average loop length.", | |
"severity": "Gas", | |
"title": "State variables access within a loop", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `nodeDelegatorQueue`\n170: nodeDelegatorQueue.push(nodeDelegatorContracts[i]);\n```", | |
"loc": [ | |
"[170](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L170)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 18, | |
"description": "Consider changing the variable to be an unnamed one, since the variable is never assigned, nor is it returned by name. If the optimizer is not turned on, leaving the code as it is will also waste gas for the stack variable.", | |
"severity": "Gas", | |
"title": "Unused named return variables without optimizer waste gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `totalAssetDeposit` not used\n47: function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L47)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n/// @audit `rsETHPrice` not used\n52: function getRSETHPrice() external view returns (uint256 rsETHPrice) {\n```", | |
"loc": [ | |
"[52](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L52)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 1540, | |
"description": "Using interfaces to make external contract calls in Solidity is convenient but can be inefficient in terms of memory utilization. Each such call involves creating a new memory location to store the data being passed, thus incurring memory expansion costs.\n\nInline assembly allows for optimized memory usage by re-using already allocated memory spaces or using the scratch space for smaller datasets. This can result in notable gas savings, especially for contracts that make frequent external calls.\n\nAdditionally, using inline assembly enables important safety checks like verifying if the target address has code deployed to it using `extcodesize(addr)` before making the call, mitigating risks associated with contract interactions.", | |
"severity": "Gas", | |
"title": "Optimize External Calls with Assembly for Memory Efficiency", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `.transferFrom(...)`\n136: if (!IERC20(asset).transferFrom(msg.sender, address(this), depositAmount)) {\n\n/// @audit `.mint(...)`\n156: IRSETH(rsethToken).mint(msg.sender, rsethAmountToMint);\n\n/// @audit `.transfer(...)`\n194: if (!IERC20(asset).transfer(nodeDelegator, amount)) {\n```", | |
"loc": [ | |
"[136](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L136)", | |
"[156](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L156)", | |
"[194](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L194)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n/// @audit `.approve(...)`\n45: IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max);\n\n/// @audit `.depositIntoStrategy(...)`\n67: IEigenStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy(IStrategy(strategy), token, balance);\n\n/// @audit `.transfer(...)`\n86: if (!IERC20(asset).transfer(lrtDepositPool, amount)) {\n\n/// @audit `.getDeposits(...)`\n103: IEigenStrategyManager(eigenlayerStrategyManagerAddress).getDeposits(address(this));\n```", | |
"loc": [ | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L45)", | |
"[67](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L67)", | |
"[86](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L86)", | |
"[103](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L103)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 720, | |
"description": "If the arguments to the encode call can fit into the scratch space (two words or fewer), then it's more efficient to use assembly to generate the hash (80 gas):\n\n`keccak256(abi.encodePacked(x, y)) -> assembly {mstore(0x00, a); mstore(0x20, b); let hash := keccak256(0x00, 0x40); }`", | |
"severity": "Gas", | |
"title": "Use assembly to compute hashes to save gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n21: bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n22: bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L21)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n7: bytes32 public constant R_ETH_TOKEN = keccak256(\"R_ETH_TOKEN\");\n\n9: bytes32 public constant ST_ETH_TOKEN = keccak256(\"ST_ETH_TOKEN\");\n\n11: bytes32 public constant CB_ETH_TOKEN = keccak256(\"CB_ETH_TOKEN\");\n\n14: bytes32 public constant LRT_ORACLE = keccak256(\"LRT_ORACLE\");\n\n15: bytes32 public constant LRT_DEPOSIT_POOL = keccak256(\"LRT_DEPOSIT_POOL\");\n\n16: bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256(\"EIGEN_STRATEGY_MANAGER\");\n\n19: bytes32 public constant MANAGER = keccak256(\"MANAGER\");\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L7)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L9)", | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L11)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L16)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L19)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 646, | |
"description": "To efficiently emit events, it's possible to utilize assembly by making use of scratch space and the free memory pointer. This approach has the advantage of potentially avoiding the costs associated with memory expansion.\n\nHowever, it's important to note that in order to safely optimize this process, it is preferable to cache and restore the free memory pointer.\n\nA good example of such practice can be seen in [Solady's](https://github.com/Vectorized/solady/blob/main/src/tokens/ERC1155.sol#L167) codebase.", | |
"severity": "Gas", | |
"title": "Use assembly to emit events", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n88: emit AddedNewSupportedAsset(asset, depositLimit);\n\n103: emit AssetDepositLimitUpdate(asset, depositLimit);\n\n162: emit SetToken(key, val);\n\n178: emit SetContract(key, val);\n```", | |
"loc": [ | |
"[88](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L88)", | |
"[103](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L103)", | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L162)", | |
"[178](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L178)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n37: emit UpdatedLRTConfig(lrtConfigAddr);\n\n143: emit AssetDeposit(asset, depositAmount, rsethAmountMinted);\n\n171: emit NodeDelegatorAddedinQueue(nodeDelegatorContracts[i]);\n\n204: emit MaxNodeDelegatorCountUpdated(maxNodeDelegatorCount);\n```", | |
"loc": [ | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L37)", | |
"[143](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L143)", | |
"[171](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L171)", | |
"[204](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L204)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n34: emit UpdatedLRTConfig(lrtConfigAddr);\n\n98: emit AssetPriceOracleUpdate(asset, priceOracle);\n```", | |
"loc": [ | |
"[34](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L34)", | |
"[98](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L98)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n32: emit UpdatedLRTConfig(lrtConfigAddr);\n\n65: emit AssetDepositIntoStrategy(asset, strategy, balance);\n```", | |
"loc": [ | |
"[32](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L32)", | |
"[65](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L65)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n41: emit UpdatedLRTConfig(lrtConfigAddr);\n\n76: emit UpdatedLRTConfig(_lrtConfig);\n```", | |
"loc": [ | |
"[41](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L41)", | |
"[76](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L76)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n31: emit UpdatedLRTConfig(lrtConfig_);\n\n48: emit AssetPriceFeedUpdate(asset, priceFeed);\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L31)", | |
"[48](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L48)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n50: emit UpdatedLRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[50](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L50)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 450, | |
"description": "Using `assembly { sstore(state.slot, addr)` instead of `state = addr` can save gas.", | |
"severity": "Gas", | |
"title": "Use assembly to write address/contract type storage values", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n67: rsETH = rsETH_;\n\n146: rsETH = rsETH_;\n```", | |
"loc": [ | |
"[67](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L67)", | |
"[146](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L146)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n36: lrtConfig = ILRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[36](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L36)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n33: lrtConfig = ILRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[33](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L33)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n31: lrtConfig = ILRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[31](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L31)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n40: lrtConfig = ILRTConfig(lrtConfigAddr);\n\n75: lrtConfig = ILRTConfig(_lrtConfig);\n```", | |
"loc": [ | |
"[40](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L40)", | |
"[75](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L75)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n30: lrtConfig = ILRTConfig(lrtConfig_);\n```", | |
"loc": [ | |
"[30](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L30)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n49: lrtConfig = ILRTConfig(lrtConfigAddr);\n```", | |
"loc": [ | |
"[49](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L49)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 97, | |
"description": "Use the function/modifier's local copy of the state variable, rather than incurring an extra Gwarmaccess (100 gas). In the unlikely event that the state variable hasn't already been used by the function/modifier, consider whether it is really necessary to include it in the event, given the fact that it incurs a Gcoldsload (2100 gas), or whether it can be passed in to or back out of the functions that do use it", | |
"severity": "Gas", | |
"title": "Use local variables for emitting", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n/// @audit `maxNodeDelegatorCount`\n204: emit MaxNodeDelegatorCountUpdated(maxNodeDelegatorCount);\n```", | |
"loc": [ | |
"[204](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L204)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "- Use a solidity version of at least 0.8.2 to get simple compiler automatic inlining.\n- Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads.\n- Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings.\n- Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value.", | |
"severity": "Gas", | |
"title": "Use a more recent version of solidity", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L2)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n2: pragma solidity 0.8.21;\n```", | |
"loc": [ | |
"[2](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L2)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 8550, | |
"description": "Avoids a Gsset (20000 gas) when changing from false to true, after having been true in the past. Since most of the bools aren't changed twice in one transaction, I've counted the amount of gas as half of the full amount, for each variable.", | |
"severity": "Gas", | |
"title": "Use `uint256(1)`/`uint256(2)` instead of `true`/`false` to save gas for changes", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n15: mapping(address token => bool isSupported) public isSupportedAsset;\n```", | |
"loc": [ | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L15)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "Using a bitmap instead of a bool array or a bool mapping to store boolean states can save gas fees. This is because the bitmap can store 256 boolean values in a single slot instead of 256 slots, which can save gas when writing bool values or when reading multiple bool values from the same slot.", | |
"severity": "Gas", | |
"title": "Using bitmap to store bool states can save gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n15: mapping(address token => bool isSupported) public isSupportedAsset;\n```", | |
"loc": [ | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L15)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 100, | |
"description": "Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See [source](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27).", | |
"severity": "Gas", | |
"title": "Using bools for storage incurs overhead", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n15: mapping(address token => bool isSupported) public isSupportedAsset;\n```", | |
"loc": [ | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L15)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "\n", | |
"severity": "Gas", | |
"title": "Don't initialize variables with default value", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n109: for (uint256 i = 0; i < strategiesLength;) {\n```", | |
"loc": [ | |
"[109](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L109)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 55, | |
"description": "Using `int`s/`uint`s smaller than 32 bytes may cost more gas. This is because the EVM operates on 32 bytes at a time, so if an element is smaller than 32 bytes, the EVM must perform more operations to reduce the size of the element from 32 bytes to the desired size.", | |
"severity": "Gas", | |
"title": "Usage of `int`s/`uint`s smaller than 32 bytes incurs overhead", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {\n```", | |
"loc": [ | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L66)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 126, | |
"description": "Payable functions cost less gas to execute, because the compiler does not have to add extra checks to ensure that no payment is provided. A constructor can be safely marked as payable, because only the deployer would be able to pass funds, and the project itself would not pass any funds.", | |
"severity": "Gas", | |
"title": "Constructors can be marked as `payable` to save deployment gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n24: constructor() {\n```", | |
"loc": [ | |
"[24](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L24)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n25: constructor() {\n```", | |
"loc": [ | |
"[25](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L25)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n23: constructor() {\n```", | |
"loc": [ | |
"[23](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L23)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n20: constructor() {\n```", | |
"loc": [ | |
"[20](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L20)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n25: constructor() {\n```", | |
"loc": [ | |
"[25](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L25)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n21: constructor() {\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L21)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"gasSavings": 441, | |
"description": "If a function modifier such as `onlyOwner` is used, the function will revert if a normal user tries to pay the function. Marking the function as `payable` will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.", | |
"severity": "Gas", | |
"title": "Functions guaranteed to revert when called by normal users can be marked `payable`", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTConfig.sol\n\n73: function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {\n\n144: function setRSETH(address rsETH_) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n149: function setToken(bytes32 tokenKey, address assetAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n165: function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L73)", | |
"[144](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L144)", | |
"[149](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L149)", | |
"[165](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTConfig.sol#L165)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n162: function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin {\n\n202: function updateMaxNodeDelegatorCount(uint256 maxNodeDelegatorCount_) external onlyLRTAdmin {\n\n208: function pause() external onlyLRTManager {\n\n213: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[162](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L162)", | |
"[202](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L202)", | |
"[208](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L208)", | |
"[213](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L213)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n45: function getAssetPrice(address asset) public view onlySupportedAsset(asset) returns (uint256) {\n\n102: function pause() external onlyLRTManager {\n\n107: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L45)", | |
"[102](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L102)", | |
"[107](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L107)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/NodeDelegator.sol\n\n127: function pause() external onlyLRTManager {\n\n132: function unpause() external onlyLRTAdmin {\n```", | |
"loc": [ | |
"[127](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L127)", | |
"[132](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/NodeDelegator.sol#L132)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n47: function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {\n\n54: function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {\n\n60: function pause() external onlyLRTManager {\n\n66: function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {\n\n73: function updateLRTConfig(address _lrtConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L47)", | |
"[54](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L54)", | |
"[60](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L60)", | |
"[66](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L66)", | |
"[73](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L73)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/oracles/ChainlinkPriceOracle.sol\n\n37: function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {\n\n45: function updatePriceFeedFor(address asset, address priceFeed) external onlyLRTManager onlySupportedAsset(asset) {\n```", | |
"loc": [ | |
"[37](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L37)", | |
"[45](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L45)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConfigRoleChecker.sol\n\n47: function updateLRTConfig(address lrtConfigAddr) external virtual onlyLRTAdmin {\n```", | |
"loc": [ | |
"[47](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConfigRoleChecker.sol#L47)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that [returns a tuple](https://github.com/code-423n4/2022-08-frax/blob/90f55a9ce4e25bceed3a74290b854341d8de6afa/src/contracts/FraxlendPair.sol#L156-L178) of the values of all currently-public constants. Saves **3406-3606 gas** in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table", | |
"severity": "Gas", | |
"title": "Using `private` rather than `public` for constants, saves gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/RSETH.sol\n\n21: bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n22: bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n```", | |
"loc": [ | |
"[21](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L21)", | |
"[22](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/RSETH.sol#L22)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/LRTConstants.sol\n\n7: bytes32 public constant R_ETH_TOKEN = keccak256(\"R_ETH_TOKEN\");\n\n9: bytes32 public constant ST_ETH_TOKEN = keccak256(\"ST_ETH_TOKEN\");\n\n11: bytes32 public constant CB_ETH_TOKEN = keccak256(\"CB_ETH_TOKEN\");\n\n14: bytes32 public constant LRT_ORACLE = keccak256(\"LRT_ORACLE\");\n\n15: bytes32 public constant LRT_DEPOSIT_POOL = keccak256(\"LRT_DEPOSIT_POOL\");\n\n16: bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256(\"EIGEN_STRATEGY_MANAGER\");\n\n19: bytes32 public constant MANAGER = keccak256(\"MANAGER\");\n```", | |
"loc": [ | |
"[7](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L7)", | |
"[9](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L9)", | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L11)", | |
"[14](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L14)", | |
"[15](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L15)", | |
"[16](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L16)", | |
"[19](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/LRTConstants.sol#L19)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
}, | |
{ | |
"gasSavings": 18, | |
"description": "Using assembly to check for zero can save gas by allowing more direct access to the evm and reducing some of the overhead associated with high-level operations in solidity.", | |
"severity": "Gas", | |
"title": "Using assembly to check for zero can save gas", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/LRTDepositPool.sol\n\n129: if (depositAmount == 0) {\n```", | |
"loc": [ | |
"[129](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTDepositPool.sol#L129)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/LRTOracle.sol\n\n56: if (rsEthSupply == 0) {\n```", | |
"loc": [ | |
"[56](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/LRTOracle.sol#L56)" | |
] | |
}, | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n12: if (address_ == address(0)) revert ZeroAddressNotAllowed();\n```", | |
"loc": [ | |
"[12](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L12)" | |
] | |
} | |
], | |
"category": null | |
}, | |
{ | |
"description": "If the functions are required by an interface, the contract should inherit from that interface and use the `override` keyword", | |
"severity": "Gas", | |
"title": "`internal` functions not called by the contract should be removed", | |
"instances": [ | |
{ | |
"content": "```solidity\nFile: src/utils/UtilLib.sol\n\n11: function checkNonZeroAddress(address address_) internal pure {\n```", | |
"loc": [ | |
"[11](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/utils/UtilLib.sol#L11)" | |
] | |
} | |
], | |
"category": null, | |
"gasSavings": null | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment