Platform: Code4rena
Start Date: 02/06/2023
Pot Size: $100,000 USDC
Total HM: 15
Participants: 75
Period: 7 days
Judge: Picodes
Total Solo HM: 5
Id: 249
League: ETH
Rank: 57/75
Findings: 1
Award: $21.62
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JCN
Also found by: 0x70C9, 0xSmartContract, 0xWaitress, 0xhacksmithh, DavidGiladi, K42, LaScaloneta, Rageur, Raihan, SAAJ, SAQ, SM3_SS, Sathish9098, Tomio, bigtone, c3phas, ernestognw, etherhood, koxuan, matrix_0wl, mgf15, naman1778, niser93, petrichor, piyushshukla, sebghatullah, shamsulhaq123
21.6219 USDC - $21.62
Issue | Instance | |
---|---|---|
[G-01] | Make The Variable Outside The Loop To Save Gas | 12 |
[G-02] | Use assembly to write address storage values | 21 |
[G-03] | Use nested if statements instead of && | 2 |
[G-04] | Sort Solidity operations using short-circuit mode | 13 |
[G-05] |  public functions to external | 21 |
[G-06] | Amounts should be checked for 0 before calling a transfer | 4 |
[G-07] | Do not calculate constants | 1 |
[G-08] | Do not shrink Variables | 6 |
[G-09] | abi.encode() is less efficient than abi.encodePacked() | 17 |
[G-10] | Change public state variable visibility to private | 1 |
[G-11] | Use != 0 instead of > 0 for unsigned integer comparison | 4 |
[G-12] | Use hardcode address instead address(this) | 4 |
[G-13] | Use Assembly To Check For address(0) | 1 |
[G-14] | Use constants instead of type(uintx).max | 1 |
[G-15] | Duplicated require()/if() checks should be refactored to a modifier or function | 3 |
[G-16] | Use assembly to hash instead of Solidity | 14 |
[G-17] | Loop best practice to save gas | 12 |
[G-18] | Remove the initializer modifier | 8 |
[G-19] | use Mappings Instead of Arrays | 2 |
[G-20] | Use assembly for math (add, sub, mul, div) | 2 |
[G-21] | Use assembly when getting a contract’s balance of ETH | 4 |
[G-22] | Replace state variable reads and writes within loops with local variable reads and writes. | 2 |
[G-23] | Gas savings can be achieved by changing the model for assigning value to the structure (260 gas) | 1 |
[G‑24] | Avoid contract existence checks by using low level calls |
In Solidity, variables that are declared inside a loop will be created and stored in memory each time the loop executes. This can lead to inefficient gas usage, as the cost of executing a loop can increase significantly if the loop body creates new variables each time it executes. On the other hand, if you declare the variable outside the loop, the variable will be created once and reused across multiple iterations of the loop. This can be more efficient because it reduces the amount of gas needed to create and store the variable.
104 bytes32 pubkeyRoot = UtilLib.getPubkeyRoot(_pubkey[i]);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L104
106 uint256 _mevTheftPenalty = calculateMEVTheftPenalty(pubkeyRoot);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L106
107 uint256 _missedAttestationPenalty = calculateMissedAttestationPenalty(pubkeyRoot);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L107
92 address operator = _permissionedNOs[i];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L92
157 address withdrawVault = IVaultFactory(vaultFactory).deployWithdrawVault(
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L157
273 uint256 validatorId = validatorIdByPubkey[_frontRunPubkey[i]];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L273
286 uint256 validatorId = validatorIdByPubkey[_invalidSignaturePubkey[i]];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L286
318 uint256 validatorId = validatorIdByPubkey[_pubkeys[i]];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L318
535 uint256 validatorId = validatorIdsByOperatorId[operatorId][i];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L535
638 uint256 validatorId = validatorIdsByOperatorId[operatorId][i];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L638
101 uint256 validatorToDeposit = selectedOperatorCapacity[i];
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L101
110 uint256 index = nextQueuedValidatorIndex;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L110
By using assembly to directly write the address to storage, we can save gas compared to using Solidity's built-in storage operations. This is because the assembly code is more efficient and optimized for writing directly to storage.
37 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Auction.sol#L37
140 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Auction.sol#L140
37 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ETHx.sol#L37
87 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ETHx.sol#L87
34 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/OperatorRewardsCollector.sol#L34
41 balances[_receiver] += msg.value;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/OperatorRewardsCollector.sol#L41
58 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/OperatorRewardsCollector.sol#L58
42 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L42
43 ratedOracleAddress = _ratedOracleAddress;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L43
86 ratedOracleAddress = _ratedOracleAddress;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L86
93 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L93
72 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L72
407 operatorStructById[operatorId].operatorRewardAddress = _rewardAddress;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L407
461 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L461
45 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L45
149 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolSelector.sol#L149
29 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolUtils.sol#L29
33 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L33
47 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L47
60 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/UserWithdrawalManager.sol#L60
86 staderConfig = IStaderConfig(_staderConfig);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/UserWithdrawalManager.sol#L86
Instead of using the && operator, you can use nested if statements to achieve the same result. Using a logical AND (&&) in an if statement can consume more gas compared to using nested if statements.
146 if (_amountSD[i] == 0 && _amountETH[i] == 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SocializingPool.sol#L146
35 if (!staderConfig.onlyOperatorRole(msg.sender) && totalRewards > staderConfig.getRewardsThreshold()) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ValidatorWithdrawalVault.sol#L35
Short-circuiting is a technique used in Solidity contract development that utilizes logical operators (OR/AND) to control the order of execution of different operations with varying gas costs. It involves placing the operations with lower gas costs at the beginning and those with higher gas costs at the end. This way, if the low-cost operation at the beginning is successful, the subsequent high-cost Ethereum virtual machine operation can be skipped, resulting in significant gas savings. Essentially, short-circuiting allows the program to take a shortcut and bypass more expensive operations when it's possible to do so.
example: function transfer(address recipient, uint amount) public { require(recipient != address(0) || amount > 0, "Invalid transfer parameters"); // Perform transfer logic }
693 if (_pubkeyLength != _preDepositSignatureLength || _pubkeyLength != _depositSignatureLength) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L693
697 if (keyCount == 0 || keyCount > inputKeyCountLimit) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L697
174 if (preDepositValidatorCount != 0 || address(this).balance == 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L174
649 if (_pubkeyLength != _preDepositSignatureLength || _pubkeyLength != _depositSignatureLength) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L649
653 if (keyCount == 0 || keyCount > inputKeyCountLimit) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L653
713 if (_validatorId == 0 || validatorRegistry[_validatorId].status != ValidatorStatus.INITIALIZED) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L713
103 if (ethToDeposit < ETH_PER_NODE || selectedValidatorCount >= poolAllocationMaxSize) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolSelector.sol#L103
127 if ((_minThreshold > _withdrawThreshold) || (_minThreshold > _maxThreshold)) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L127
170 if (_index == 0 || _index > lastReportedRewardsData.index) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SocializingPool.sol#L170
44 if (address(this).balance < _amount || _amount == 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderInsuranceFund.sol#L44
532 if (_erChangeLimit == 0 || _erChangeLimit > ER_CHANGE_MAX_BPS) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L532
171 if (assets > maxDeposit() || assets < minDeposit()) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderStakePoolsManager.sol#L171
98 if (assets < staderConfig.getMinWithdrawAmount() || assets > staderConfig.getMaxWithdrawAmount()) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/UserWithdrawalManager.sol#L98
When we say that "external call cost is less expensive than that of public functions," we mean that calling an external function is generally cheaper in terms of gas costs than calling a public function. This is because external functions can only be accessed externally, and therefore, they don't require the additional checks and validation that public functions do. The Solidity compiler is able to optimize external functions more effectively, resulting in lower gas costs.
example:
contract MyContract { uint public value;
function setValue(uint newValue) public { require(newValue > value, "New value must be greater than current value"); value = newValue; } function getValue() external view returns (uint) { return value; }
}
29 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ETHx.sol#L29
66 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L66
40 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L40
66 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L66
440 function getTotalQueuedValidatorCount() public view override returns (uint256) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L440
38 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L38
25 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolUtils.sol#L25
26 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L26
205 function convertSDToETH(uint256 _sdAmount) public view override returns (uint256) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L205
39 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SocializingPool.sol#L39
62 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L62
571 function getERReportableBlock() public view override returns (uint256) { return getReportableBlockFor(ETHX_ER_UF); }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L571
582 function getSDPriceReportableBlock() public view override returns (uint256) { return getReportableBlockFor(SD_PRICE_UF); }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L582
586 function getValidatorStatsReportableBlock() public view override returns (uint256) { return getReportableBlockFor(VALIDATOR_STATS_UF); }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L586
590 function getWithdrawnValidatorReportableBlock() public view override returns (uint256) { return getReportableBlockFor(WITHDRAWN_VALIDATORS_UF); }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L590
50 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderStakePoolsManager.sol#50
140 function convertToShares(uint256 _assets) public view override returns (uint256) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderStakePoolsManager.sol#140
145 function convertToAssets(uint256 _shares) public view override returns (uint256) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderStakePoolsManager.sol#145
54 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/UserWithdrawalManager.sol#L54
34 function deployWithdrawVault( uint8 _poolId, uint256 _operatorId, uint256 _validatorCount, uint256 _validatorId ) public override onlyRole(NODE_REGISTRY_CONTRACT) returns (address) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L34
62 function computeWithdrawVaultAddress( uint8 _poolId, uint256 _operatorId, uint256 _validatorCount ) public view override returns (address) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L62
When transferring tokens or ether in a Solidity smart contract using the transfer function, it's important to check the amount being transferred to avoid wasting gas by transferring zero amounts. This is because transferring zero amounts is still a valid operation, but it has no effect, and it can consume gas unnecessarily.
To avoid this waste of gas, it's recommended to check the amount being transferred before calling the transfer function. This way, we can avoid making an unnecessary transfer and save gas in the process.
example:
function sendTokens(address recipient, uint amount) public { require(amount > 0, "Amount must be greater than zero"); require(token.balanceOf(msg.sender) >= amount, "Insufficient balance"); token.transfer(recipient, amount); }
55 if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), _sdAmount)) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Auction.sol#L55
87 if (!IERC20(staderConfig.getStaderToken()).transfer(lotItem.highestBidder, lotItem.sdAmount)) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Auction.sol#L87
82 super._beforeTokenTransfer(from, to, amount);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ETHx.sol#L82
68 if (!IERC20(staderConfig.getStaderToken()).transfer(payable(operator), _requestedSD)) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L68
When we say "do not calculate constants," we mean that if a value is constant and known at compile-time, it should be hard-coded into the code instead of being calculated at runtime. This avoids the need for expensive calculations during contract execution and can help reduce gas costs.
Here's an example of how to avoid calculating constants: contract MyContract { uint constant public MAX_VALUE = 100; uint public value;
function setValue(uint newValue) public { require(newValue <= MAX_VALUE, "Value exceeds maximum"); value = newValue; }
}
26 uint256 public constant MAX_ER_UPDATE_FREQUENCY = 7200 * 7; // 7 days
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L26
When we say "do not shrink variables," we mean that if a variable needs to hold a certain range of values, it should be declared with the appropriate data type to avoid unnecessary conversions and potential data loss. Shrinking a variable's data type to the smallest possible size can result in additional gas costs due to the need for conversions and can even lead to data loss if the value exceeds the variable's range.
Here's an example of how to avoid shrinking variables:
contract MyContract { uint public value;
function setValue(uint256 newValue) public { require(newValue <= 100, "Value exceeds maximum"); value = newValue; }
}
30 uint8 public constant override POOL_ID = 1;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L30
31 uint16 public override inputKeyCountLimit;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L31
32 uint64 public override maxNonTerminalKeyPerOperator;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L32
31 uint8 public constant override POOL_ID = 2;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L31
32 uint16 public override inputKeyCountLimit;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L32
33 uint64 public override maxNonTerminalKeyPerOperator;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L33
When we say that abi.encodePacked() is less gas-intensive than abi.encode(), we mean that abi.encodePacked() is generally more efficient in terms of gas usage because it does not add any additional overhead or padding to the encoded data. In contrast, abi.encode() adds additional padding to the encoded data, resulting in higher gas costs.
Here's an example of how to use abi.encodePacked() to save gas:
contract MyContract { function encodeData(uint256 value, address recipient, bytes32 data) public returns (bytes memory) { return abi.encodePacked(value, recipient, data); } }
127 abi.encode( msg.sender, _exchangeRate.reportingBlockNumber, _exchangeRate.totalETHBalance, _exchangeRate.totalETHXSupply )
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L127
135 abi.encode(_exchangeRate.reportingBlockNumber, _exchangeRate.totalETHBalance, _exchangeRate.totalETHXSupply)
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L135
221 abi.encode( msg.sender, _rewardsData.index, _rewardsData.merkleRoot, _rewardsData.poolId, _rewardsData.operatorETHRewards, _rewardsData.userETHRewards, _rewardsData.protocolETHRewards, _rewardsData.operatorSDRewards )
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L221
233 abi.encode( _rewardsData.index, _rewardsData.merkleRoot, _rewardsData.poolId, _rewardsData.operatorETHRewards, _rewardsData.userETHRewards, _rewardsData.protocolETHRewards, _rewardsData.operatorSDRewards )
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L233
282 bytes32 nodeSubmissionKey = keccak256(abi.encode(msg.sender, _sdPriceData.reportingBlockNumber));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L282
283 bytes32 submissionCountKey = keccak256(abi.encode(_sdPriceData.reportingBlockNumber));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L283
334 abi.encode( msg.sender, _validatorStats.reportingBlockNumber, _validatorStats.exitingValidatorsBalance, _validatorStats.exitedValidatorsBalance, _validatorStats.slashedValidatorsBalance, _validatorStats.exitingValidatorsCount, _validatorStats.exitedValidatorsCount, _validatorStats.slashedValidatorsCount )
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L334
346 abi.encode( _validatorStats.reportingBlockNumber, _validatorStats.exitingValidatorsBalance, _validatorStats.exitedValidatorsBalance, _validatorStats.slashedValidatorsBalance, _validatorStats.exitingValidatorsCount, _validatorStats.exitedValidatorsCount, _validatorStats.slashedValidatorsCount )
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L346
407 bytes memory encodedPubkeys = abi.encode(_withdrawnValidators.sortedPubkeys);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L407
410 abi.encode( msg.sender, _withdrawnValidators.reportingBlockNumber, _withdrawnValidators.nodeRegistry, encodedPubkeys )
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L410
418 abi.encode(_withdrawnValidators.reportingBlockNumber, _withdrawnValidators.nodeRegistry, encodedPubkeys)
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L418
469 bytes32 nodeSubmissionKey = keccak256(abi.encode(msg.sender, _mapd.index, encodedPubkeys));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L469
470 bytes32 submissionCountKey = keccak256(abi.encode(_mapd.index, encodedPubkeys));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L470
40 bytes32 salt = sha256(abi.encode(_poolId, _operatorId, _validatorCount));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L40
54 bytes32 salt = sha256(abi.encode(_poolId, _operatorId));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L54
67 bytes32 salt = sha256(abi.encode(_poolId, _operatorId, _validatorCount));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L67
77 bytes32 salt = sha256(abi.encode(_poolId, _operatorId));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L77
14 address public override owner;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/VaultProxy.sol#L14
When we say "use != 0 instead of > 0 for unsigned integer comparison," we mean that when checking if an unsigned integer value is non-zero, it's more gas-efficient to use the != operator instead of the > operator. This is because the != operator is a bitwise operation and is therefore more efficient than the arithmetic comparison performed by the > operator.
Here's an example of how to use != 0 instead of > 0 for unsigned integer comparison:
contract MyContract { uint public value;
function isNonZero() public view returns (bool) { return value != 0; }
}
299 if (totalDefectedKeys > 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L299
209 if (frontRunValidatorsLength > 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L209
119 if (totalAmountETH > 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SocializingPool.sol#L119
127 if (totalAmountSD > 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SocializingPool.sol#L127
When we say "use hardcode address instead of address(this)," we mean that if the contract's address is needed in the code, it's more gas-efficient to hardcode the address as a constant rather than using the address(this) expression. This is because using address(this) requires additional gas consumption to compute the contract's address at runtime.
Here's an example : contract MyContract { address constant public CONTRACT_ADDRESS = 0x1234567890123456789012345678901234567890;
function getContractAddress() public view returns (address) { return CONTRACT_ADDRESS; }
}
uint8 poolId = IVaultProxy(address(this)).poolId(); uint256 operatorId = IVaultProxy(address(this)).id(); IStaderConfig staderConfig = IVaultProxy(address(this)).staderConfig(); uint256 totalRewards = address(this).balance;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/NodeELRewardVault.sol#L25-L28
174 if (preDepositValidatorCount != 0 || address(this).balance == 0) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L174
178 value: address(this).balance
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L178
31 uint8 poolId = VaultProxy(payable(address(this))).poolId(); uint256 validatorId = VaultProxy(payable(address(this))).id(); IStaderConfig staderConfig = VaultProxy(payable(address(this))).staderConfig(); 34 uint256 totalRewards = address(this).balance;
96 if (_owner == address(0)) revert ZeroAddressReceived();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/UserWithdrawalManager.sol#L96
When we say "use constants instead of type(uintX).max," we mean that when initializing a variable with the maximum value of an unsigned integer type, it's more gas-efficient to use a constant variable rather than the type(uintX).max expression. This is because the type(uintX).max expression requires additional gas consumption to compute the maximum value at runtime.
106 IERC20(staderConfig.getStaderToken()).approve(auctionContract, type(uint256).max);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L106
59 if (_addr != withdrawVaultAddress) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/library/UtilLib.sol#L59
75 if (_addr != withdrawVaultAddress) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/library/UtilLib.sol#L75
90 if (_addr != withdrawVaultAddress) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/library/UtilLib.sol#L90
When we say "use assembly to hash instead of Solidity," we mean that when hashing data in a smart contract, it's more gas-efficient to use assembly code to perform the hash operation instead of Solidity's built-in hash functions. This is because Solidity's built-in hash functions require additional gas consumption to perform the operation.
Here's an example:
contract MyContract { function sha256(bytes memory data) public view returns (bytes32) { bytes32 hash; assembly { hash := sha256(add(data, 32), mload(data)) } return hash; } }
174 bytes32 node = keccak256(abi.encodePacked(_operator, _amountSD, _amountETH));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SocializingPool.sol#L174
126 bytes32 nodeSubmissionKey = keccak256( abi.encode( msg.sender, _exchangeRate.reportingBlockNumber, _exchangeRate.totalETHBalance, _exchangeRate.totalETHXSupply ) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L126
134 bytes32 submissionCountKey = keccak256( abi.encode(_exchangeRate.reportingBlockNumber, _exchangeRate.totalETHBalance, _exchangeRate.totalETHXSupply) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L134
220 bytes32 nodeSubmissionKey = keccak256( abi.encode( msg.sender, _rewardsData.index, _rewardsData.merkleRoot, _rewardsData.poolId, _rewardsData.operatorETHRewards, _rewardsData.userETHRewards, _rewardsData.protocolETHRewards, _rewardsData.operatorSDRewards ) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L220
232 bytes32 submissionCountKey = keccak256( abi.encode( _rewardsData.index, _rewardsData.merkleRoot, _rewardsData.poolId, _rewardsData.operatorETHRewards, _rewardsData.userETHRewards, _rewardsData.protocolETHRewards, _rewardsData.operatorSDRewards ) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L232
282 bytes32 nodeSubmissionKey = keccak256(abi.encode(msg.sender, _sdPriceData.reportingBlockNumber));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L282
283 bytes32 submissionCountKey = keccak256(abi.encode(_sdPriceData.reportingBlockNumber));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L283
333 bytes32 nodeSubmissionKey = keccak256( abi.encode( msg.sender, _validatorStats.reportingBlockNumber, _validatorStats.exitingValidatorsBalance, _validatorStats.exitedValidatorsBalance, _validatorStats.slashedValidatorsBalance, _validatorStats.exitingValidatorsCount, _validatorStats.exitedValidatorsCount, _validatorStats.slashedValidatorsCount ) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L333
345 bytes32 submissionCountKey = keccak256( abi.encode( _validatorStats.reportingBlockNumber, _validatorStats.exitingValidatorsBalance, _validatorStats.exitedValidatorsBalance, _validatorStats.slashedValidatorsBalance, _validatorStats.exitingValidatorsCount, _validatorStats.exitedValidatorsCount, _validatorStats.slashedValidatorsCount ) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L345
409 bytes32 nodeSubmissionKey = keccak256( abi.encode( msg.sender, _withdrawnValidators.reportingBlockNumber, _withdrawnValidators.nodeRegistry, encodedPubkeys ) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L409
417 bytes32 submissionCountKey = keccak256( abi.encode(_withdrawnValidators.reportingBlockNumber, _withdrawnValidators.nodeRegistry, encodedPubkeys) );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L417
469 bytes32 nodeSubmissionKey = keccak256(abi.encode(msg.sender, _mapd.index, encodedPubkeys));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L469
470 bytes32 submissionCountKey = keccak256(abi.encode(_mapd.index, encodedPubkeys));
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L470
16 bytes32 public constant override NODE_REGISTRY_CONTRACT = keccak256('NODE_REGISTRY_CONTRACT');
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/factory/VaultFactory.sol#L16
177 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L177
214 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L214
279 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L279
292 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L292
326 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L326
492 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L492
539 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L539
163 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L163
204 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L204
220 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L220
230 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L230
256 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L256
420 unchecked { ++i; }
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L420
When we say "remove the initializer modifier," we mean that instead of defining a separate function with the initializer modifier to initialize a contract's state variables, we can simply initialize them directly in the constructor function. This can be more gas-efficient because it avoids the additional gas costs associated with calling a separate initialization function.
29 function initialize(address _admin, address _staderConfig) external initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Auction.sol#L29
29 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ETHx.sol#L29
27 function initialize(address _admin, address _staderConfig) external initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/OperatorRewardsCollector.sol#L27
31 function initialize( address _admin, address _staderConfig, address _ratedOracleAddress ) external initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L31
66 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L66
40 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L40
66 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L66
38 function initialize(address _admin, address _staderConfig) public initializer {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L38
When we say "use mappings instead of arrays," we mean that when storing and accessing data in a smart contract, it's more gas-efficient to use mappings instead of arrays. This is because mappings do not require iteration to find a specific element, whereas arrays do.
125 uint256[] memory violatedEpochs = IRatedV1(ratedOracleAddress).getViolationsForValidator(_pubkeyRoot);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L125
202 uint256[] memory remainingOperatorCapacity = new uint256[](nextOperatorId);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L202
When we say "use assembly for math operations," we mean that when performing basic math operations in a smart contract, it's more gas-efficient to use assembly code to perform the operation instead of Solidity's built-in math functions. This is because Solidity's built-in math functions require additional gas consumption to perform the operation.
629 uint256 endIndex = startIndex + _pageSize;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L629
500 uint256 endIndex = startIndex + _pageSize;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessNodeRegistry.sol#L500
When we say "use assembly to get a contract's balance of Ether," we mean that when retrieving the balance of Ether held by a contract, it's more gas-efficient to use assembly code to perform the operation instead of Solidity's built-in address.balance property. This is because Solidity's built-in address.balance property requires additional gas consumption to perform the operation.
28 uint256 totalRewards = address(this).balance;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/NodeELRewardVault.sol#L28
178 value: address(this).balance
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L178
34 uint256 totalRewards = address(this).balance;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ValidatorWithdrawalVault.sol#L34
99 uint256 contractBalance = address(this).balance;
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ValidatorWithdrawalVault.sol#L99
When we say "replace state variable reads and writes within loops with local variable reads and writes," we mean that when accessing state variables within loops, it's more gas-efficient to read the state variable once and store it in a local variable, and subsequently, read and write to the local variable within the loop instead of repeatedly accessing the state variable. This is because reading and writing to state variables is more gas-intensive than reading and writing to local variables.
206 for (uint256 i = 1; i < nextOperatorId; ) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L206
488 for (uint256 i = 1; i < nextOperatorId; ) {
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedNodeRegistry.sol#L488
When we say "change the model for assigning value to a structure," we mean that when initializing or assigning values to a structure, it's more gas-efficient to use a single assignment statement that includes all of the values for the structure, instead of assigning each value one by one. This is because each individual assignment requires additional gas consumption, so reducing the number of assignments can lead to significant gas savings.
131 poolThresholdbyPoolId[_poolId] = PoolThresholdInfo({ minThreshold: _minThreshold, maxThreshold: _maxThreshold, withdrawThreshold: _withdrawThreshold, units: _units });
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/SDCollateral.sol#L131-L136
when invoking a contract function, it's more gas-efficient to use a low-level call instead of Solidity's built-in contract existence checks. This is because Solidity's built-in contract existence checks require additional gas consumption to perform the check, which can be costly when invoked repeatedly.
95 uint256[] memory selectedOperatorCapacity = IPermissionedNodeRegistry(nodeRegistryAddress) .allocateValidatorsAndUpdateOperatorId(requiredValidators);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L95
114 uint256 validatorId = INodeRegistry(nodeRegistryAddress).validatorIdsByOperatorId(i, index);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L114
139 uint256 validatorId = INodeRegistry(nodeRegistryAddress).validatorIdByPubkey(_pubkey[i]);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L139
140 (, , , bytes memory depositSignature, address withdrawVaultAddress, , , ) = INodeRegistry( nodeRegistryAddress ).validatorRegistry(validatorId);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L140
143 bytes memory withdrawCredential = IVaultFactory(vaultFactory).getValidatorWithdrawCredential( withdrawVaultAddress );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L143
186 return INodeRegistry(staderConfig.getPermissionedNodeRegistry()).getTotalQueuedValidatorCount();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L186
183 return INodeRegistry(staderConfig.getPermissionedNodeRegistry()).getTotalActiveValidatorCount();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L183
205 INodeRegistry(staderConfig.getPermissionedNodeRegistry()).getOperatorTotalNonTerminalKeys( _nodeOperator, _startIndex, _endIndex );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L205
218 return INodeRegistry(staderConfig.getPermissionedNodeRegistry()).getCollateralETH();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L218
227 return INodeRegistry(staderConfig.getPermissionedNodeRegistry()).isExistingPubkey(_pubkey);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L227
232 return INodeRegistry(staderConfig.getPermissionedNodeRegistry()).isExistingOperator(_operAddr);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L232
298 bytes memory withdrawCredential = IVaultFactory(_vaultFactory).getValidatorWithdrawCredential( withdrawVaultAddress );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionedPool.sol#L298
95 address withdrawVault = IVaultFactory(vaultFactory).computeWithdrawVaultAddress( INodeRegistry((staderConfig).getPermissionlessNodeRegistry()).POOL_ID(), _operatorId, _operatorTotalKeys + i );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L95
100 bytes memory withdrawCredential = IVaultFactory(vaultFactory).getValidatorWithdrawCredential(withdrawVault);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L100
136 uint256 depositQueueStartIndex = IPermissionlessNodeRegistry(nodeRegistryAddress).nextQueuedValidatorIndex();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L136
138 uint256 validatorId = IPermissionlessNodeRegistry(nodeRegistryAddress).queuedValidators(i);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L138
165 return INodeRegistry(staderConfig.getPermissionlessNodeRegistry()).getTotalQueuedValidatorCount();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L165
172 return INodeRegistry(staderConfig.getPermissionlessNodeRegistry()).getTotalActiveValidatorCount();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L172
184 INodeRegistry(staderConfig.getPermissionlessNodeRegistry()).getOperatorTotalNonTerminalKeys( _nodeOperator, _startIndex, _endIndex ); https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L184 ```solidity 192 return INodeRegistry(staderConfig.getPermissionlessNodeRegistry()).getCollateralETH();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L192
201 return INodeRegistry(staderConfig.getPermissionlessNodeRegistry()).isExistingPubkey(_pubkey);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L201
206 return INodeRegistry(staderConfig.getPermissionlessNodeRegistry()).isExistingOperator(_operAddr);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L206
248 (, bytes memory pubkey, , bytes memory depositSignature, address withdrawVaultAddress, , , ) = INodeRegistry( _nodeRegistryAddress ).validatorRegistry(_validatorId);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L248
252 bytes memory withdrawCredential = IVaultFactory(_vaultFactoryAddress).getValidatorWithdrawCredential( withdrawVaultAddress );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PermissionlessPool.sol#L252
File: /contracts/ValidatorWithdrawalVault.sol 145 (, bytes memory pubkey, , , , , , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId); 149 return IPenalty(_staderConfig.getPenaltyContract()).totalPenaltyAmount(pubkey);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/ValidatorWithdrawalVault.sol#L145
197 uint256 selectedPoolCapacity = IPoolSelector(staderConfig.getPoolSelector()).computePoolAllocationForDeposit( _poolId, (availableETHForNewDeposit / poolDepositSize) ); https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderStakePoolsManager.sol#L197 ```solidity 227 (uint256[] memory selectedPoolCapacity, uint8[] memory poolIdArray) = IPoolSelector( staderConfig.getPoolSelector() ).poolAllocationForExcessETHDeposit(availableETHForNewDeposit);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderStakePoolsManager.sol#L227
32 (uint256 userShare, uint256 operatorShare, uint256 protocolShare) = IPoolUtils(staderConfig.getPoolUtils()) .calculateRewardShare(poolId, totalRewards);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/NodeELRewardVault.sol#L32
256 address socializingPool = IPoolUtils(staderConfig.getPoolUtils()).getSocializingPoolAddress( _rewardsData.poolId );
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L256
576 (, , uint256 currentEndBlock) = ISocializingPool( IPoolUtils(staderConfig.getPoolUtils()).getSocializingPoolAddress(_poolId) ).getRewardDetails();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L576
608 ISocializingPool(IPoolUtils(staderConfig.getPoolUtils()).getSocializingPoolAddress(_poolId)) .getCurrentRewardsIndex();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/StaderOracle.sol#L608
125 uint256[] memory violatedEpochs = IRatedV1(ratedOracleAddress).getViolationsForValidator(_pubkeyRoot);
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/Penalty.sol#L125
92 return IStaderPoolBase(poolAddressById[_poolId]).protocolFee();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolUtils.sol#L92
143 return IStaderPoolBase(poolAddressById[_poolId]).getSocializingPoolAddress();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolUtils.sol#L143
163 return IStaderPoolBase(poolAddressById[_poolId]).getNodeRegistry();
https://github.com/code-423n4/2023-06-stader/blob/main/contracts/PoolUtils.sol#L163
#0 - c4-judge
2023-06-14T05:34:40Z
Picodes marked the issue as grade-b