Beginner FriendlyFoundryDeFi
100 EXP
View results
Submission Details
Severity: medium
Invalid

Absence of Emergency Stop Mechanism.

Description:

The unstake function lacks an emergency stop mechanism, which is crucial for halting contract operations in case of an exploit or other urgent issues. Without this mechanism, it is difficult to stop the contract’s operations if a vulnerability is discovered, potentially locking funds or allowing further damage.

Impact:

The absence of an emergency stop mechanism means that if a critical vulnerability or exploit is found, the contract cannot be paused to prevent further damage or loss of funds. This could result in a prolonged period of exposure to risks or exploitation, impacting the security and stability of the protocol.

Proof of Concept:

To demonstrate this vulnerability, deploy the contract and simulate an exploit scenario. Without an emergency stop mechanism, even if a serious issue is detected, no immediate action can be taken to halt the contract and protect funds.

Recommended Mitigation:

Implement an emergency stop mechanism, such as a circuit breaker, to allow the contract owner or a designated authority to pause critical functions in the event of an exploit. This can be achieved by adding a paused state variable and modifying the relevant functions to check this state.

Here’s an example of how to implement it:

# Add state variable to track the paused status
+ paused: public(bool)
# Add modifier to check if contract is paused
+ @internal
+ def onlyWhenNotPaused():
+ assert not self.paused, "Contract is paused"
# Modify the unstake function to include the onlyWhenNotPaused check
@external
def unstake(_amount: uint256, _to: address):
"""
@notice Allows users to unstake their staked ETH before the staking period ends. Users
can adjust their staking amounts to their liking.
@param _amount The amount of staked ETH to withdraw.
@param _to The address to send the withdrawn ETH to.
"""
+ onlyWhenNotPaused() # Check if the contract is paused
assert not self._hasStakingPeriodEnded(), STEAK__STAKING_PERIOD_ENDED
assert _to != ADDRESS_ZERO, STEAK__ADDRESS_ZERO
stakedAmount: uint256 = self.usersToStakes[msg.sender]
assert stakedAmount > 0 and _amount > 0, STEAK__AMOUNT_ZERO
assert _amount <= stakedAmount, STEAK__INSUFFICIENT_STAKE_AMOUNT
self.usersToStakes[msg.sender] -= _amount
self.totalAmountStaked -= _amount
send(_to, _amount)
log Unstaked(msg.sender, _amount, _to)
# Add function to pause or unpause the contract
+ @external
+ def setPaused(_paused: bool):
+ """
+ @notice Allows the owner to pause or unpause the contract.
+ @param _paused The new paused state.
+ """
+ assert msg.sender == self.owner, STEAK__NOT_OWNER
+ self.paused = _paused
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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