Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: medium
Invalid

contracts/core/test/RewardsPoolControllerMock.sol

The provided Solidity code is a mock implementation of a rewards pool controller that allows users to stake tokens and withdraw them. However, there are several potential vulnerabilities and issues you should consider:

  1. Underflow/Overflow Issues:

    • Although Solidity 0.8.x has built-in overflow and underflow checks, you should still ensure that the _amount passed to withdraw does not exceed the user's stakeBalances. If a user attempts to withdraw more than they have staked, it will revert, but it may be worth adding explicit checks for better clarity.

    require(stakeBalances[msg.sender] >= _amount, "Insufficient balance");
  2. Reentrancy Vulnerability:

    • The withdraw function transfers tokens to the user after updating the state. This opens up a potential reentrancy attack, where a malicious user could call withdraw recursively before the state is updated. To mitigate this, you can use the Checks-Effects-Interactions pattern:

    function withdraw(uint256 _amount) external updateRewards(msg.sender) {
    require(stakeBalances[msg.sender] >= _amount, "Insufficient balance");
    // Update state before transferring tokens
    stakeBalances[msg.sender] -= _amount;
    stakedTotal -= _amount;
    // Transfer tokens after state change
    token.safeTransfer(msg.sender, _amount);
    }
  3. Initial State Setup:

    • The constructor calls _disableInitializers(), which is a pattern to prevent initialization in the proxy contracts but can lead to confusion. Ensure that the initialization function is called correctly in your test environment.

  4. Potential Gas Issues:

    • If the mapping stakeBalances grows large, withdraw could consume significant gas if many operations need to be executed. Consider implementing a mechanism to manage large arrays or mappings effectively.

  5. Lack of Events:

    • It is a best practice to emit events when tokens are staked or withdrawn. This not only provides transparency but also aids in debugging and tracking activity on the contract.

    event Staked(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    function stake(uint256 _amount) external updateRewards(msg.sender) {
    ...
    emit Staked(msg.sender, _amount);
    }
    function withdraw(uint256 _amount) external updateRewards(msg.sender) {
    ...
    emit Withdrawn(msg.sender, _amount);
    }
  6. No Access Control:

    • The initialize function does not implement any access control, which may be okay in a mock contract but should be addressed in production contracts. Consider using onlyOwner or another modifier to restrict initialization to specific addresses.

  7. Token Approval:

    • The contract assumes that the caller has already approved the contract to spend _amount of tokens. Ensure that the frontend or calling contracts manage token approvals correctly to avoid failed transactions.

  8. Handling of updateRewards Modifier:

    • Since the updateRewards modifier is not shown in the provided code, ensure that it does not introduce vulnerabilities, such as unintended side effects or access control issues.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.