Liquid Staking

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

contracts/core/base/StakingRewardsPool.sol

Here is an analysis of potential vulnerabilities and improvement suggestions in your StakingRewardsPool smart contract:


1. UUPS Upgradeability Issues

  • Risk: Improper usage of UUPSUpgradeable could expose the contract to proxy hijacking.

  • Cause: If _authorizeUpgrade() is not properly protected, anyone might call the upgradeTo() function and upgrade the contract.

  • Mitigation:

    • Your _authorizeUpgrade() function uses onlyOwner, which is good. However, ensure that ownership management (like transferOwnership) is carefully monitored to avoid accidental or malicious ownership changes.

    • Additionally, make sure to disable initializers after initialization by calling _disableInitializers() to prevent re-initialization attacks.


2. Reentrancy Vulnerability in Transfers and Minting

  • Risk: There is no reentrancy guard on functions like _transfer, _mint, or transferSharesFrom.

  • Cause: If IERC20Upgradeable tokens call external contracts during transfers, a reentrancy attack could exploit balance inconsistencies.

  • Mitigation:

    • Add a reentrancy guard (nonReentrant modifier from OpenZeppelin).

    • Example:

      function transferShares(address _recipient, uint256 _sharesAmount)
      external nonReentrant returns (bool) {
      _transferShares(msg.sender, _recipient, _sharesAmount);
      return true;
      }

3. Insufficient Zero-Address Checks for Token Transfers

  • Risk: Some functions, such as _mintShares, rely on implicit logic when handling zero-address transfers.

  • Cause: For example, burning from or minting to the zero address could go unnoticed in transferShares.

  • Mitigation:

    • Make explicit zero-address checks consistent across the code.

    • Ensure that mint() calls and any internal logic cannot mistakenly treat zero addresses as valid operations.


4. Incorrect Dead Shares Initialization Logic

  • Risk: The logic around DEAD_SHARES may cause the system to misbehave.

  • Cause: In _mintShares(), you reduce _amount by DEAD_SHARES only during the first mint. If the first mint is very small, this could cause underflows or unexpected behavior.

  • Mitigation:

    • Add checks to ensure that DEAD_SHARES does not exceed the _amount being minted.

    • Example:

      require(_amount > DEAD_SHARES, "Amount must exceed dead shares");

5. Lack of Slippage Control in getSharesByStake()

  • Risk: There is no slippage protection when converting between staked tokens and shares.

  • Cause: _amount * totalShares / totalStaked() could result in minor inaccuracies due to rounding, creating unexpected slippage in the conversion.

  • Mitigation:

    • Add range validation to ensure that the conversion stays within an acceptable tolerance.

    • Alternatively, you can use fixed-point math libraries (like OpenZeppelin's SafeMath) to handle rounding more predictably.


6. Unhandled Decimal Precision Issues

  • Risk: If the underlying token has decimal precision issues, your getSharesByStake and getStakeByShares functions may yield inaccurate results.

  • Cause: If IERC20Upgradeable tokens have non-standard decimals (e.g., 6 or 18 decimals), calculations may become imprecise.

  • Mitigation:

    • Ensure that the contract adjusts the calculations by using the same decimal precision across all token types.


7. Potential Out-of-Gas Issues for Loops over Large Balances

  • Risk: Functions like _totalStaked() might become unreliable if they depend on iterating over large datasets.

  • Cause: This contract does not seem to have large loops now, but functions like totalSupply() or other future extensions could run into gas limitations.

  • Mitigation:

    • Ensure that _totalStaked() is optimized and avoids any unbounded loops.

    • Consider implementing batch processing if staked amounts grow over time.


8. ERC677 Compatibility Issues

  • Risk: ERC677 introduces an additional transferAndCall function, which could be exploited if a malicious contract is used as the recipient.

  • Cause: When transferAndCall is used, the recipient contract could trigger unexpected callbacks and potentially drain funds.

  • Mitigation:

    • Ensure proper validation of recipient contracts that can handle transferAndCall.

    • You could restrict its usage to only whitelisted contracts.


9. Front-Running Risks for Staking

  • Risk: If reward distributions are time-sensitive, front-runners could exploit the system by staking just before rewards are distributed and unstaking right after.

  • Mitigation:

    • Implement a lock-up period or cool-down period after staking to prevent immediate withdrawals.

    • Another solution is to use TWAP-based rewards (time-weighted average) to mitigate short-term stake fluctuations.


10. Access Control and Ownership Risks

  • Risk: If ownership is transferred to a malicious actor, they could perform unauthorized upgrades or tamper with the contract.

  • Mitigation:

    • Use a multi-signature wallet (like Gnosis Safe) to control ownership.

    • Monitor any calls to transferOwnership or renounceOwnership.


Summary of Recommendations:

  1. Add reentrancy guards to protect transfer and mint functions.

  2. Harden zero-address checks across the code.

  3. Ensure DEAD_SHARES logic doesn’t lead to underflows.

  4. Use slippage control to avoid rounding inaccuracies.

  5. Adjust calculations to handle decimal precision issues.

  6. Optimize _totalStaked and avoid unbounded loops.

  7. Validate ERC677 transferAndCall usage for security.

  8. Introduce lock-up periods to prevent front-running.

  9. Use a multi-sig wallet for ownership to prevent malicious upgrades.


Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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