# Re-entrancy
This contract suffers from a popular reentrancy (opens new window) bug. The goal of this level is for you to steal all the funds from the contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
TIP
In order to prevent re-entrancy attacks when moving funds out of your contract,
use the Checks-Effects-Interactions
pattern (opens new window)
being aware that call
will only return false without interrupting the
execution flow. Solutions such as
ReentrancyGuard (opens new window)
or
PullPayment (opens new window)
can also be used.
transfer()
and send()
are no longer recommended solutions as they can
potentially break contracts after the Istanbul hard fork Source
1 (opens new window) Source 2 (opens new window).
Always assume that the receiver of the funds you are sending can be another contract, not just a regular address. Hence, it can execute code in its payable fallback method and re-enter** your contract, possibly messing up your state/logic.
Re-entrancy is a common attack. You should always be prepared for it!
The DAO Hack.
The famous DAO hack used reentrancy to extract a huge amount of ether from the victim contract. See 15 lines of code that could have prevented TheDAO Hack (opens new window).