# Examples

{% hint style="info" %}
[**Book an audit with Zokyo**](https://www.zokyo.io/)
{% endhint %}

{% hint style="info" %}
**Understanding the Examples**: In this section, we dive into practical instances of reentrancy vulnerabilities discovered in actual bug bounty reports, Code Arena analyses, and more. By examining these real-life scenarios, you'll attain a richer, more tangible comprehension of reentrancy attacks and their potential repercussions. This understanding will serve to bolster your smart contract auditing capabilities in a substantive and effective manner.
{% endhint %}

### **Example 1:  ERC721 \_checkOnERC721Received re-entrancy**&#x20;

{% embed url="<https://github.com/code-423n4/2022-01-xdefi-findings/issues/25>" %}

#### **1. The Core Functionality:**

The smart contract in question seems to be a kind of bank or vault that holds `XDEFI` tokens. Users can "lock" their `XDEFI` tokens in this contract for some duration and receive a unique token (an NFT) in return, representing their deposit.

#### **2. The Vulnerable Functions:**

**\_safeMint Function:** This function mints (or creates) a new token. However, before completing, it checks if the recipient can handle receiving this type of token through the `_checkOnERC721Received` function.

**\_checkOnERC721Received Function:** This function checks if the receiving address (of the minted token) is a contract and if it can properly handle the incoming token. If it is a contract, it will call the `onERC721Received` function on that contract.

**lock and \_lock Functions:** These functions handle the process of locking `XDEFI` tokens and creating the unique token (NFT) in return.

**updateDistribution Function:** This function updates the distribution of rewards based on the amount of `XDEFI` in the contract.

#### **3. The Problem:**

**Reentrancy Vulnerability:** After locking `XDEFI` tokens and before updating the total deposited amount (`totalDepositedXDEFI`), an external contract (a potentially malicious one) can be triggered due to the `_checkOnERC721Received` function. If this external contract then tries to interact again with our main contract, it might catch it in an inconsistent state because `totalDepositedXDEFI` hasn't been updated yet.

In simpler terms, think of it like a bank teller who gives out money to a customer but gets interrupted to perform another task before noting down the transaction. If this interruption can be manipulated, the customer might be able to exploit this situation.

**Impact:** An attacker can artificially inflate the `_pointsPerUnit` variable, making it abnormally large. This would then allow them to claim a lot more rewards than they should get. Moreover, they can potentially "unlock" and withdraw more assets than they deposited.

#### **4. Mitigation:**

To protect the smart contract from this vulnerability, a reentrancy guard or modifier should be added to functions. This ensures that once a function is being executed, it cannot be interrupted or "re-entered" until it's completed its tasks. It's like a bank teller saying, "Please wait for your current transaction to complete before initiating another one."

### Example 2: Double Re-entrancy guard&#x20;

{% embed url="<https://github.com/code-423n4/2021-10-defiprotocol/blob/7ca848f2779e2e64ed0b4756c02f0137ecd73e50/contracts/contracts/Basket.sol#L83-L88>" %}

When writing smart contracts, ensuring their security is of the utmost importance. In Solidity, the `nonReentrant` modifier is often used as a protective measure against reentrancy attacks. However, using it without a clear understanding can lead to unexpected behavior, as demonstrated in the example below.<br>

```
function mint(uint256 amount) public nonReentrant override {
    mintTo(amount, msg.sender);
}

function mintTo(uint256 amount, address to) public nonReentrant override {
    require(auction.auctionOngoing() == false);
    // ... Rest of the function implementation ...
}

```

In the code snippet above, we see that the `mint` function has a `nonReentrant` modifier, and it calls the `mintTo` function which **also** has a `nonReentrant` modifier. The issue here is that when the `mint` function is called, it will set the `_notEntered` state variable (used in a typical `nonReentrant` implementation) to `false`. Then, when it calls the `mintTo` function, this function will immediately fail because of its own `nonReentrant` check, seeing that `_notEntered` is `false`.

Effectively, this double use of `nonReentrant` makes the `mint` function unusable, as it will always result in an error when attempting to invoke the `mintTo` function.

#### Recommendation:

To avoid such malfunction and ensure that the contract behaves as expected, one should avoid stacking or nesting the `nonReentrant` modifier.

The corrected code should be:

```
function mint(uint256 amount) public override {
    mintTo(amount, msg.sender);
}

function mintTo(uint256 amount, address to) public nonReentrant override {
    require(auction.auctionOngoing() == false);
    // ... Rest of the function implementation ...
}
```

By removing the `nonReentrant` modifier from the `mint` function, we ensure that the guard is only applied once when `mintTo` is executed, allowing the functions to proceed without unnecessary errors.

#### Conclusion:

While guards like `nonReentrant` are powerful tools in a Solidity developer's toolkit, it's crucial to understand their underlying mechanism and use them appropriately. Misuse can lead to undesired behavior and potential vulnerabilities. Always ensure you know the consequences of the modifiers and other security mechanisms you apply.

### Example 3: Reentrancy Vulnerability in `sponsor()` function

{% embed url="<https://github.com/code-423n4/2022-01-sandclock-findings/issues/4>" %}

Security in smart contracts is a matter of utmost importance. Ensuring that functions are protected from malicious attacks is critical. One such vulnerability often overlooked is reentrancy attacks, and in this spotlight, we'll look at a real-world example of such an oversight.

#### Problematic Code:

Here is the problematic `sponsor()` function from the `Vault.sol` contract:

```
function sponsor(uint256 _amount, uint256 _lockedUntil)
    external
    override(IVaultSponsoring)
{
    if (_lockedUntil == 0)
        _lockedUntil = block.timestamp + MIN_SPONSOR_LOCK_DURATION;
    else
        require(
            _lockedUntil >= block.timestamp + MIN_SPONSOR_LOCK_DURATION,
            "Vault: lock time is too small"
        );

    uint256 tokenId = depositors.mint(
        _msgSender(),
        _amount,
        0,
        _lockedUntil
    );

    emit Sponsored(tokenId, _amount, _msgSender(), _lockedUntil);

    totalSponsored += _amount;
    _transferAndCheckUnderlying(_msgSender(), _amount);
}

```

The vulnerability arises due to the `depositors.mint()` function, which has a callback to the `msg.sender`. Since there are state updates (`totalSponsored` variable update and `Sponsored` event emission) after the external call to `depositors.mint()`, a malicious actor can exploit this to reenter the `sponsor()` function.

Effectively, an attacker can exploit this vulnerability by ensuring the `totalSponsored` amount is updated only once, even after calling `mint()` several times. The same issue will affect the `Sponsored` event, which will be emitted only once after the multiple reentries.

#### Recommendation:

To safeguard against this vulnerability, a reentrancy guard should be added to the `sponsor()` function. The typical pattern involves adding a state variable like `_status` which is checked at the beginning and end of the function to prevent reentrancy:

```
modifier nonReentrant() {
    require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
    _status = _ENTERED;
    _;
    _status = _NOT_ENTERED;
}
```

Now, add this `nonReentrant` modifier to the `sponsor()` function:

```
function sponsor(uint256 _amount, uint256 _lockedUntil)
    external
    override(IVaultSponsoring)
    nonReentrant
{
    // ... Rest of the function implementation ...
}
```

#### Conclusion:

Reentrancy vulnerabilities can lead to unexpected and unintended consequences if not adequately addressed. Developers should always be cautious about the order of state updates and external calls in their smart contracts and utilize tools like the reentrancy guard to ensure robust security.
