DEV Community

Cover image for Hack Solidity: Unchecked Call Return Value
Kamil Polak
Kamil Polak

Posted on

Hack Solidity: Unchecked Call Return Value

The main idea behind this type of vulnerability is that the return value of a message call is not checked. As a result, execution will resume even if the called contract throws an exception. If the call fails accidentally or an attacker forces the call to fail, this may cause unexpected behavior in the subsequent program logic.

In Solidity you can use a few low-level call methods that work on raw addresses: call, callcode, delegatecall, and send. These low-level methods never throw an exception but will return false if the call encounters an exception.

Let's look at the example derived from Sigmaprime blog.

contract Lotto {

    bool public payedOut = false;
    address public winner;
    uint public winAmount;

    // ... extra functionality here

    function sendToWinner() public {
        require(!payedOut);
        winner.send(winAmount);
        payedOut = true;
    }

    function withdrawLeftOver() public {
        require(payedOut);
        msg.sender.send(this.balance);
    }
}
Enter fullscreen mode Exit fullscreen mode

In this simple contract, the bug exists where a send is used without checking the response. If a winner's transaction fails it allows payedOut to be set to true (regardless of whether ether was sent or not). In this case, the public can withdraw the winner's winnings using the withdrawLeftOver function.

How to prevent Unchecked Call Return Value

It is recommended to use the transfer function rather than send. This is because transfer will revert if the external transaction reverts.

If you choose to use the low-level call methods, make sure to handle the possibility that the call will fail, by checking the return value.

Sources

Top comments (0)