# 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="/files/0G1BiPHt6b3n1OANHzvz" 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfnote/web3-security-research/secureum/epoch-infinity/race-11-staking.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
