The provided Solidity code for the LSTRewardsSplitter
contract is generally well-structured, but there are a few potential vulnerabilities and areas for improvement that you should consider:
Arithmetic Underflow/Overflow:
The contract uses arithmetic operations like subtraction and addition on uint256
types. Although Solidity 0.8.x includes built-in overflow and underflow checks, you should ensure that you're aware of the potential for failures in certain scenarios, especially in functions like withdraw
and the _splitRewards
method where amounts are being decremented and could potentially lead to an underflow.
Reward Calculation:
In the performUpkeep
and splitRewards
functions, if newRewards
is negative (which indicates that the balance of the contract is less than the principalDeposits
), the contract adjusts principalDeposits
without checks. This could lead to a negative principalDeposits
if newRewards
is significantly negative, which is a logical error since it would imply a greater withdrawal than deposits.
Reentrancy:
The contract does not use the ReentrancyGuard
modifier from OpenZeppelin, which is often a good practice when dealing with external calls (like transferring tokens). If the lst.safeTransfer
call in _splitRewards
or withdraw
can call back into the contract (e.g., if the receiver is a contract), it could lead to unexpected behavior or reentrancy attacks.
Fee Management:
The addFee
and updateFee
functions do not check if the new receiver address is zero. Adding a fee with a zero address would lead to a situation where fees cannot be processed properly.
Gas Limit in _splitRewards
:
The for loop in _splitRewards
does not check for gas limits. If the number of fees becomes very large, it could lead to out-of-gas exceptions during execution. Consider implementing a limit on the number of fees or using a batching mechanism.
Lack of Events for Fee Changes:
Adding events for fee addition and updates would enhance transparency and allow for better tracking of changes in the contract state.
Insufficient Validation in Fee Updates:
In the updateFee
function, you only check if the index is valid. You should also ensure that the new fee does not exceed the allowed total of 10,000 basis points after updating.
Constructor controller
Initialization:
The constructor assigns controller
to msg.sender
, but if the constructor is called by a contract that changes its address afterward, it may not function as expected. Consider whether the controller address should be explicitly passed to the constructor rather than using msg.sender
.
Use of Constants:
You can define 10000
as a constant for better readability and maintainability, especially since it is used multiple times.
Error Messages:
The revert error messages could be more informative. Instead of just "Fee does not exist," you could provide more context, such as the index that was provided.
Function Visibility:
Review the visibility of functions. While the performUpkeep
and splitRewards
functions are public, if they should only be called from specific contexts, consider adjusting their visibility.
Documentation:
While the code has some comments, more comprehensive documentation, especially for complex functions, can be beneficial for maintainability and understanding.
Upgradeability:
If you plan to make changes to the contract in the future, consider using a proxy pattern or upgradable contracts from OpenZeppelin to allow for upgrades without losing state.
While the LSTRewardsSplitter
contract appears to be a solid implementation, addressing the potential vulnerabilities and areas for improvement mentioned above can enhance its security and reliability. Always ensure to perform thorough testing and consider conducting an external audit for critical smart contracts, especially those handling financial transactions.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.