# Understanding Reentrancy

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

Reentrancy, a term originating from computer science, refers to a situation where a piece of code can be interrupted and run again before its previous execution has completed. In the context of smart contracts and blockchain, a reentrancy attack is a kind of malicious action which allows an attacker to repeatedly call a function of a smart contract before the first function call has ended, potentially draining funds or causing other harm. To fully grasp the complexities of reentrancy, let's unpack this concept step by step.

**Smart Contracts and Function Calls**

A smart contract is a self-executing contract with the terms of the agreement directly written into lines of code. Ethereum was the first blockchain to introduce smart contracts. These are autonomous scripts deployed on the Ethereum network that automatically execute transactions if certain conditions are met.

**Function calls and external interactions**&#x20;

When interacting with smart contracts, external accounts (like a user's wallet) or other smart contracts can trigger functions within the contract.

For example&#x20;

Let's explore a scenario where we have two smart contracts: `ContractA` and `ContractB`. In this scenario, `ContractA` wants to trigger a function within `ContractB`.

Here is what our `ContractB` might look like:

```
pragma solidity ^0.8.7;

// This is ContractB
contract ContractB {
    uint public data;

    function setData(uint _data) public {
        data = _data;
    }
}
```

`ContractB` is straightforward, and it just contains a public variable `data` and a function `setData` which updates the `data` variable.

Next, let's take a look at `ContractA`, which will interact with `ContractB`.

```
pragma solidity ^0.8.7;

// This is ContractA
contract ContractA {
    address contractBAddress;

    constructor(address _contractBAddress) {
        contractBAddress = _contractBAddress;
    }

    function callSetDataOnContractB(uint _data) public {
        // Creating an instance of ContractB
        ContractB contractB = ContractB(contractBAddress);
        // Now we can call setData on ContractB
        contractB.setData(_data);
    }
}

```

In `ContractA`, we store the address of `ContractB` in a variable `contractBAddress`. In the `callSetDataOnContractB` function, we create an instance of `ContractB` using the stored address. Now we can call the `setData` function of `ContractB` directly from `ContractA`.

The key to making this interaction is that `ContractA` must have the address of `ContractB`. This address is how it knows where to send the function call in the Ethereum network. Moreover, it needs to know the interface of `ContractB` (i.e., the function signatures of `ContractB`), so it knows what functions it can call and what parameters they require. This is why we can see `ContractB`'s `setData` function being called within `ContractA` with the correct number and type of parameters.

This example shows a simple interaction between two contracts, but it demonstrates how one contract can trigger functions within another contract.\
\
&#x20;A function is a piece of code designed to perform a specific task. For instance, a smart contract managing a digital wallet might have functions to deposit or withdraw funds.

One key feature of smart contracts is that they can interact with other smart contracts by calling their functions. Such an interaction is an external call. A function in smart contract A can call a function in smart contract B, causing the code in B to execute.

#### The Crux of Reentrancy Attacks

Reentrancy attacks exploit the potential vulnerability in the order of operations in smart contracts, particularly when a function calls an external contract and then continues to execute.

In a reentrancy attack, a malicious contract manipulates the control flow of the contract by causing it to execute certain parts of its code multiple times, changing its state in unexpected ways. This occurs when a function of the vulnerable contract, in the midst of its execution, calls another function (possibly external), which in return calls the original function, creating a loop.\
\
**Example**

Let's imagine there is a bank-like contract that allows users to deposit and withdraw Ether. This contract might look something like this:

```
pragma solidity ^0.8.7;

contract VulnerableBank {
    mapping (address => uint) private balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance");

        (bool success, ) = msg.sender.call{value: _amount}("");
        require(success, "Transfer failed");

        balances[msg.sender] -= _amount;
    }

    function getBalance() public view returns (uint) {
        return balances[msg.sender];
    }
}
```

The `VulnerableBank` contract has three main functions:

1. `deposit()`: Allows a user to deposit ether. The ether sent with the transaction (`msg.value`) is added to the sender's (`msg.sender`) balance.
2. `withdraw(uint _amount)`: Allows a user to withdraw ether. It first checks whether the user has sufficient balance. Then, it sends the specified `_amount` of ether to the sender. If the ether transfer is successful, it subtracts the `_amount` from the sender's balance.
3. `getBalance()`: Allows a user to check their balance.

Now, let's say there is a malicious actor who wants to exploit the `withdraw` function using a reentrancy attack. They could create a malicious contract that looks like this:

```
pragma solidity ^0.8.7;

contract MaliciousContract {
    VulnerableBank public vulnerableBank;
    
    constructor(address _vulnerableBankAddress) {
        vulnerableBank = VulnerableBank(_vulnerableBankAddress);
    }
    
    // Fallback function which is called whenever the contract receives ether
    fallback() external payable {
        if (address(vulnerableBank).balance >= 1 ether) {
            vulnerableBank.withdraw(1 ether);
        }
    }
    
    // Initial function to start the attack
    function attack() external payable {
        require(msg.value >= 1 ether);
        vulnerableBank.deposit{value: 1 ether}();
        vulnerableBank.withdraw(1 ether);
    }
}
```

1. `VulnerableBank public vulnerableBank;`: This line declares a state variable `vulnerableBank` of the type `VulnerableBank`, which is the contract to be attacked. The `public` keyword allows this variable to be read from outside the contract.
2. `constructor(address _vulnerableBankAddress) {`: This line defines the constructor function for the `MaliciousContract`. The constructor function is called when the contract is deployed. This constructor takes one parameter: the address of the `VulnerableBank` contract.
3. `vulnerableBank = VulnerableBank(_vulnerableBankAddress);`: This line casts the address `_vulnerableBankAddress` to type `VulnerableBank` and assigns it to `vulnerableBank`. This allows `MaliciousContract` to interact with the `VulnerableBank` contract using this variable.
4. `fallback() external payable {`: This line defines the fallback function of the contract. It is marked as `external`, meaning it can be called from outside the contract, and
5. `function attack() external payable {`: This line defines a new function named `attack`. It is marked as `external`, so it can be called from outside the contract, and `payable`, so it can receive Ether.
6. `require(msg.value >= 1 ether);`: This line checks if the incoming transaction (the one calling `attack`) includes at least 1 ether. If it doesn't, the function will revert and stop executing.
7. `vulnerableBank.deposit{value: 1 ether}();`: This line deposits 1 ether into the `VulnerableBank` contract by calling its `deposit` function. The `value: 1 ether` syntax specifies that 1 ether should be sent with this function call.
8. `vulnerableBank.withdraw(1 ether);`: This line withdraws 1 ether from the `VulnerableBank` contract. If the `VulnerableBank` contract is vulnerable to reentrancy attacks, this will trigger the fallback function in the `MaliciousContract`, potentially starting a cycle of reentrant calls that could drain the `VulnerableBank` contract's balance.

Let's dissect the malicious contract and the reentrancy attack step-by-step:

1. **Initialization**: The attacker deploys the `MaliciousContract` and provides the address of the `VulnerableBank` contract during the deployment (passed as `_vulnerableBankAddress` to the constructor).
2. **Start of Attack**: The attacker triggers the attack by calling the `attack` function and sends along 1 Ether. The function does two things: It first deposits 1 Ether to the `VulnerableBank` contract (via `vulnerableBank.deposit{value: 1 ether}();`) thereby increasing the attacker's balance in the `VulnerableBank`. Next, it attempts to withdraw the same 1 Ether (via `vulnerableBank.withdraw(1 ether);`).
3. **First Withdrawal Attempt**: When the `withdraw` function is called, the `VulnerableBank` contract checks whether the attacker has enough balance. Since we've just deposited 1 Ether, this check passes. Next, the contract attempts to send the 1 Ether back to the attacker's contract.
4. **Fallback Function**: As soon as the `MaliciousContract` receives the Ether, its fallback function is triggered. If there's more than 1 Ether left in the `VulnerableBank` contract, it calls the `withdraw` function again.
5. **Second Withdrawal Attempt**: Now, back in the `VulnerableBank` contract, the `withdraw` function starts its execution again. It checks whether the attacker has enough balance. As the balance has not yet been updated from the previous withdrawal (because the execution hasn't completed yet), this check still sees the original 1 Ether balance and passes. The contract sends another Ether to the `MaliciousContract`.
6. **Loop Continues**: Steps 4 and 5 repeat, causing the fallback function to repeatedly call the `withdraw` function before the `VulnerableBank` contract can update its state. This is the loop that drains Ether from the `VulnerableBank` contract. Each loop withdraws 1 Ether from the `VulnerableBank` and adds it to the `MaliciousContract`.
7. **End of Attack**: The attack continues as long as there's at least 1 Ether left in the `VulnerableBank` contract. Once the balance drops below 1 Ether, the conditional check in the fallback function of `MaliciousContract` fails, breaking the loop. By the end of the attack, the `VulnerableBank` is drained of its Ether, and the balance recorded in the `VulnerableBank` for the attacker is much higher than what's actually left in the contract.

This example illustrates how reentrancy attacks take advantage of the order of operations in a contract, manipulating the contract to perform actions repeatedly before it can update its state.



<figure><img src="https://2435636835-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5BID0P7sbZpVTEKkwMbp%2Fuploads%2FlG7dHCeTFPI2yhg1whjd%2Freentrancy-attacks.png?alt=media&#x26;token=c1e48e77-b084-4c7b-b30d-b55ffcd0a904" alt=""><figcaption><p>DAO Here just referes to out bank contract</p></figcaption></figure>

**Why does this happen?**

In Solidity (and many other programming languages), when a function calls another function, control is passed to the called function. This means that until the called function finishes executing and returns, the calling function is paused and waits for the completion of the called function.

This concept is also true when the function is not just a different function within the same contract, but a function from an entirely different contract. So when a contract function calls another contract's function, the control flow is passed to that other contract until the function finishes executing.

In the context of reentrancy attacks, this transfer of control flow becomes significant. If the called function is part of a malicious contract and it manages to call back into the original calling contract before it finishes execution, it can potentially exploit vulnerabilities and manipulate the state of the original contract.

For instance, if the original contract's function was supposed to decrease the balance of an account after it has transferred funds to that account, but the malicious contract calls back into the original contract before it finishes execution, the balance might not be decreased as intended. The malicious contract can continue this loop of calling the original contract's function to drain all the funds.

That's why it's crucial to manage the order of operations in smart contracts correctly, especially in the context of calls to other contracts, to avoid potential reentrancy attacks.
