0
    function recoverContribution() public payable{
        require(hasDeadlinePassed(), "deadline has not passed, contributions cannot be recovered rightnow");
        require(!(address(this).balance >= minimumTarget), "target has been met, cannot recover contributions now");
        require(contributors[msg.sender] != 0, "you have not contributed anything");
        payable(msg.sender).transfer(contributors[msg.sender]);
        contributors[msg.sender] = 0;
    }

The above function is called by a contributor to recover his/her funds incase the target has not been met and the dead line has passed.

this function gives a reentrancy error and a gas cost infinite error.

this function is extremely simple why would this function exhibit such potential errors?

Sam
  • 55
  • 6

1 Answers1

1

Simple theory on reentrancy attacks.

When you use any transfer function on your contract, to transfer ether from your contract to someone else, if that someone else is another contract, the contract can execute logic before the transfer is finished ( check out the receive fallback function ), on this receive function, the attacker contract can call again your recoverContribution function, and keep on transferring and reentring.

Now, if you keep track of the ether AFTER the transfer, this will cause a reentrancy vulnerability because you'll update their ether balance only after the transfer has been executed, which is the case of your function, so they can empty your balance by calling recoverContribution, because your requires will pass the checks since you update their balance only after the transfer has been done.

To avoid this kind of attack, just update their balance BEFORE the transfer, this way their balance will be updated on each call, even if they are reentering from their receive function.

So basically to avoid reentrancy attacks on your function, just do:

   function recoverContribution() public payable{
    require(hasDeadlinePassed(), "deadline has not passed, contributions cannot be recovered rightnow");
    require(!(address(this).balance >= minimumTarget), "target has been met, cannot recover contributions now");
    require(contributors[msg.sender] != 0, "you have not contributed anything");

    contributors[msg.sender] = 0;
    payable(msg.sender).transfer(contributors[msg.sender]);
}
MrFrenzoid
  • 1,208
  • 6
  • 21
  • can you also explain why it gives the gas cost is infinite error?? – Sam Jul 21 '22 at 18:22
  • @Sam Honestly at first glance i have no idea, it seems like a normal function unless the caller's "receive" function does something that might cause that infinite gas warning. Did you use any tool or library to detect the reentrancy attack by the way? I'm curious about it. – MrFrenzoid Jul 21 '22 at 20:38
  • no, remix gave me these warnings – Sam Jul 23 '22 at 06:27
  • Wow, didn't knew remix implemented that kind of checks, its amazing :D – MrFrenzoid Jul 23 '22 at 12:10
  • yeah just go to plugins and enable SOLIDITY STATIC ANALYSIS it'll give you these warnings – Sam Jul 23 '22 at 12:17