Platform: Code4rena
Start Date: 11/11/2022
Pot Size: $90,500 USDC
Total HM: 52
Participants: 92
Period: 7 days
Judge: LSDan
Total Solo HM: 20
Id: 182
League: ETH
Rank: 47/92
Findings: 2
Award: $120.17
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xSmartContract
Also found by: 0x4non, 0xNazgul, 0xRoxas, 0xdeadbeef0x, 0xmuxyz, 9svR6w, Awesome, Aymen0909, B2, Bnke0x0, CloudX, Deivitto, Diana, Franfran, IllIllI, Josiah, RaymondFam, ReyAdmirado, Rolezn, Sathish9098, Secureverse, SmartSek, Trust, Udsen, a12jmx, aphak5010, brgltd, bulej93, c3phas, ch0bu, chaduke, chrisdior4, clems4ever, cryptostellar5, datapunk, delfin454000, fs0c, gogo, gz627, hl_, immeas, joestakey, lukris02, martin, nogo, oyc_109, pashov, pavankv, peanuts, pedr02b2, rbserver, rotcivegaf, sahar, sakman, shark, tnevler, trustindistrust, zaskoh, zgo
52.0338 USDC - $52.03
Context:
pool = _pool;
L25transferHookProcessor = ITransferHookProcessor(_transferHookProcessor);
L26 (_transferHookProcessor)Recommendation:
Add non-zero address checks when set address state variables.
require(owner != address(0), 'Wallet cannot be address 0');
L37
Double quotes are used in all contracts except here.
Context:
uint256 public MODULO = 100_00000;
L158 (variable name must be mixedCase)mapping(LPToken => bytes) public KnotAssociatedWithLPToken;
L47 (variable name must be in mixedCase)Context:
Recommendation:
Choose named return variable or return statement. It is unnecessary to use both.
Context:
Description:
According to official solidity documentation functions should be grouped according to their visibility and ordered:
constructor
receive function (if exists)
fallback function (if exists)
external
public
internal
private
Within a grouping, place the view and pure functions last.
Recommendation:
Put the functions in the correct order according to the documentation.
Context:
Description:
Public functions can be declared external if they are not called by the contract.
Recommendation:
Declare these functions as external instead of public.
Context:
function createWallet() external returns (address wallet) {
L28function createWallet(address owner) external returns (address wallet) {
L32function _createWallet(address owner) internal returns (address wallet) {
L36function mint(address _recipient, uint256 _amount) external {
L29function burn(address _recipient, uint256 _amount) external {
L34function _beforeTokenTransfer(address _from, address _to, uint256 _amount) internal override {
L39function _afterTokenTransfer(address _from, address _to, uint256 _amount) internal override {
L43function init(address _liquidStakingManagerAddress, LPTokenFactory _lpTokenFactory) external virtual initializer {
L45function _updateCollateralizedSlotOwnersLiabilitySnapshot(bytes memory _blsPubKey) internal {
L491function _calculateCollateralizedETHOwedPerKnot() internal view returns (uint256) {
L538function _initStakingFundsVault(address _stakingFundsVaultDeployer, address _tokenFactory) internal virtual {
L911Context:
require(numOfTokens == _amounts.length, "Inconsisent array length");
L115 (Change Inconsisent to Inconsistent)/// @notice Utility function that determins whether an LP can be burned for dETH if the associated derivatives have been minted
L227 (Change determins to determines)// register validtor initals for each of the KNOTs
L476 (Change validtor to validator)// register validtor initals for each of the KNOTs
L476 (Change initals to initials)/// @param _newLPToken Instane of the new LP token (to be minted)
L74 (Change Instane to Instance)// mint LP tokens for the depoistor with 1:1 ratio of LP tokens and ETH supplied
L124 (Change depoistor to depositor)// mint LP tokens for the depoistor with 1:1 ratio of LP tokens and ETH supplied
L150 (Change depoistor to depositor)Context:
// todo - check else case for any ETH lost
L195
Context:
if (address(transferHookProcessor) != address(0)) ITransferHookProcessor(transferHookProcessor).beforeTokenTransfer(_from, _to, _amount);
L40if (address(transferHookProcessor) != address(0)) ITransferHookProcessor(transferHookProcessor).afterTokenTransfer(_from, _to, _amount);
L46import { ERC20PermitUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";
L6if (address(transferHookProcessor) != address(0)) transferHookProcessor.beforeTokenTransfer(_from, _to, _amount);
L62function batchDepositETHForStaking(bytes[] calldata _blsPublicKeyOfKnots, uint256[] calldata _amounts) external payable {
L57require(liquidStakingManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnots[i]) == false, "BLS public key is not part of LSD network");
L64getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKeyOfKnots[i]) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L66function depositETHForStaking(bytes calldata _blsPublicKeyOfKnot, uint256 _amount) public payable returns (uint256) {
L83require(liquidStakingManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnot) == false, "BLS public key is banned or not a part of LSD network");
L84getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKeyOfKnot) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L86IDataStructures.LifecycleStatus validatorStatus = getAccountManager().blsPublicKeyToLifecycleStatus(blsPublicKeyOfKnot);
L132uint256 dETHBalance = getSavETHRegistry().knotDETHBalanceInIndex(indexOwnedByTheVault, blsPublicKeyOfKnot);
L158getSavETHRegistry().addKnotToOpenIndex(liquidStakingManager.stakehouse(), blsPublicKeyOfKnot, address(this));
L165IDataStructures.LifecycleStatus validatorStatus = getAccountManager().blsPublicKeyToLifecycleStatus(blsPublicKeyOfKnot);
L230/// @notice Stake ETH against multiple BLS keys within multiple LSDNs and specify the amount of ETH being supplied for each key
L22return _previewAccumulatedETH(_user, address(lpTokenETH), lpTokenETH.balanceOf(_user), lpTokenETH.totalSupply(), accumulated);
L97function batchDepositETHForStaking(bytes[] calldata _blsPublicKeyOfKnots, uint256[] calldata _amounts) external payable {
L69require(liquidStakingNetworkManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnots[i]) == false, "BLS public key is not part of LSD network");
L79getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKeyOfKnots[i]) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L81claimed[msg.sender][address(tokenForKnot)] = (tokenForKnot.balanceOf(msg.sender) * accumulatedETHPerLPShare) / PRECISION;
L103function depositETHForStaking(bytes calldata _blsPublicKeyOfKnot, uint256 _amount) public payable returns (uint256) {
L113require(liquidStakingNetworkManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnot) == false, "BLS public key is banned or not a part of LSD network");
L114getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKeyOfKnot) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L116claimed[msg.sender][address(tokenForKnot)] = (tokenForKnot.balanceOf(msg.sender) * accumulatedETHPerLPShare) / PRECISION;
L140getAccountManager().blsPublicKeyToLifecycleStatus(blsPublicKeyOfKnot) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L181/// @notice Any LP tokens for BLS keys that have had their derivatives minted can claim ETH from the syndicate contract
L197getAccountManager().blsPublicKeyToLifecycleStatus(_blsPubKeys[i]) == IDataStructures.LifecycleStatus.TOKENS_MINTED,
L211if (i == 0 && !Syndicate(payable(liquidStakingNetworkManager.syndicate())).isNoLongerPartOfSyndicate(_blsPubKeys[i])) {
L215// If a partial list of BLS keys that have free floating staked are supplied, then partial funds accrued will be fetched
L217require(token.lastInteractedTimestamp(msg.sender) + 30 minutes < block.timestamp, "Last transfer too recent");
L230/// @param _blsPublicKeys List of BLS public keys being processed (assuming DAO only has BLS pub keys from correct smart wallet)
L253/// @notice Preview total ETH accumulated by a staking funds LP token holder associated with many KNOTs that have minted derivatives
L273function batchPreviewAccumulatedETHByBLSKeys(address _user, bytes[] calldata _blsPubKeys) external view returns (uint256) {
L274/// @notice Preview total ETH accumulated by a staking funds LP token holder associated with many KNOTs that have minted derivatives
L283/// @notice Preview total ETH accumulated by a staking funds LP token holder associated with a KNOT that has minted derivatives
L292if (getAccountManager().blsPublicKeyToLifecycleStatus(associatedBLSPublicKeyOfLpToken) != IDataStructures.LifecycleStatus.TOKENS_MINTED) {
L296// Looking at this contract balance and the ETH that is yet to be transferred from the syndicate, then tell the user how much ETH they have earned
L300if (getAccountManager().blsPublicKeyToLifecycleStatus(blsPubKey) == IDataStructures.LifecycleStatus.TOKENS_MINTED) {
L322// in case the new user has existing rewards - give it to them so that the after transfer hook does not wipe pending rewards
L336/// @param _blsPubKeys List of BLS public key identifiers of validators that have sETH staked in the syndicate for the vault
L354/// @dev This contract can be extended to allow lending and borrowing of time slots for borrower to redeem any revenue generated within the specified window
L35event ETHClaimed(bytes BLSPubKey, address indexed user, address recipient, uint256 claim, bool indexed isCollateralizedClaim);
L63/// @notice Total accrued ETH for all collateralized SLOT holders per knot which is then distributed based on individual balances
L71/// @notice Block number after which if there are sETH staking slots available, it can be supplied by anyone on the market
L92/// @notice Syndicate deployer can highlight addresses that get priority for staking free floating house sETH up to a certain block before anyone can do it
L95/// @notice Whether a BLS public key, that has been previously registered, is no longer part of the syndicate and its shares (free floating or SLOT) cannot earn any more rewards
L116/// @notice Once a BLS public key is no longer part of the syndicate, the accumulated ETH per free floating SLOT share is snapshotted so historical earnings can be drawn down correctly
L119/// @param _priorityStakers Optional list of addresses that will have priority for staking sETH against each knot registered
L127/// @param _blsPubKeysForSyndicateKnots List of BLS public keys of Stakehouse protocol registered KNOTs participating in syndicate
L128/// @notice Make knot shares of a registered list of BLS public keys inactive - the action cannot be undone and no further ETH accrued
L153/// @notice Should this block be in the future, it means only those listed in the priority staker list can stake sETH
L166/// @notice Update accrued ETH per SLOT share without distributing ETH as users of the syndicate individually pull funds
L173// Ensure there are registered KNOTs. Syndicates are deployed with at least 1 registered but this can fall to zero.
L175accumulatedETHPerFreeFloatingShare += _calculateNewAccumulatedETHPerFreeFloatingShare(freeFloatingUnprocessed);
L185uint256 collateralizedUnprocessed = ((totalEthPerSlotType - lastSeenETHPerCollateralizedSlotPerKnot) / numberOfRegisteredKnots);
L189/// @param _sETHAmounts Per BLS public key, the total amount of sETH that will be staked (up to 4 collateralized SLOT per KNOT)
L201/// @param _onBehalfOf Allows a caller to specify an address that will be assigned stake ownership and rights to claim
L202if (!isKnotRegistered[_blsPubKey] || isNoLongerPartOfSyndicate[_blsPubKey]) revert KnotIsNotRegisteredWithSyndicate();
L216sETHUserClaimForKnot[_blsPubKey][_onBehalfOf] = (_sETHAmount * accumulatedETHPerFreeFloatingShare) / PRECISION;
L228// This is designed to cope with falling SLOT balances i.e. when collateralized SLOT is burnt after applying penalties
L311/// @notice For any new ETH received by the syndicate, at the knot level allocate ETH owed to each collateralized owner
L335/// @notice For any new ETH received by the syndicate, at the knot level allocate ETH owed to each collateralized owner and do it for a batch of knots
L341/// @notice Calculate the amount of unclaimed ETH for a given BLS publice key + free floating SLOT staker without factoring in unprocessed rewards
L356function calculateUnclaimedFreeFloatingETHShare(bytes memory _blsPubKey, address _user) public view returns (uint256) {
L359/// @notice Using `highestSeenBalance`, this is the amount that is separately allocated to either free floating or collateralized SLOT holders
L372/// @notice Preview the amount of unclaimed ETH available for an sETH staker against a KNOT which factors in unprocessed rewards from new ETH sent to contract
L381currentAccumulatedETHPerFreeFloatingShare + calculateNewAccumulatedETHPerFreeFloatingShare();
L390/// @notice Preview the amount of unclaimed ETH available for a collatearlized SLOT staker against a KNOT which factors in unprocessed rewards from new ETH sent to contract
L398+ ((calculateETHForFreeFloatingOrCollateralizedHolders() - lastSeenETHPerCollateralizedSlotPerKnot) / numberOfRegisteredKnots);
L407uint256 numberOfCollateralisedSlotOwnersForKnot = getSlotRegistry().numberOfCollateralisedSlotOwnersForKnot(_blsPubKey);
L416return ((calculateETHForFreeFloatingOrCollateralizedHolders() - lastSeenETHPerCollateralizedSlotPerKnot) / numberOfRegisteredKnots);
L447/// Given an amount of ETH allocated to the collateralized SLOT owners of a KNOT, distribute this amongs the current set of collateralized owners (a dynamic set of addresses and balances)
L490// Don't allocate ETH when the current slashed amount is four. Syndicate will wait until ETH is topped up to claim revenue
L503// This copes with increasing numbers of collateralized slot owners and also copes with SLOT that has been slashed but not topped up
L505uint256 numberOfCollateralisedSlotOwnersForKnot = getSlotRegistry().numberOfCollateralisedSlotOwnersForKnot(_blsPubKey);
L506accruedEarningPerCollateralizedSlotOwnerOfKnot[_blsPubKey][collateralizedOwnerAtIndex] += unprocessedETHForCurrentKnot;
L511// if the knot is no longer active, no further accrual of rewards are possible snapshots are possible but ETH accrued up to that point
L531/// @dev Business logic for de-registering a set of knots from the syndicate and doing the required snapshots to ensure historical earnings are preserved
L596event ETHWithdrawnFromSmartWallet(address indexed associatedSmartWallet, bytes blsPublicKeyOfKnot, address nodeRunner);
L66/// @notice In preparation of a rage quit, restore sETH to a smart wallet which are recoverable with the execution methods in the event this step does not go to plan
L222/// @param _blsPublicKeys List of BLS public keys being processed (assuming DAO only has BLS pub keys from correct smart wallet)
L224require(isNodeRunnerWhitelisted[_nodeRunner] != isNodeRunnerWhitelisted[_nodeRunner], "Unnecessary update to same status");
L280/// @notice Allow node runners to withdraw ETH from their smart wallet. ETH can only be withdrawn until the KNOT has not been staked.
L323require(isBLSPublicKeyBanned(_blsPublicKeyOfKnot) == false, "BLS public key has already withdrawn or not a part of LSD network");
L328require(smartWalletOfNodeRunner[msg.sender] == associatedSmartWallet, "Not the node runner for the smart wallet ");
L331require(isNodeRunnerBanned(nodeRunnerOfSmartWallet[associatedSmartWallet]) == false, "Node runner is banned from LSD network");
L332getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKeyOfKnot) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L335function rotateNodeRunnerOfSmartWallet(address _current, address _new, bool _wasPreviousNodeRunnerMalicious) external {
L356require(isBLSPublicKeyBanned(_blsPubKeys[i]) == false, "BLS public key is banned or not a part of LSD network");
L393require(smartWalletOfKnot[_blsPubKeys[i]] == smartWallet, "BLS public key doesn't belong to the node runner");
L396// Ensure that the node runner does not whitelist multiple EOA representatives - they can only have 1 active at a time
L453require(smartWalletRepresentative[smartWallet] == _eoaRepresentative, "Different EOA specified - rotate outside");
L455require(isBLSPublicKeyPartOfLSDNetwork(_blsPublicKey) == false, "BLS public key is banned or not a part of LSD network");
L469getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKey) == IDataStructures.LifecycleStatus.UNBEGUN,
L472return !isBLSPublicKeyPartOfLSDNetwork(_blsPublicKeyOfKnot) || bannedBLSPublicKeys[_blsPublicKeyOfKnot] != address(0);
L501getAccountManager().blsPublicKeyToLifecycleStatus(blsPubKey) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L546/// @notice Anyone can call this to trigger creating a knot which will mint derivatives once the balance has been reported
L573/// @param _blsPublicKeyOfKnots List of BLS public keys registered with the network becoming knots and minting derivatives
L574require(isBLSPublicKeyBanned(_blsPublicKeyOfKnots[i]) == false, "BLS public key is banned or not a part of LSD network");
L589getAccountManager().blsPublicKeyToLifecycleStatus(_blsPublicKeyOfKnots[i]) == IDataStructures.LifecycleStatus.DEPOSIT_COMPLETED,
L593require(_oldLPToken.lastInteractedTimestamp(msg.sender) + 30 minutes < block.timestamp, "Liquidity is still fresh");
L82getAccountManager().blsPublicKeyToLifecycleStatus(blsPublicKeyOfPreviousKnot) == IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L92getAccountManager().blsPublicKeyToLifecycleStatus(blsPublicKeyOfNewKnot) ==IDataStructures.LifecycleStatus.INITIALS_REGISTERED,
L97function _depositETHForStaking(bytes calldata _blsPublicKeyOfKnot, uint256 _amount, bool _enableTransferHook) internal {
L110require(lpToken.totalSupply() + _amount <= maxStakingAmountPerValidator, "Amount exceeds the staking limit for the validator");
L122LPToken(lpTokenFactory.deployLPToken(address(this), address(this), tokenSymbol, tokenName)) :
L140Description:
Maximum suggested line length is 120 characters.
#0 - c4-judge
2022-12-02T21:45:17Z
dmvt marked the issue as grade-b
🌟 Selected for report: IllIllI
Also found by: 0xSmartContract, Awesome, Aymen0909, CloudX, Deivitto, ReyAdmirado, Saintcode_, bharg4v, brgltd, btk, c3phas, chrisdior4, ignacio, imare, lukris02, skyle, tnevler
68.1383 USDC - $68.14
Context:
for (uint256 i; i < amountOfTokens; ++i) {
L76for (uint256 i; i < numOfSavETHVaults; ++i) {
L42for (uint256 i; i < numOfVaults; ++i) {
L78for (uint256 j; j < _lpTokens[i].length; ++j) {
L82for (uint256 i; i < numOfRotations; ++i) {
L128for (uint256 i; i < numOfVaults; ++i) {
L146for (uint256 j; j < _lpTokens[i].length; ++j) {
L148for (uint256 i; i < numOfValidators; ++i) {
L63for (uint256 i; i < numOfTokens; ++i) {
L103for (uint256 i; i < numOfTokens; ++i) {
L116for (uint256 i; i < numOfVaults; ++i) {
L38for (uint256 i; i < numOfVaults; ++i) {
L64for (uint256 i; i < _stakingFundsVaults.length; ++i) {
L90for (uint256 i; i < numOfRotations; ++i) {
L117for (uint256 i; i < numOfVaults; ++i) {
L135for (uint256 i; i < _lpTokens.length; ++i) {
L183for (uint256 i; i < numOfValidators; ++i) {
L78for (uint256 i; i < numOfTokens; ++i) {
L152for (uint256 i; i < numOfTokens; ++i) {
L166for (uint256 i; i < _blsPubKeys.length; ++i) {
L203for (uint256 i; i < _blsPublicKeys.length; ++i) {
L266for (uint256 i; i < _blsPubKeys.length; ++i) {
L276for (uint256 i; i < _token.length; ++i) {
L286for (uint256 i; i < _blsPubKeys.length; ++i) {
L211for (uint256 i; i < _blsPubKeys.length; ++i) {
L259for (uint256 i; i < _blsPubKeys.length; ++i) {
L301for (uint256 i; i < _blsPubKeys.length; ++i) {
L346for (uint256 i; i < numberOfCollateralisedSlotOwnersForKnot; ++i) {
L420for (uint256 i; i < numberOfCollateralisedSlotOwnersForKnot; ++i) {
L513for (uint256 i; i < knotsToRegister; ++i) {
L560for (uint256 i; i < _priorityStakers.length; ++i) {
L585for (uint256 i; i < _blsPublicKeys.length; ++i) {
L598for (uint256 i; i < _blsPubKeys.length; ++i) {
L648for(uint256 i; i < _blsPubKeys.length; ++i) {
L392for(uint256 i; i < len; ++i) {
L465for (uint256 i; i < numOfValidators; ++i) {
L538for (uint256 i; i < numOfKnotsToProcess; ++i) {
L587for (uint256 i; i < numOfRotations; ++i) {
L63Description:
This can save 30-40 gas per loop iteration.
Recommendation:
Example how to fix. Change:
for (uint256 i = 0; i < orders.length; ++i) { // Do the thing }
To:
for (uint256 i = 0; i < orders.length;) { // Do the thing unchecked { ++i; } }
Context:
idleETH -= _amount;
L57
Description:
Some gas can be saved by using an unchecked {} block if an underflow isn't possible because of a previous require() or if-statement.
Context:
function _assertUserHasEnoughGiantLPToClaimVaultLP(LPToken _token, uint256 _amount) internal view {
L93
Description:
If they are not inlined, they cost an additional 20 to 40 gas because of 2 extra jump instructions and additional stack operations needed for function calls.
Context:
if (unprocessedETHForCurrentKnot > 0 && !isNoLongerPartOfSyndicate[_blsPubKey]) { ... } // if the knot is no longer active, no further accrual of rewards are possible snapshots are possible but ETH accrued up to that point // Basically, under a rage quit or voluntary withdrawal from the beacon chain, the knot kick is auto-propagated to syndicate if (!isActive && !isNoLongerPartOfSyndicate[_blsPubKey]) { _deRegisterKnot(_blsPubKey); }
require(smartWalletRepresentative[smartWallet] != _newRepresentative, "Invalid rotation to same EOA"); // unauthorize old representative _authorizeRepresentative(smartWallet, smartWalletRepresentative[smartWallet], false);
require(smartWalletRepresentative[smartWallet] != _newRepresentative, "Invalid rotation to same EOA"); // unauthorize old representative _authorizeRepresentative(smartWallet, smartWalletRepresentative[smartWallet], false);
if(smartWalletRepresentative[smartWallet] != address(0)) { require(smartWalletRepresentative[smartWallet] == _eoaRepresentative, "Different EOA specified - rotate outside");
Description:
If you read value from mapping/array more than once within a function then it is cheaper to cache it in local memory and then read it from memory wnen it is neaded. This will save about 40 gas.
Recommendation:
Example how to fix. Change:
require(smartWalletRepresentative[smartWallet] != _newRepresentative, "Invalid rotation to same EOA"); // unauthorize old representative _authorizeRepresentative(smartWallet, smartWalletRepresentative[smartWallet], false);
to:
address _oldRepresentative = smartWalletRepresentative[smartWallet]; require(_oldRepresentative != _newRepresentative, "Invalid rotation to same EOA"); // unauthorize old representative _authorizeRepresentative(smartWallet, _oldRepresentative, false);
Context:
if (numberOfRegisteredKnots > 0) { ... } uint256 collateralizedUnprocessed = ((totalEthPerSlotType - lastSeenETHPerCollateralizedSlotPerKnot) / numberOfRegisteredKnots);
require(_newAddress != dao, "Same address"); emit UpdateDAOAddress(dao, _newAddress);
require(_current == msg.sender || dao == msg.sender, "Not current owner or DAO"); ... if (msg.sender == dao && _wasPreviousNodeRunnerMalicious) {
Description:
Every reading from storage costs about 100 gas while every reading from memory costs only 3 gas. If state variable referred more than once within a function then it is cheaper to cache it in local memory (100 gas) and then read it from memory wnen it is neaded (3 gas) rather than read state variable from storage everytime (100 gas).
Recommendation:
Example how to fix. Change:
require(_current == msg.sender || dao == msg.sender, "Not current owner or DAO"); ... if (msg.sender == dao && _wasPreviousNodeRunnerMalicious) {
to:
address _dao = dao; require(_current == msg.sender || _dao == msg.sender, "Not current owner or DAO"); ... if (msg.sender == _dao && _wasPreviousNodeRunnerMalicious) {
Context:
function execute(address target, bytes memory callData)
L41bytes memory callData,
L54bytes memory callData,
L69function claimFundsFromSyndicateForDistribution(bytes[] memory _blsPubKeys) external {
L355function _claimFundsFromSyndicateForDistribution(address _syndicate, bytes[] memory _blsPubKeys) internal {
L360function updateCollateralizedSlotOwnersAccruedETH(bytes memory _blsPubKey) external {
L337function batchUpdateCollateralizedSlotOwnersAccruedETH(bytes[] memory _blsPubKeys) external {
L343function calculateUnclaimedFreeFloatingETHShare(bytes memory _blsPubKey, address _user) public view returns (uint256) {
L359address[] memory _priorityStakers,
L472bytes[] memory _blsPubKeysForSyndicateKnots
L473function _updateCollateralizedSlotOwnersLiabilitySnapshot(bytes memory _blsPubKey) internal {
L491function _registerKnotsToSyndicate(bytes[] memory _blsPubKeysForSyndicateKnots) internal {
L555function _addPriorityStakers(address[] memory _priorityStakers) internal {
L583function _deRegisterKnot(bytes memory _blsPublicKey) internal {
L610function _autoStakeWithSyndicate(address _associatedSmartWallet, bytes memory _blsPubKey) internal {
L879Description:
If a reference type function parameter is read-only, it is recommended to use calldata instead of memory because this provides significant gas savings. Since Solidity v0.6.9, memory and calldata are allowed in all functions regardless of their visibility type (ie external, public, etc).
Context:
vault.isDETHReadyForWithdrawal(address(_lpTokens[i][j])) == false,
L150require(liquidStakingManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnots[i]) == false, "BLS public key is not part of LSD network");
L64require(liquidStakingManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnot) == false, "BLS public key is banned or not a part of LSD network");
L84require(liquidStakingNetworkManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnots[i]) == false, "BLS public key is not part of LSD network");
L79require(liquidStakingNetworkManager.isBLSPublicKeyBanned(_blsPublicKeyOfKnot) == false, "BLS public key is banned or not a part of LSD network");
L114liquidStakingNetworkManager.isBLSPublicKeyBanned(_blsPubKeys[i]) == false,
L205if (isKnotRegistered[_blsPublicKey] == false) revert KnotIsNotRegisteredWithSyndicate();
L611if (isNoLongerPartOfSyndicate[_blsPublicKey] == true) revert KnotHasAlreadyBeenDeRegistered();
L612require(isNodeRunnerBanned(msg.sender) == false, "Node runner is banned from LSD network");
L291require(isBLSPublicKeyBanned(_blsPublicKeyOfKnot) == false, "BLS public key has already withdrawn or not a part of LSD network");
L328require(isNodeRunnerBanned(nodeRunnerOfSmartWallet[associatedSmartWallet]) == false, "Node runner is banned from LSD network");
L332require(isBLSPublicKeyBanned(_blsPubKeys[i]) == false, "BLS public key is banned or not a part of LSD network");
L393require(_isNodeRunnerValid(msg.sender) == true, "Unrecognised node runner");
L436require(isNodeRunnerBanned(msg.sender) == false, "Node runner is banned from LSD network");
L437require(isBLSPublicKeyPartOfLSDNetwork(_blsPublicKey) == false, "BLS public key is banned or not a part of LSD network");
L469require(isBLSPublicKeyBanned(blsPubKey) == false, "BLS public key is banned or not a part of LSD network");
L541require(isBLSPublicKeyBanned(_blsPublicKeyOfKnots[i]) == false, "BLS public key is banned or not a part of LSD network");
L589require(isNodeRunnerWhitelisted[_nodeRunner] == true, "Invalid node runner");
L688#0 - c4-judge
2022-12-02T19:50:05Z
dmvt marked the issue as grade-b