What is a reentrancy attack?
When a contract is executing a certain function, an attacker can repeatedly call that function in various ways. Due to the dependency on the contract's state, repeated calls can disrupt the expected logic. For example, a contract may decrease a user's balance before transferring funds and increase the recipient's balance after the transfer. By repeatedly calling the contract while the balance is being decreased, an attacker can decrease the balance multiple times.
Methods to prevent reentrancy attacks:
Set a state variable to prevent reentrancy before executing a function.
Avoid external contract calls. Secure calling methods can be defined through interfaces.
Use a mutex (Mutex) to prevent conflicts when calling functions simultaneously.
Avoid directly calling transferFrom after token approval; instead, check the approved amount between the two steps.
Code examples:
// Use mutex to prevent reentrancy
Mutex mutex;
function withdraw(uint amount) external {
require(!mutex.locked());
mutex.lock();
msg.sender.call.value(amount)();
mutex.release();
}
// Use state variable to prevent reentrancy
uint256 protecting;
function withdraw() external {
require(protecting == 0);
protecting = 1;
msg.sender.transfer(balance[msg.sender]);
protecting = 0;
}