# RACE #11 - Staking

{% embed url="<https://ventral.digital/posts/2022/10/31/race-11-of-the-secureum-bootcamp-epoch>" %}
RACE #11
{% endembed %}

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2F4WYHRbuxGA72xeaZpqfL%2Fimage.png?alt=media&#x26;token=87eaf578-0d92-4cb1-92b4-7c4e07c490d4" alt=""><figcaption><p>RACE #11 result</p></figcaption></figure>

{% hint style="info" %}
*Note: All 8 questions in this RACE are based on the below contract. This is the same contract you will see for all the 8 questions in this RACE. The question is below the shown contract.*
{% endhint %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";


contract Staking {

   using SafeERC20 for IERC20;

   bool internal _paused;
   address internal _operator;
   address internal _governance;
   address internal _token;
   uint256 internal _minDepositLockTime;

   mapping(address => uint256) _userBalances;
   mapping(address => uint256) _userLastDeposit;

   event Deposit(
       address indexed user,
       uint256 amount
   );

   event Withdraw(
       address indexed user,
       uint256 amount
   );

   constructor(address operator, address governance, address token, uint256 minDepositLockTime) {
       _operator = operator;
       _governance = governance;
       _token = token;
       _minDepositLockTime = minDepositLockTime;
   }

   function depositFor(address user, uint256 amount) external {
       _userBalances[user] += amount;
       _userLastDeposit[user] = block.timestamp;

       IERC20(_token).safeTransferFrom(user, address(this), amount);

       emit Deposit(msg.sender, amount);
   }

   function withdraw(uint256 amount) external {
       require(!_paused, 'paused');
       require(block.timestamp >= _userLastDeposit[msg.sender] + _minDepositLockTime, 'too early');

       IERC20(_token).safeTransferFrom(address(this), msg.sender, amount);

       if (_userBalances[msg.sender] >= amount) {
           _userBalances[msg.sender] -= amount;
       } else {
           _userBalances[msg.sender] = 0;
       }

       emit Withdraw(msg.sender, amount);
   }

   function pause() external {
       // operator or gov
       require(msg.sender == _operator && msg.sender == _governance, 'unauthorized');

       _paused = true;
   }

   function unpause() external {
       // only gov
       require(msg.sender == _governance, 'unauthorized');

       _paused = false;
   }

   function changeGovernance(address governance) external {
       _governance = governance;
   }
}
```

## Question 1 :white\_check\_mark:

Which statements are true in *withdraw()*?

* [ ] &#x20;A. Can be successfully executed when contract is paused -> `require(!_paused, 'paused')`
* [ ] &#x20;B. User can withdraw only after *\_minDepositLockTime* elapsed since last withdrawal -> "since last deposit", not "withdrawal"
* [ ] &#x20;C. Follows checks-effects-interaction pattern best practice
* [x] &#x20;D. User can withdraw more than deposited -> if `amount` is huge, that amount of tokens still will be sent via `safeTransferFrom()` and `_userBalances[msg.sender] = 0` is set after the transfer

## Question 2 :white\_check\_mark:

Which mitigations are applicable to *withdraw()*?

* [x] &#x20;A. Transferred amount should be minimum of *amount* and *\_userBalances\[msg.sender]*
* [ ] &#x20;B. Move *if/else* block before *safeTransferFrom ->* But user can still withdraw more than `_userBalances[msg.sender]`
* [x] &#x20;C. Require *amount* to be *<=* user’s balance deposited earlier
* [x] &#x20;D. Remove *if/else* block and add *\_userBalances\[msg.sender] -= amount* before *safeTransferFrom ->* If `amount` is larger than user's balance then tx will revert

## Question 3 :white\_check\_mark:

The security concern(s) in *pause()* is/are:

* [x] &#x20;A. Does not emit an event
* [ ] &#x20;B. Access control is not strict enough
* [ ] &#x20;C. Will always revert
* [ ] &#x20;D. None of the above

## Question 4 :white\_check\_mark:

Which statement(s) is/are true for *unpause()*?

* [ ] &#x20;A. Will unpause deposits and withdrawals
* [x] &#x20;B. Will unpause withdrawals only
* [x] &#x20;C. Anyone can successfully call the function
* [ ] &#x20;D. None of the above

## Question 5 :white\_check\_mark:

Which statement(s) is/are true in *depositFor()*?

* [x] &#x20;A. Can be executed when contract is paused
* [x] &#x20;B. Allows a user to deposit for another user
* [ ] &#x20;C. Allows a user to fund the deposit for another user
* [ ] &#x20;D. None of the above

## Question 6 :white\_check\_mark:

The issue(s) in *depositFor()* is/are:

* [x] &#x20;A. Cannot be paused for emergency
* [ ] &#x20;B. Exploitable re-entrancy attack
* [x] &#x20;C. User withdrawals can be delayed indefinitely via DoS attack -> Attacker can call `depositFor(user, 0)` over and over
* [ ] &#x20;D. None of the above

## Question 7 :white\_check\_mark:

Which of the following statement(s) is/are true?

* [ ] &#x20;A. Withdraw event is emitted with incorrect amount
* [x] &#x20;B. Withdraw event is emitted with correct user
* [ ] &#x20;C. Deposit event is always emitted incorrectly -> Not always, because `msg.sender` could be `user`
* [x] &#x20;D. Deposit event is emitted with incorrect user

## Question 8 :white\_check\_mark:

Potential gas optimization(s) is/are:

* [ ] &#x20;A. Use *immutable* for all variables assigned in constructor -> `_governance` should be mutable
* [x] &#x20;B. Use *immutable* for *\_token*, *\_operator* and *\_minDepositLockTime*
* [x] &#x20;C. Use *unchecked*
* [ ] &#x20;D. None of the above
