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: 42/92
Findings: 2
Award: $140.62
π Selected for report: 0
π Solo Findings: 0
88.5851 USDC - $88.59
The function is not used internally from any other contract, but can/will be used from bots or endusers to check the balance. As the return value is always wrong when _stakingFundsVaults.length > 1 it is not usable for consumers.
accumulated is overwritten for every loop.
File: contracts/liquid-staking/GiantMevAndFeesPool.sol 89: uint256 accumulated; 90: for (uint256 i; i < _stakingFundsVaults.length; ++i) { 91: accumulated = StakingFundsVault(payable(_stakingFundsVaults[i])).batchPreviewAccumulatedETH( 92: address(this), 93: _lpTokens[i] 94: ); 95: }
In the end accumulated is returned via
return _previewAccumulatedETH(_user, address(_lpTokenETH), _lpTokenETH.balanceOf(_user), _lpTokenETH.totalSupply(), accumulated);
Remove function, so users or bots can't use it if it's not important, or fix the accumulated to sum up correctly.
accumulated +=
#0 - c4-judge
2022-11-21T21:47:09Z
dmvt marked the issue as duplicate of #160
#1 - c4-judge
2022-11-30T14:18:44Z
dmvt marked the issue as satisfactory
π 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
Solidity pragma versioning should be exactly same in all contracts. Currently some contracts use ^0.8.13 but some are fixed to 0.8.13
Solidity pragma versioning can be upgraded to latest version 0.8.17 as this version has some bugs fixed that still exist in 0.8.13 - https://docs.soliditylang.org/en/v0.8.17/bugs.html
To Upgrade to 0.8.17 you need to remove the stakehouse dependency ("@blockswaplab/stakehouse-solidity-api": "2.1.0") as you need to change the Version to 0.8.17 in the Interfaces.
The stakehouse-contract-interfaces has a wrong pragma definition (pragma solidity 0.8.13) and so you need to import them locally and change it to 0.8.17 / ^0.8.13.
Probably it's best to open a PR to change it on the original site.
β 2022-11-stakehouse git:(main) β forge test [β ’] Compiling... [β ] Compiling 100 files with 0.8.17 [β ] Solc 0.8.17 finished in 11.85s Compiler run successful
All tests also pass.
An outdated OZ version is used (which has known vulnerabilities, see https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories).
Currently used:
"@openzeppelin/contracts": "^4.5.0", "@openzeppelin/contracts-upgradeable": "4.5.0",
Consider updating to > 4.7.3 / 4.8
For a better developer experience you should stick to the solidity-docs specification how to structure a Solidity Source File.
Some files mixed up the order of the licencse => pragmas => imports => rest definition.
File: contracts/liquid-staking/GiantLP.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6: import { ITransferHookProcessor } from "../interfaces/ITransferHookProcessor.sol"; File: contracts/liquid-staking/GiantMevAndFeesPool.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { GiantLP } from "./GiantLP.sol"; File: contracts/liquid-staking/GiantPoolBase.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; File: contracts/liquid-staking/GiantSavETHVaultPool.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { StakehouseAPI } from "@blockswaplab/stakehouse-solidity-api/contracts/StakehouseAPI.sol"; File: contracts/liquid-staking/LPToken.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; File: contracts/liquid-staking/LPTokenFactory.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; File: contracts/liquid-staking/LSDNFactory.sol 1: pragma solidity 0.8.17; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; File: contracts/liquid-staking/OptionalHouseGatekeeper.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { IGateKeeper } from "../interfaces/IGateKeeper.sol"; File: contracts/liquid-staking/SavETHVaultDeployer.sol 1: pragma solidity ^0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; File: contracts/syndicate/Syndicate.sol 1: pragma solidity 0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; File: contracts/syndicate/SyndicateErrors.sol 1: pragma solidity 0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: error ZeroAddress(); File: contracts/syndicate/SyndicateFactory.sol 1: pragma solidity 0.8.13; 2: 3: // SPDX-License-Identifier: MIT 4: 5: import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so itβs not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question.
File: contracts/liquid-staking/ETHPoolLPFactory.sol 16: event ETHWithdrawnByDepositor(address depositor, uint256 amount); // @audit-qa depositor indexed File: contracts/liquid-staking/ETHPoolLPFactory.sol 19: event LPTokenBurnt(bytes blsPublicKeyOfKnot, address token, address depositor, uint256 amount); // @audit-qa token + depositor indexed File: contracts/liquid-staking/ETHPoolLPFactory.sol 22: event NewLPTokenIssued(bytes blsPublicKeyOfKnot, address token, address firstDepositor, uint256 amount); // @audit-qa token + firstDepositor indexed File: contracts/liquid-staking/ETHPoolLPFactory.sol 25: event LPTokenMinted(bytes blsPublicKeyOfKnot, address token, address depositor, uint256 amount); // @audit-qa token + depositor indexed File: contracts/liquid-staking/SavETHVault.sol 19: event DETHRedeemed(address depositor, uint256 amount); // @audit-qa depositor indexed File: contracts/liquid-staking/SavETHVault.sol 22: event ETHWithdrawnForStaking(address withdrawalAddress, address liquidStakingManager, uint256 amount); // @audit-qa NatSpec withdrawalAddress + liquidStakingManager indexed File: contracts/liquid-staking/StakingFundsVault.sol 25: event ETHDeposited(address sender, uint256 amount); // @audit-qa indexed sender File: contracts/liquid-staking/StakingFundsVault.sol 28: event ETHWithdrawn(address receiver, address admin, uint256 amount); // @audit-qa indexed receiver + admin File: contracts/liquid-staking/StakingFundsVault.sol 31: event ERC20Recovered(address admin, address recipient, uint256 amount); // @audit-qa indexed admin + recipient File: contracts/liquid-staking/StakingFundsVault.sol 34: event WETHUnwrapped(address admin, uint256 amount); // @audit-qa indexed admin
Usually lines in source code are limited to 80 characters. Todayβs screens are much larger so itβs reasonable to stretch this in some cases. Since the files will most likely reside in GitHub, and GitHub starts using a scroll bar in all cases when the length is over 164 characters, the lines below should be split when they reach that length
File: contracts/liquid-staking/LiquidStakingManager.sol 222: /// @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 File: contracts/syndicate/Syndicate.sol 116: /// @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 File: contracts/syndicate/Syndicate.sol 119: /// @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 File: contracts/syndicate/Syndicate.sol 398: /// @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 File: contracts/syndicate/Syndicate.sol 490: /// 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)
If a function is not used internally change the visibility to external for a better experience to identify the puprose of the function.
File: contracts/liquid-staking/GiantPoolBase.sol 34: function depositETH(uint256 _amount) public payable { // @audit-qa change external File: contracts/liquid-staking/GiantSavETHVaultPool.sol 29: function batchDepositETHForStaking( 30: address[] calldata _savETHVaults, 31: uint256[] calldata _ETHTransactionAmounts, 32: bytes[][] calldata _blsPublicKeys, 33: uint256[][] calldata _stakeAmounts 34: ) public { // @audit-qa change external File: contracts/liquid-staking/LiquidStakingManager.sol 514: function isKnotDeregistered(bytes calldata _blsPublicKey) public view returns (bool) { // @audit-qa change external File: contracts/liquid-staking/SavETHVault.sol 83: function depositETHForStaking(bytes calldata _blsPublicKeyOfKnot, uint256 _amount) public payable returns (uint256) { // @audit-qa change external File: contracts/liquid-staking/SavETHVault.sol 200: function withdrawETHForStaking( 201: address _smartWallet, 202: uint256 _amount 203: ) public onlyManager nonReentrant returns (uint256) { // @audit-qa change external File: contracts/liquid-staking/SavETHVault.sol 218: function isBLSPublicKeyPartOfLSDNetwork(bytes calldata _blsPublicKeyOfKnot) public virtual view returns (bool) { // @audit-qa change external File: contracts/liquid-staking/SavETHVault.sol 223: function isBLSPublicKeyBanned(bytes calldata _blsPublicKeyOfKnot) public view returns (bool) { // @audit-qa change external File: contracts/liquid-staking/StakingFundsVault.sol 113: function depositETHForStaking(bytes calldata _blsPublicKeyOfKnot, uint256 _amount) public payable returns (uint256) { // @audit-qa change external File: contracts/liquid-staking/StakingFundsVault.sol 239: function withdrawETH(address _wallet, uint256 _amount) public onlyManager nonReentrant returns (uint256) { // @audit-qa change external File: contracts/syndicate/Syndicate.sol 285: function claimAsStaker(address _recipient, bytes[] calldata _blsPubKeys) public nonReentrant { // @audit-qa change external File: contracts/syndicate/Syndicate.sol 458: function calculateNewAccumulatedETHPerCollateralizedSharePerKnot() public view returns (uint256) { // @audit-qa change external
It is bad practice to use numbers directly in code without explanation.
File: contracts/liquid-staking/ETHPoolLPFactory.sol 113: require(_blsPublicKeyOfKnot.length == 48, "Invalid BLS public key"); File: contracts/liquid-staking/GiantSavETHVaultPool.sol 127: require(lpTokenETH.balanceOf(msg.sender) >= 0.5 ether, "No common interest"); File: contracts/liquid-staking/LiquidStakingManager.sol 434: require(msg.value == len * 4 ether, "Insufficient ether provided"); File: contracts/liquid-staking/LiquidStakingManager.sol 751: savETHVault.withdrawETHForStaking(smartWallet, 24 ether); File: contracts/liquid-staking/LiquidStakingManager.sol 754: stakingFundsVault.withdrawETH(smartWallet, 4 ether); File: contracts/liquid-staking/LiquidStakingManager.sol 768: 32 ether File: contracts/liquid-staking/LiquidStakingManager.sol 885: uint256 stakeAmount = 12 ether; File: contracts/liquid-staking/LiquidStakingManager.sol 939: require(associatedSmartWallet.balance >= 4 ether, "Smart wallet balance must be at least 4 ether"); File: contracts/liquid-staking/LiquidStakingManager.sol 943: require(stakingFundsLP.totalSupply() == 4 ether, "DAO staking funds vault balance must be at least 4 ether"); File: contracts/liquid-staking/LiquidStakingManager.sol 947: require(savETHVaultLP.totalSupply() == 24 ether, "KNOT must have 24 ETH in savETH vault"); File: contracts/liquid-staking/SavETHVault.sol 141: bool isStaleLiquidity = _lpToken.lastInteractedTimestamp(msg.sender) + 30 minutes < block.timestamp; File: contracts/liquid-staking/StakingFundsVault.sol 58: totalShares += 4 ether; File: contracts/liquid-staking/StakingFundsVault.sol 230: require(token.lastInteractedTimestamp(msg.sender) + 30 minutes < block.timestamp, "Last transfer too recent"); File: contracts/liquid-staking/StakingFundsVault.sol 380: maxStakingAmountPerValidator = 4 ether; File: contracts/syndicate/Syndicate.sol 221: if (totalStaked == 12 ether) revert KnotIsFullyStakedWithFreeFloatingSlotTokens(); File: contracts/syndicate/Syndicate.sol 223: if (_sETHAmount + totalStaked > 12 ether) revert InvalidStakeAmount(); File: contracts/syndicate/Syndicate.sol 428: 429: if (currentSlashedAmount < 4 ether) { 430: currentAccrued += 431: balance * unprocessedForKnot / (4 ether - currentSlashedAmount); 432: } File: contracts/syndicate/Syndicate.sol 504: if (currentSlashedAmount < 4 ether) { File: contracts/syndicate/Syndicate.sol 522: balance * unprocessedETHForCurrentKnot / (4 ether - currentSlashedAmount);
It's recommended to check addresses before storing that they're not address(0), except it's wished to be zero.
File: contracts/liquid-staking/GiantLP.sol 19: constructor( 20: address _pool, 21: address _transferHookProcessor, 22: string memory _name, 23: string memory _symbol 24: ) ERC20(_name, _symbol) { 25: pool = _pool; File: contracts/liquid-staking/LPToken.sol 32: function init( 33: address _deployer, 34: address _transferHookProcessor, 35: string calldata _tokenSymbol, 36: string calldata _tokenName 37: ) external override initializer { 38: deployer = _deployer;
Consider changing the variable to be an unnamed one
File: contracts/liquid-staking/LiquidStakingManager.sol 924: function _calculateCommission(uint256 _received) internal virtual view returns (uint256 _nodeRunner, uint256 _dao) {
The length for _ETHTransactionAmounts is not checked in the function.
File: contracts/liquid-staking/GiantMevAndFeesPool.sol 28: function batchDepositETHForStaking( 29: address[] calldata _stakingFundsVault, 30: uint256[] calldata _ETHTransactionAmounts, 31: bytes[][] calldata _blsPublicKeyOfKnots, 32: uint256[][] calldata _amounts 33: ) external { 34: uint256 numOfVaults = _stakingFundsVault.length; 35: require(numOfVaults > 0, "Zero vaults"); 36: require(numOfVaults == _blsPublicKeyOfKnots.length, "Inconsistent lengths"); 37: require(numOfVaults == _amounts.length, "Inconsistent lengths");length
Consider implementing a two step process where the owner / admin nominates an account and the nominated account needs to call an acceptOwnership() function for the transfer of ownership to fully succeed. This ensures the nominated EOA account is a valid and active account.
contracts/liquid-staking/LiquidStakingManager.sol
File: contracts/liquid-staking/LiquidStakingManager.sol 239: function updateDAOAddress(address _newAddress) external onlyDAO {
contracts/smart-wallet/OwnableSmartWallet.sol
can also move to address(0) and loose complete ownership
Use Scientific notation (e.g. 1e6) rather than decimal literals (e.g. 1000000), for better code readability.
File: contracts/liquid-staking/LiquidStakingManager.sol 158: uint256 public MODULO = 100_00000;
The contracts are very well documented and clear to read. Nearly every public function in the contracts contract have complete NatSpec comments. Still it misses some documentation that could be added for a even better developer experience.
Functions missing @param (or wrong param mentioned) / @return / @notice or is missing complete
File: contracts/liquid-staking/GiantLP.sol 29: function mint(address _recipient, uint256 _amount) external { // @audit-qa NatSpec File: contracts/liquid-staking/GiantLP.sol 34: function burn(address _recipient, uint256 _amount) external { // @audit-qa NatSpec File: contracts/liquid-staking/GiantMevAndFeesPool.sol 56: function claimRewards( // @audit-qa NatSpec File: contracts/liquid-staking/GiantMevAndFeesPool.sol 82: function previewAccumulatedETH( // @audit-qa NatSpec File: contracts/liquid-staking/GiantMevAndFeesPool.sol 105: function batchRotateLPTokens( // @audit-qa NatSpec param 2 x _oldLPTokens File: contracts/liquid-staking/GiantMevAndFeesPool.sol 146: function beforeTokenTransfer(address _from, address _to, uint256) external { // @audit-qa NatSpec File: contracts/liquid-staking/GiantMevAndFeesPool.sol 170: function afterTokenTransfer(address, address _to, uint256) external { // @audit-qa NatSpec File: contracts/liquid-staking/GiantMevAndFeesPool.sol 176: function totalRewardsReceived() public view override returns (uint256) { // @audit-qa NatSpec File: contracts/liquid-staking/GiantPoolBase.sol 34: function depositETH(uint256 _amount) public payable { // @audit-qa NatSpec File: contracts/liquid-staking/GiantSavETHVaultPool.sol 116: function batchRotateLPTokens( // @audit-qa NatSpec param 2 x _oldLPTokens File: contracts/liquid-staking/LPToken.sol 32: function init( 33: address _deployer, 34: address _transferHookProcessor, 35: string calldata _tokenSymbol, 36: string calldata _tokenName 37: ) external override initializer { // @audit-qa NatSpec File: contracts/liquid-staking/LPToken.sol 46: function mint(address _recipient, uint256 _amount) external onlyDeployer { // @audit-qa NatSpec File: contracts/liquid-staking/LPToken.sol 51: function burn(address _recipient, uint256 _amount) external onlyDeployer { // @audit-qa NatSpec File: contracts/liquid-staking/LPToken.sol 56: function liquidStakingManager() external view returns (address) { // @audit-qa NatSpec File: contracts/liquid-staking/LPTokenFactory.sol 27: function deployLPToken( 28: address _deployer, 29: address _transferHookProcessor, 30: string calldata _tokenSymbol, 31: string calldata _tokenName 32: ) external returns (address) { // @audit-qa NatSpec File: contracts/liquid-staking/LSDNFactory.sol 73: function deployNewLiquidStakingDerivativeNetwork( // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 218: function deRegisterKnotFromSyndicate(bytes[] calldata _blsPublicKeys) external onlyDAO { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 239: function updateDAOAddress(address _newAddress) external onlyDAO { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 249: function updateDAORevenueCommission(uint256 _commissionPercentage) external onlyDAO { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 255: function updateTicker(string calldata _newTicker) external onlyDAO { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 267: function updateWhitelisting(bool _changeWhitelist) external onlyDAO returns (bool) { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 326: function withdrawETHForKnot(address _recipient, bytes calldata _blsPublicKeyOfKnot) external { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 356: function rotateNodeRunnerOfSmartWallet(address _current, address _new, bool _wasPreviousNodeRunnerMalicious) external { // @audit-qa NatSpec File: contracts/liquid-staking/LiquidStakingManager.sol 635: function getNetworkFeeRecipient() external view returns (address) { // @audit-qa NatSpec File: contracts/liquid-staking/OptionalGatekeeperFactory.sol 11: function deploy(address _liquidStakingManager) external returns (OptionalHouseGatekeeper) { // @audit-qa NatSpec File: contracts/liquid-staking/OptionalHouseGatekeeper.sol 19: function isMemberPermitted(bytes calldata _blsPublicKeyOfKnot) external override view returns (bool) { // @audit-qa NatSpec File: contracts/liquid-staking/SavETHVault.sol 22: event ETHWithdrawnForStaking(address withdrawalAddress, address liquidStakingManager, uint256 amount); // @audit-qa NatSpec File: contracts/liquid-staking/SavETHVault.sol 45: function init(address _liquidStakingManagerAddress, LPTokenFactory _lpTokenFactory) external virtual initializer { // @audit-qa NatSpec File: contracts/liquid-staking/SavETHVault.sol 218: function isBLSPublicKeyPartOfLSDNetwork(bytes calldata _blsPublicKeyOfKnot) public virtual view returns (bool) { // @audit-qa NatSpec File: contracts/liquid-staking/SavETHVault.sol 223: function isBLSPublicKeyBanned(bytes calldata _blsPublicKeyOfKnot) public view returns (bool) { // @audit-qa NatSpec File: contracts/liquid-staking/SavETHVault.sol 228: function isDETHReadyForWithdrawal(address _lpTokenAddress) external view returns (bool) { // @audit-qa NatSpec File: contracts/liquid-staking/SavETHVaultDeployer.sol 18: function deploySavETHVault(address _liquidStakingManger, address _lpTokenFactory) external returns (address) { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 46: function init(address _liquidStakingNetworkManager, LPTokenFactory _lpTokenFactory) external virtual initializer { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 113: function depositETHForStaking(bytes calldata _blsPublicKeyOfKnot, uint256 _amount) public payable returns (uint256) { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 199: function claimRewards( 200: address _recipient, 201: bytes[] calldata _blsPubKeys 202: ) external nonReentrant { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 255: function unstakeSyndicateSharesForRageQuit( 256: address _sETHRecipient, 257: bytes[] calldata _blsPublicKeys, 258: uint256[] calldata _amounts 259: ) external onlyManager nonReentrant { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 274: function batchPreviewAccumulatedETHByBLSKeys(address _user, bytes[] calldata _blsPubKeys) external view returns (uint256) { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 284: function batchPreviewAccumulatedETH(address _user, LPToken[] calldata _token) external view returns (uint256) { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 293: function previewAccumulatedETH(address _user, LPToken _token) public view returns (uint256) { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 315: function beforeTokenTransfer(address _from, address _to, uint256) external override { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVault.sol 343: function afterTokenTransfer(address, address _to, uint256) external override { // @audit-qa NatSpec File: contracts/liquid-staking/StakingFundsVaultDeployer.sol 18: function deployStakingFundsVault(address _liquidStakingManager, address _tokenFactory) external returns (address) { // @audit-qa NatSpec File: contracts/liquid-staking/SyndicateRewardsProcessor.sol 93: function totalRewardsReceived() public virtual view returns (uint256) { // @audit-qa NatSpec File: contracts/smart-wallet/OwnableSmartWalletFactory.sol 28: function createWallet() external returns (address wallet) { // @audit-qa NatSpec File: contracts/smart-wallet/OwnableSmartWalletFactory.sol 32: function createWallet(address owner) external returns (address wallet) { // @audit-qa NatSpec
There are some typos in the comments.
--- a/contracts/liquid-staking/ETHPoolLPFactory.sol +++ b/contracts/liquid-staking/ETHPoolLPFactory.sol @@ -71,7 +71,7 @@ abstract contract ETHPoolLPFactory is StakehouseAPI { /// @notice Allow users to rotate the ETH from one LP token to another in the event that the BLS key is never staked /// @param _oldLPToken Instance of the old LP token (to be burnt) - /// @param _newLPToken Instane of the new LP token (to be minted) + /// @param _newLPToken Instance of the new LP token (to be minted) /// @param _amount Amount of LP tokens to be rotated/converted from old to new function rotateLPTokens(LPToken _oldLPToken, LPToken _newLPToken, uint256 _amount) public { require(address(_oldLPToken) != address(0), "Zero address"); @@ -121,7 +121,7 @@ abstract contract ETHPoolLPFactory is StakehouseAPI { // total supply after minting the LP token must not exceed maximum staking amount per validator require(lpToken.totalSupply() + _amount <= maxStakingAmountPerValidator, "Amount exceeds the staking limit for the validator"); - // mint LP tokens for the depoistor with 1:1 ratio of LP tokens and ETH supplied + // mint LP tokens for the depositor with 1:1 ratio of LP tokens and ETH supplied lpToken.mint(msg.sender, _amount); emit LPTokenMinted(_blsPublicKeyOfKnot, address(lpToken), msg.sender, _amount); } @@ -147,7 +147,7 @@ abstract contract ETHPoolLPFactory is StakehouseAPI { lpTokenForKnot[_blsPublicKeyOfKnot] = newLPToken; KnotAssociatedWithLPToken[newLPToken] = _blsPublicKeyOfKnot; - // mint LP tokens for the depoistor with 1:1 ratio of LP tokens and ETH supplied + // mint LP tokens for the depositor with 1:1 ratio of LP tokens and ETH supplied newLPToken.mint(msg.sender, _amount); emit NewLPTokenIssued(_blsPublicKeyOfKnot, address(newLPToken), msg.sender, _amount); } --- a/contracts/liquid-staking/LiquidStakingManager.sol +++ b/contracts/liquid-staking/LiquidStakingManager.sol @@ -98,7 +98,7 @@ contract LiquidStakingManager is ILiquidStakingManager, Initializable, Reentranc /// @notice address of the DAO deploying the contract address public dao; - /// @notice address of optional gatekeeper for admiting new knots to the house created by the network + /// @notice address of optional gatekeeper for admitting new knots to the house created by the network OptionalHouseGatekeeper public gatekeeper; /// @notice instance of the syndicate factory that deploys the syndicates @@ -473,7 +473,7 @@ contract LiquidStakingManager is ILiquidStakingManager, Initializable, Reentranc "Lifecycle status must be zero" ); - // register validtor initals for each of the KNOTs + // register validator initals for each of the KNOTs --- a/contracts/liquid-staking/SavETHVault.sol +++ b/contracts/liquid-staking/SavETHVault.sol @@ -112,7 +112,7 @@ contract SavETHVault is Initializable, ETHPoolLPFactory, ReentrancyGuard { function burnLPTokens(LPToken[] calldata _lpTokens, uint256[] calldata _amounts) external { uint256 numOfTokens = _lpTokens.length; require(numOfTokens > 0, "Empty arrays"); - require(numOfTokens == _amounts.length, "Inconsisent array length"); + require(numOfTokens == _amounts.length, "Inconsistent array length"); --- a/contracts/smart-wallet/OwnableSmartWallet.sol +++ b/contracts/smart-wallet/OwnableSmartWallet.sol @@ -8,9 +8,9 @@ import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.s import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /// @title Ownable smart wallet -/// @notice Ownable and transferrable smart wallet that allows the owner to +/// @notice Ownable and transferable smart wallet that allows the owner to /// interact with any contracts the same way as from an EOA. The -/// main intended use is to make non-transferrable positions and assets +/// main intended use is to make non-transferable positions and assets --- a/contracts/syndicate/Syndicate.sol +++ b/contracts/syndicate/Syndicate.sol @@ -279,7 +279,7 @@ contract Syndicate is ISyndicateInit, Initializable, Ownable, ReentrancyGuard, S } } - /// @notice Claim ETH cashflow from the syndicate as an sETH staker proportional to how much the user has staked + /// @notice Claim ETH cash flow from the syndicate as an sETH staker proportional to how much the user has staked /// @param _recipient Address that will receive the share of ETH funds /// @param _blsPubKeys List of BLS public keys that the caller has staked against function claimAsStaker(address _recipient, bytes[] calldata _blsPubKeys) public nonReentrant { @@ -395,7 +395,7 @@ contract Syndicate is ISyndicateInit, Initializable, Ownable, ReentrancyGuard, S return userShare - sETHUserClaimForKnot[_blsPubKey][_staker]; } - /// @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 + /// @notice Preview the amount of unclaimed ETH available for a collateralized SLOT staker against a KNOT which factors in unprocessed rewards from new ETH sent to contract /// @param _staker Address of a collateralized SLOT owner for a KNOT /// @param _blsPubKey BLS public key of the KNOT that is registered with the syndicate function previewUnclaimedETHAsCollateralizedSlotOwner( @@ -487,7 +487,7 @@ contract Syndicate is ISyndicateInit, Initializable, Ownable, ReentrancyGuard, S emit ContractDeployed(); } - /// 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) + /// Given an amount of ETH allocated to the collateralized SLOT owners of a KNOT, distribute this among the current set of collateralized owners (a dynamic set of addresses and balances) function _updateCollateralizedSlotOwnersLiabilitySnapshot(bytes memory _blsPubKey) internal { // Establish how much new ETH is for the new KNOT uint256 unprocessedETHForCurrentKnot = @@ -651,7 +651,7 @@ contract Syndicate is ISyndicateInit, Initializable, Ownable, ReentrancyGuard, S uint256 unclaimedUserShare = calculateUnclaimedFreeFloatingETHShare(_blsPubKey, msg.sender); - // this means that user can call the funtion even if there is nothing to claim but the + // this means that user can call the function even if there is nothing to claim but the
#0 - c4-judge
2022-12-02T19:54:13Z
dmvt marked the issue as grade-b