> ## Documentation Index
> Fetch the complete documentation index at: https://docs.webacy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reentrancy

> Learn how reentrancy attacks like the DAO hack exploit external calls to drain smart contracts, and how to detect and prevent these vulnerabilities.

## Overview

A reentrancy attack is a serious vulnerability where a function calls an external contract, allowing that contract to make repeated calls back before execution completes.

<Warning>
  The DAO hack in 2016 exploited a reentrancy vulnerability, resulting in approximately \$60 million USD in losses.
</Warning>

## How It Works

The basic mechanism: **Contract A calls Contract B. The exploit allows B to call back into A before A finishes execution.**

### Attack Sequence

```mermaid theme={null}
sequenceDiagram
    participant Attacker
    participant Bank
    Attacker->>Bank: withdraw(10 ETH)
    Bank->>Bank: Check balance (10 ETH) ✓
    Bank->>Attacker: Send 10 ETH
    Attacker->>Bank: withdraw(10 ETH) [re-enter]
    Bank->>Bank: Check balance (still 10 ETH!) ✓
    Bank->>Attacker: Send 10 ETH
    Note over Attacker,Bank: Repeats until drained
```

### Step-by-Step Example

1. User initiates withdrawal from bank contract holding 10 ETH
2. Bank verifies balance equals 10 ETH
3. Bank begins transferring 10 ETH to user
4. Attacker's contract receives funds and **immediately triggers another withdrawal**
5. Balance hasn't been updated yet, so contract allows another 10 ETH withdrawal
6. Cycle repeats until bank is drained

## Vulnerable Code

```solidity theme={null}
// VULNERABLE: State updated after external call
function withdraw(uint256 amount) public {
    require(balances[msg.sender] >= amount);

    // External call BEFORE state update
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);

    // State update happens too late
    balances[msg.sender] -= amount;
}
```

## Attacker Contract

```solidity theme={null}
contract Attacker {
    Bank public bank;

    constructor(address _bankAddress) {
        bank = Bank(_bankAddress);
    }

    receive() external payable {
        if (address(bank).balance >= 10 ether) {
            bank.withdraw(10 ether);  // Re-enter!
        }
    }

    function attack() public payable {
        bank.deposit{value: 10 ether}();
        bank.withdraw(10 ether);
    }
}
```

## Safe Patterns

### Checks-Effects-Interactions

```solidity theme={null}
// SAFE: State updated BEFORE external call
function withdraw(uint256 amount) public {
    require(balances[msg.sender] >= amount);

    // Update state FIRST
    balances[msg.sender] -= amount;

    // External call LAST
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}
```

### Reentrancy Guard

```solidity theme={null}
// SAFE: Mutex lock prevents re-entry
bool private locked;

modifier noReentrant() {
    require(!locked, "Reentrant call");
    locked = true;
    _;
    locked = false;
}

function withdraw(uint256 amount) public noReentrant {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}
```

## Reentrancy Variants

| Variant             | Description                                           |
| ------------------- | ----------------------------------------------------- |
| **Single-function** | Re-entering the same function                         |
| **Cross-function**  | Re-entering a different function that shares state    |
| **Cross-contract**  | Re-entering via another contract in the same protocol |
| **Read-only**       | Exploiting view functions during reentrancy           |

## API Detection

```json theme={null}
{
  "issues": [
    {
      "tag": "reentrancy",
      "severity": "high",
      "description": "External call before state update in withdraw()",
      "location": "withdraw(uint256)",
      "variant": "single-function"
    }
  ]
}
```

## Prevention Checklist

* [ ] Follow Checks-Effects-Interactions pattern
* [ ] Update all state before making external calls
* [ ] Use reentrancy guards (e.g., OpenZeppelin `ReentrancyGuard`) on sensitive functions
* [ ] Use `.call{value: ...}("")` for ETH transfers (not `transfer()`/`send()`)
* [ ] Always check the boolean return value from `.call` and handle failures explicitly

<Warning>
  `transfer()` and `send()` are **deprecated** due to their hardcoded 2300 gas limit, which can fail after gas cost changes (EIP-1884). Use `.call{value: ...}("")` instead.
</Warning>
