Why a .send() transaction can fail

We already covered the difference between .send() and .transfer() in another blog post. But now, someone in our Udemy courses asked the great question: "How can a .send() transaction fail"?

Send transfers an arbitrary amount of ether to another address.

If the address is an externally owned account (not a smart contract) then the only reason it can fail, in my opinion, is if it runs out of gas. This, however, is very unlikely, given that in most cases the amount of gas needed to successfully execute the whole transaction was estimated in advance. .send() needs the gas stipend of 2300 gas and sends this along. Again, unless you modify and calculate the necessary overall gas for the transaction to the smart contract that executes the .send function youself, you're in 99.999% not affected.

Okay, what about .send to another smart contract.

The first reason .send would fail is the receiving smart contract would need more than 2300 gas. That would end in an out-of-gas-exception. If you consider this fallback function:

pragma solidity ^0.5.0;
 
contract SomeContract {
    event SomeEvent(uint _amount);
    
    function() external payable {
        emit SomeEvent(msg.value);
    }
}

Then you are already using 1084 gas for the execution of the fallback function.

That's pretty much anything you can do with 2300 gas... any writing or reading or calling is not possible. Let alone call back to the original calling contract.

Okay, that is one reason.

The other reason I can think of are exceptions. If the called contract throws an exception then .send will fail and return false:

pragma solidity ^0.5.0;
 
contract SomeContract {
    function() external payable {
        revert('We are not allowing fallback functions here');
    }
}

Then a calling contract would receive a false as return variable:

pragma solidity ^0.5.0;
 
contract MyContract {
    function thisIsDoingSomethingBig() public {
        address payable _someContractAddress = address(new SomeContract());
        bool isSent = _someContractAddress.send(0 ether);
        
        require(isSent, 'Send returned false, aborting');
        
    }
}
 
contract SomeContract {
    function() external payable {
        revert('We are not allowing fallback functions here');
    }
}

You will receive this error message:

send_returned_false

I hope that helps. Let me know in the comments if you can think of any other reason why send might fail, but I believe I got all of them.

Checkout Complete Cryptocurrency & Blockchain Course | Learn Solidity for $19.99.

And don't foget to subscribe to my newsletter to receive more of these blog posts!