I'm trying to validate a condition using require()
. If the condition is false for the first time, the contract is stopped and reverted to its initial state. On the other hand, if the condition is true for the first time and false second time onwards the contract continues to execute in spite of the false condition in require.
Similar behavior is observed in case of assert
and revert
. I'm testing everything in remix with JavaScript VM.
Can somebody help me to understand why this is happening?
In below example of SimpleDAO, we are changing the flag value when withdraw function is called and using this flag value we are checking if withdraw is called for more than one time. But the require
is not working as expected and also the if condition which is placed after require
is not evaluated except for the first call of withdraw.
pragma solidity >=0.4.0 <0.7.0;
contract SimpleDAO {
mapping (address => uint256) public credit;
bool flag = true;
constructor() payable public {
donate();
}
function donate() payable public{
credit[msg.sender] += msg.value;
}
function withdraw(uint256 amount) public{
require(flag, "Only one time call is allowed.");
flag = false;
if (credit[msg.sender]>= amount) {
msg.sender.call.value(amount)("");
credit[msg.sender]-=amount;
}
}
function queryCredit(address to) public view returns (uint256) {
return credit[to];
}
}
contract Mallory2 {
SimpleDAO public dao;
address payable owner;
constructor(SimpleDAO addr) public payable{
owner = msg.sender;
dao = addr;
}
function attack() public payable{
dao.donate.value(1)();
dao.withdraw(1);
}
function getJackpot() public{
dao.withdraw(address(dao).balance);
owner.transfer(address(this).balance);
}
function() external payable{
dao.withdraw(1);
}
}
require(x)
andx
isfalse
, then the transaction will be reverted.require
statement to be executed only under certain conditions, which means that your description above is not even correct). Obviously, no one here will be able to guess any further than that, since you haven't shared this contract!flag
) istrue
in the first time, it will not necessarily befalse
in the second time. If the function reverts atmsg.sender.call.value(amount)("")
, then the operationflag = false
will be reverted along with the rest of the operations in the function, thus leavingflag == true
.credit[msg.sender]-=amount
first, andmsg.sender.call.value(amount)("")
last).