0
0
Blockchain / Solidityprogramming~7 mins

Reentrancy attacks in Blockchain / Solidity

Choose your learning style9 modes available
Introduction

Reentrancy attacks happen when a program lets another program call back into it before finishing its work. This can cause unexpected problems like losing money or data.

When writing smart contracts that handle money transfers.
When you want to protect your contract from being tricked by repeated calls.
When you need to make sure your contract finishes one task before starting another.
When you want to understand how hackers might try to steal funds from your contract.
When testing your contract for security before deploying it.
Syntax
Blockchain / Solidity
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount);
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
    balances[msg.sender] -= amount;
}

This example shows a vulnerable withdraw function in Solidity.

The call to send money happens before updating the balance, which can be exploited.

Examples
This fixes the problem by updating the balance before sending money.
Blockchain / Solidity
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}
This uses a lock to prevent the function from being called again before it finishes.
Blockchain / Solidity
bool locked;

modifier noReentrancy() {
    require(!locked, "No reentrancy");
    locked = true;
    _;
    locked = false;
}

function withdraw(uint amount) public noReentrancy {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}
Sample Program

This contract lets users deposit and withdraw money. The withdraw function is vulnerable because it sends money before updating the balance.

Blockchain / Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Vulnerable {
    mapping(address => uint) public 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;
    }
}
OutputSuccess
Important Notes

Always update balances before sending money to prevent reentrancy.

Use a reentrancy guard (lock) to block repeated calls during execution.

Test your contracts with attack simulations to find vulnerabilities.

Summary

Reentrancy attacks happen when a contract calls back into itself before finishing.

Update state before sending money to avoid this attack.

Use locks or modifiers to protect your functions.