msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: RocketRewardsPool - registerClaimer should check if a node is already disabled before decrementing rewards.pool.claim.interval.claimers.total.next
Severity: low

Description:
The other branch in `registerClaimer` does not check whether the provided `_claimerAddress` is already disabled (or invalid). This might lead to inconsistencies where `rewards.pool.claim.interval.claimers.total.next` is decremented because the caller provided an already deactivated address.\\nThis issue is flagged as `minor` since we have not found an exploitable version of this issue in the current codebase. However, we recommend safeguarding the implementation instead of relying on the caller to provide sane parameters. Registered Nodes cannot unregister, and Trusted Nodes are unregistered when they leave.\\n```\\nfunction registerClaimer(address \\_claimerAddress, bool \\_enabled) override external onlyClaimContract {\\n    // The name of the claiming contract\\n    string memory contractName = getContractName(msg.sender);\\n    // Record the block they are registering at\\n    uint256 registeredBlock = 0;\\n    // How many users are to be included in next interval\\n    uint256 claimersIntervalTotalUpdate = getClaimingContractUserTotalNext(contractName);\\n    // Ok register\\n    if(\\_enabled) {\\n        // Make sure they are not already registered\\n        require(getClaimingContractUserRegisteredBlock(contractName, \\_claimerAddress) == 0, "Claimer is already registered");\\n        // Update block number\\n        registeredBlock = block.number;\\n        // Update the total registered claimers for next interval\\n        setUint(keccak256(abi.encodePacked("rewards.pool.claim.interval.claimers.total.next", contractName)), claimersIntervalTotalUpdate.add(1));\\n    }else{\\n        setUint(keccak256(abi.encodePacked("rewards.pool.claim.interval.claimers.total.next", contractName)), claimersIntervalTotalUpdate.sub(1));\\n    }\\n    // Save the registered block\\n    setUint(keccak256(abi.encodePacked("rewards.pool.claim.contract.registered.block", contractName, \\_claimerAddress)), registeredBlock);\\n}\\n```\\n

Impact:

Recommended mitigation:
Ensure that `getClaimingContractUserRegisteredBlock(contractName, _claimerAddress)` returns `!=0` before decrementing the `.total.next`.
Vulnerability: RocketNetworkPrices - Price feed update lacks block number sanity check
Severity: low

Description:
Trusted nodes submit the RPL price feed. The function is called specifying a block number and the corresponding RPL price for that block. If a DAO vote goes through for that block-price combination, it is written to storage. In the unlikely scenario that a vote confirms a very high block number such as `uint(-1)`, all future price updates will fail due to the `require` check below.\\nThis issue becomes less likely the more active members the DAO has. Thus, it's considered a minor issue that mainly affects the initial bootstrapping process.\\n```\\n// Check block\\nrequire(\\_block > getPricesBlock(), "Network prices for an equal or higher block are set");\\n```\\n

Impact:

Recommended mitigation:
The function's `_block` parameter should be checked to prevent large block numbers from being submitted. This check could, e.g., specify that node operators are only allowed to submit price updates for a maximum of x blocks ahead of `block.number`.
Vulnerability: RocketDepositPool - Potential gasDoS in assignDeposits  Acknowledged
Severity: low

Description:
`assignDeposits` seems to be a gas heavy function, with many external calls in general, and few of them are inside the for loop itself. By default, `rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments()` returns `2`, which is not a security concern. Through a DAO vote, the settings key `deposit.assign.maximum` can be set to a value that exhausts the block gas limit and effectively deactivates the deposit assignment process.\\n```\\nfor (uint256 i = 0; i < rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments(); ++i) {\\n    // Get & check next available minipool capacity\\n```\\n

Impact:

Recommended mitigation:
The `rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments()` return value could be cached outside the loop. Additionally, a check should be added that prevents unreasonably high values.
Vulnerability: RocketNetworkWithdrawal - ETH dust lockup due to rounding errors
Severity: low

Description:
There's a potential `ETH` dust lockup when processing a withdrawal due to rounding errors when performing a division.\\n```\\nuint256 totalShare = rocketMinipoolManager.getMinipoolWithdrawalTotalBalance(msg.sender);\\nuint256 nodeShare = rocketMinipoolManager.getMinipoolWithdrawalNodeBalance(msg.sender);\\nuint256 userShare = totalShare.sub(nodeShare);\\n// Get withdrawal amounts based on shares\\nuint256 nodeAmount = 0;\\nuint256 userAmount = 0;\\nif (totalShare > 0) {\\n    nodeAmount = msg.value.mul(nodeShare).div(totalShare);\\n    userAmount = msg.value.mul(userShare).div(totalShare);\\n}\\n```\\n

Impact:

Recommended mitigation:
Calculate `userAmount` as `msg.value - nodeAmount` instead. This should also save some gas.
Vulnerability: RocketAuctionManager - calcBase should be declared constant
Severity: low

Description:
Declaring the same constant value `calcBase` multiple times as local variables to some methods in `RocketAuctionManager` carries the risk that if that value is ever updated, one of the value assignments might be missed. It is therefore highly recommended to reduce duplicate code and declare the value as a public constant. This way, it is clear that the same `calcBase` is used throughout the contract, and there is a single point of change in case it ever needs to be changed.\\n```\\nfunction getLotPriceByTotalBids(uint256 \\_index) override public view returns (uint256) {\\n    uint256 calcBase = 1 ether;\\n    return calcBase.mul(getLotTotalBidAmount(\\_index)).div(getLotTotalRPLAmount(\\_index));\\n}\\n```\\n\\n```\\nfunction getLotClaimedRPLAmount(uint256 \\_index) override public view returns (uint256) {\\n    uint256 calcBase = 1 ether;\\n    return calcBase.mul(getLotTotalBidAmount(\\_index)).div(getLotCurrentPrice(\\_index));\\n}\\n```\\n\\n```\\n// Calculation base value\\nuint256 calcBase = 1 ether;\\n```\\n\\n```\\nuint256 bidAmount = msg.value;\\nuint256 calcBase = 1 ether;\\n```\\n\\n```\\n// Calculate RPL claim amount\\nuint256 calcBase = 1 ether;\\nuint256 rplAmount = calcBase.mul(bidAmount).div(currentPrice);\\n```\\n

Impact:

Recommended mitigation:
Consider declaring `calcBase` as a private const state var instead of re-declaring it with the same value in multiple, multiple functions. Constant, literal state vars are replaced in a preprocessing step and do not require significant additional gas when accessed than normal state vars.
Vulnerability: RocketDAO* - daoNamespace is missing a trailing dot; should be declared constant/immutable
Severity: low

Description:
`string private daoNameSpace = 'dao.trustednodes'` is missing a trailing dot, or else there's no separator when concatenating the namespace with the vars.\\nrequests `dao.trustednodesmember.index` instead of `dao.trustednodes.member.index`\\n```\\nfunction getMemberAt(uint256 \\_index) override public view returns (address) {\\n    AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));\\n    return addressSetStorage.getItem(keccak256(abi.encodePacked(daoNameSpace, "member.index")), \\_index);\\n}\\n```\\n\\n```\\n// The namespace for any data stored in the trusted node DAO (do not change)\\nstring private daoNameSpace = 'dao.trustednodes';\\n```\\n\\n```\\n// Calculate using this as the base\\nuint256 private calcBase = 1 ether;\\n\\n// The namespace for any data stored in the trusted node DAO (do not change)\\nstring private daoNameSpace = 'dao.trustednodes';\\n```\\n\\n```\\n// The namespace for any data stored in the network DAO (do not change)\\nstring private daoNameSpace = 'dao.protocol';\\n```\\n

Impact:

Recommended mitigation:
Remove the `daoNameSpace` and add the prefix to the respective variables directly.
Vulnerability: RocketVault - consider rejecting zero amount deposit/withdrawal requests
Severity: low

Description:
Consider disallowing zero amount token transfers unless the system requires this to work. In most cases, zero amount token transfers will emit an event (that potentially triggers off-chain components). In some cases, they allow the caller without holding any balance to call back to themselves (pot. reentrancy) or the caller provided token address.\\n`depositEther` allows to deposit zero ETH\\nemits `EtherDeposited`\\n`withdrawEther` allows to withdraw zero ETH\\ncalls back to `withdrawer` (msg.sender)!\\nemits `EtherWithdrawn`\\n(depositToken checks for amount >0)\\n`withdrawToken` allows zero amount token withdrawals\\ncalls into user provided (actually a network contract) tokenAddress)\\nemits `TokenWithdrawn`\\n`transferToken` allows zero amount token transfers\\nemits `TokenTransfer`\\n```\\nfunction depositEther() override external payable onlyLatestNetworkContract {\\n    // Get contract key\\n    bytes32 contractKey = keccak256(abi.encodePacked(getContractName(msg.sender)));\\n    // Update contract balance\\n    etherBalances[contractKey] = etherBalances[contractKey].add(msg.value);\\n    // Emit ether deposited event\\n    emit EtherDeposited(contractKey, msg.value, block.timestamp);\\n}\\n```\\n

Impact:

Recommended mitigation:
Zero amount transfers are no-operation calls in most cases and should be avoided. However, as all vault actions are authenticated (to registered system contracts), the risk of something going wrong is rather low. Nevertheless, it is recommended to deny zero amount transfers to avoid running code unnecessarily (gas consumption), emitting unnecessary events, or potentially call back to callers/token address for ineffective transfers.
Vulnerability: RocketVault - methods returning static return values and unchecked return parameters
Severity: low

Description:
The `Token*` methods in `RocketVault` either throw or return `true`, but they can never return `false`. If the method fails, it will always throw. Therefore, it is questionable if the static return value is needed at all. Furthermore, callees are in most cases not checking the return value of\\nstatic return value `true`\\n```\\n// Emit token transfer\\nemit TokenDeposited(contractKey, \\_tokenAddress, \\_amount, block.timestamp);\\n// Done\\nreturn true;\\n```\\n\\n```\\nemit TokenWithdrawn(contractKey, \\_tokenAddress, \\_amount, block.timestamp);\\n// Done\\nreturn true;\\n```\\n\\n```\\n// Emit token withdrawn event\\nemit TokenTransfer(contractKeyFrom, contractKeyTo, \\_tokenAddress, \\_amount, block.timestamp);\\n// Done\\nreturn true;\\n```\\n\\nreturn value not checked\\n```\\nrocketVault.depositToken("rocketNodeStaking", rplTokenAddress, \\_amount);\\n// Update RPL stake amounts & node RPL staked block\\n```\\n\\n```\\nrocketVault.withdrawToken(msg.sender, getContractAddress("rocketTokenRPL"), rplAmount);\\n```\\n\\n```\\nrocketVault.withdrawToken(msg.sender, getContractAddress("rocketTokenRPL"), \\_amount);\\n```\\n\\n```\\nrocketVault.transferToken("rocketAuctionManager", getContractAddress("rocketTokenRPL"), rplSlashAmount);\\n```\\n

Impact:

Recommended mitigation:
Define a clear interface for these functions. Remove the static return value in favor of having the method throw on failure (which is already the current behavior).
Vulnerability: RocketMinipoolDelegate - enforce that the delegate contract cannot be called directly
Severity: low

Description:
This contract is not meant to be consumed directly and will only be delegate called from `Minipool`. Being able to call it directly might even create the problem that, in the worst case, someone might be able to `selfdestruct` the contract rendering all other contracts that link to it dysfunctional. This might even not be easily detectable because `delegatecall` to an EOA will act as a NOP.\\nThe access control checks on the methods currently prevent methods from being called directly on the delegate. They require state variables to be set correctly, or the delegate is registered as a valid minipool in the system. Both conditions are improbable to be fulfilled, hence, mitigation any security risk. However, it looks like this is more of a side-effect than a design decision, and we would recommend not explicitly stating that the delegate contract cannot be used directly.\\n```\\nconstructor(address \\_rocketStorageAddress) {\\n    // Initialise RocketStorage\\n    require(\\_rocketStorageAddress != address(0x0), "Invalid storage address");\\n    rocketStorage = RocketStorageInterface(\\_rocketStorageAddress);\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nAddressed in branch `rp3.0-updates` (rocket-pool/[email protected]b424ca1) by removing the constructor and therefore the initialization code from the RocketMinipoolDelegate contract. The contract cannot be used directly anymore as all relevant methods are decorated `onlyInitialised` and there is no way to initialize it in the implementation directly.\\nRemove the initialization from the constructor in the delegate contract. Consider adding a flag that indicates that the delegate contract is initialized and only set in the Minipool contract and not in the logic contract (delegate). On calls, check that the contract is initialized.
Vulnerability: Re-entrancy issue for ERC1155
Severity: high

Description:
ERC1155 tokens have callback functions on some of the transfers, like `safeTransferFrom`, `safeBatchTransferFrom`. During these transfers, the `IERC1155ReceiverUpgradeable(to).onERC1155Received` function is called in the `to` address.\\nFor example, `safeTransferFrom` is used in the `LiquidityMining` contract:\\n```\\nfunction distributeAllNFT() external {\\n    require(block.timestamp > getEndLMTime(),\\n        "2 weeks after liquidity mining time has not expired");\\n    require(!isNFTDistributed, "NFT is already distributed");\\n\\n    for (uint256 i = 0; i < leaderboard.length; i++) {\\n        address[] memory \\_groupLeaders = groupsLeaders[leaderboard[i]];\\n\\n        for (uint256 j = 0; j < \\_groupLeaders.length; j++) {\\n            \\_sendNFT(j, \\_groupLeaders[j]);\\n        }\\n    }\\n\\n    for (uint256 i = 0; i < topUsers.length; i++) {\\n        address \\_currentAddress = topUsers[i];\\n        LMNFT.safeTransferFrom(address(this), \\_currentAddress, 1, 1, "");\\n        emit NFTSent(\\_currentAddress, 1);\\n    }\\n\\n    isNFTDistributed = true;\\n}\\n```\\n\\nDuring that transfer, the `distributeAllNFT` function can be called again and again. So multiple transfers will be done for each user.\\nIn addition to that, any receiver of the tokens can revert the transfer. If that happens, nobody will be able to receive their tokens.

Impact:

Recommended mitigation:
Add a reentrancy guard.\\nAvoid transferring tokens for different receivers in a single transaction.
Vulnerability: Winning pods can be frontrun with large deposits
Severity: high

Description:
`Pod.depositTo()` grants users shares of the pod pool in exchange for `tokenAmount` of `token`.\\n```\\nfunction depositTo(address to, uint256 tokenAmount)\\n    external\\n    override\\n    returns (uint256)\\n{\\n    require(tokenAmount > 0, "Pod:invalid-amount");\\n\\n    // Allocate Shares from Deposit To Amount\\n    uint256 shares = \\_deposit(to, tokenAmount);\\n\\n    // Transfer Token Transfer Message Sender\\n    IERC20Upgradeable(token).transferFrom(\\n        msg.sender,\\n        address(this),\\n        tokenAmount\\n    );\\n\\n    // Emit Deposited\\n    emit Deposited(to, tokenAmount, shares);\\n\\n    // Return Shares Minted\\n    return shares;\\n}\\n```\\n\\nThe winner of a prize pool is typically determined by an off-chain random number generator, which requires a request to first be made on-chain. The result of this RNG request can be seen in the mempool and frontrun. In this case, an attacker could identify a winning `Pod` contract and make a large deposit, diluting existing user shares and claiming the entire prize.

Impact:

Recommended mitigation:
The modifier `pauseDepositsDuringAwarding` is included in the `Pod` contract but is unused.\\n```\\nmodifier pauseDepositsDuringAwarding() {\\n    require(\\n        !IPrizeStrategyMinimal(\\_prizePool.prizeStrategy()).isRngRequested(),\\n        "Cannot deposit while prize is being awarded"\\n    );\\n    \\_;\\n}\\n```\\n\\nAdd this modifier to the `depositTo()` function along with corresponding test cases.
Vulnerability: TokenDrop: Unprotected initialize() function
Severity: high

Description:
The `TokenDrop.initialize()` function is unprotected and can be called multiple times.\\n```\\nfunction initialize(address \\_measure, address \\_asset) external {\\n    measure = IERC20Upgradeable(\\_measure);\\n    asset = IERC20Upgradeable(\\_asset);\\n\\n    // Set Factory Deployer\\n    factory = msg.sender;\\n}\\n```\\n\\nAmong other attacks, this would allow an attacker to re-initialize any `TokenDrop` with the same `asset` and a malicious `measure` token. By manipulating the balance of a user in this malicious `measure` token, the entire `asset` token balance of the `TokenDrop` contract could be drained.

Impact:

Recommended mitigation:
Add the `initializer` modifier to the `initialize()` function and include an explicit test that every initialization function in the system can be called once and only once.
Vulnerability: Pod: Re-entrancy during deposit or withdrawal can lead to stealing funds
Severity: high

Description:
During the deposit, the token transfer is made after the Pod shares are minted:\\n```\\nuint256 shares = \\_deposit(to, tokenAmount);\\n\\n// Transfer Token Transfer Message Sender\\nIERC20Upgradeable(token).transferFrom(\\n    msg.sender,\\n    address(this),\\n    tokenAmount\\n);\\n```\\n\\nThat means that if the `token` allows re-entrancy, the attacker can deposit one more time inside the `token` transfer. If that happens, the second call will mint more tokens than it is supposed to, because the first `token` transfer will still not be finished. By doing so with big amounts, it's possible to drain the pod.

Impact:

Recommended mitigation:
Add re-entrancy guard to the external functions.
Vulnerability: TokenDrop: Re-entrancy in the claim function can cause to draining funds
Severity: high

Description:
If the `asset` token is making a call before the `transfer` to the `receiver` or to any other 3-d party contract (like it's happening in the `Pod` token using the `_beforeTokenTransfer` function), the attacker can call the `drop` function inside the `transfer` call here:\\n```\\nfunction claim(address user) external returns (uint256) {\\n    drop();\\n    \\_captureNewTokensForUser(user);\\n    uint256 balance = userStates[user].balance;\\n    userStates[user].balance = 0;\\n    totalUnclaimed = uint256(totalUnclaimed).sub(balance).toUint112();\\n\\n    // Transfer asset/reward token to user\\n    asset.transfer(user, balance);\\n\\n    // Emit Claimed\\n    emit Claimed(user, balance);\\n\\n    return balance;\\n}\\n```\\n\\nBecause the `totalUnclaimed` is already changed, but the current balance is not, the `drop` function will consider the funds from the unfinished transfer as the new tokens. These tokens will be virtually redistributed to everyone.\\nAfter that, the transfer will still happen, and further calls of the `drop()` function will fail because the following line will revert:\\n`uint256 newTokens = assetTotalSupply.sub(totalUnclaimed);`\\nThat also means that any transfers of the `Pod` token will fail because they all are calling the `drop` function. The `TokenDrop` will “unfreeze” only if someone transfers enough tokens to the `TokenDrop` contract.\\nThe severity of this issue is hard to evaluate because, at the moment, there's not a lot of tokens that allow this kind of re-entrancy.

Impact:

Recommended mitigation:
Simply adding re-entrancy guard to the `drop` and the `claim` function won't help because the `drop` function is called from the `claim`. For that, the transfer can be moved to a separate function, and this function can have the re-entrancy guard as well as the `drop` function.\\nAlso, it's better to make sure that `_beforeTokenTransfer` will not revert to prevent the token from being frozen.
Vulnerability: Pod: Having multiple token drops is inconsistent
Severity: medium

Description:
The `Pod` contract had the `drop` storage field and mapping of different TokenDrops `(token => TokenDrop)`. When adding a new `TokenDrop` in the mapping, the `drop` field is also changed to the added _tokenDrop:\\n```\\nfunction setTokenDrop(address \\_token, address \\_tokenDrop)\\n    external\\n    returns (bool)\\n{\\n    require(\\n        msg.sender == factory || msg.sender == owner(),\\n        "Pod:unauthorized-set-token-drop"\\n    );\\n\\n    // Check if target<>tokenDrop mapping exists\\n    require(\\n        drops[\\_token] == TokenDrop(0),\\n        "Pod:target-tokendrop-mapping-exists"\\n    );\\n\\n    // Set TokenDrop Referance\\n    drop = TokenDrop(\\_tokenDrop);\\n\\n    // Set target<>tokenDrop mapping\\n    drops[\\_token] = drop;\\n\\n    return true;\\n}\\n```\\n\\nOn the other hand, the `measure` token and the `asset` token of the `drop` are strictly defined by the Pod contract. They cannot be changed, so all `TokenDrops` are supposed to have the same `asset` and `measure` tokens. So it is useless to have different `TokenDrops`.

Impact:

Recommended mitigation:
The mapping seems to be unused, and only one `TokenDrop` will normally be in the system. If that code is not used, it should be deleted.
Vulnerability: Pod: Fees are not limited by a user during the withdrawal
Severity: medium

Description:
When withdrawing from the Pod, the shares are burned, and the deposit is removed from the Pod. If there are not enough deposit tokens in the contract, the remaining tokens are withdrawn from the pool contract:\\n```\\nif (amount > currentBalance) {\\n    // Calculate Withdrawl Amount\\n    uint256 \\_withdraw = amount.sub(currentBalance);\\n\\n    // Withdraw from Prize Pool\\n    uint256 exitFee = \\_withdrawFromPool(\\_withdraw);\\n\\n    // Add Exit Fee to Withdrawl Amount\\n    amount = amount.sub(exitFee);\\n}\\n```\\n\\nThese tokens are withdrawn with a fee from the pool, which is not controlled or limited by the user.

Impact:

Recommended mitigation:
Allow users to pass a `maxFee` parameter to control fees.
Vulnerability: Pod.setManager() checks validity of wrong address
Severity: low

Description:
The function `Pod.setManager()` allows the `owner` of the Pod contract to change the Pod's `manager`. It checks that the value of the existing `manager` in storage is nonzero. This is presumably intended to ensure that the `owner` has provided a valid `newManager` parameter in calldata.\\nThe current check will always pass once the contract is initialized with a nonzero `manager`. But, the contract can currently be initialized with a `manager` of `IPodManager(address(0))`. In this case, the check would prevent the `manager` from ever being updated.\\n```\\nfunction setManager(IPodManager newManager)\\n    public\\n    virtual\\n    onlyOwner\\n    returns (bool)\\n{\\n    // Require Valid Address\\n    require(address(manager) != address(0), "Pod:invalid-manager-address");\\n```\\n

Impact:

Recommended mitigation:
Change the check to:\\n```\\nrequire(address(newManager) != address(0), "Pod:invalid-manager-address");\\n```\\n\\nMore generally, attempt to define validity criteria for all input values that are as strict as possible. Consider preventing zero inputs or inputs that might conflict with other addresses in the smart contract system altogether, including in contract initialization functions.