Search code examples
ethereumsolidity

Can transaction fail but the calling contract will think it was successful?


When making an ERC20 transfer it is a standard practice to wrap it in require statement so if it fails the tx will revert like this:

require(token.transfer(...));

What if I'm calling an external contract that doesn't return a boolean and the transaction fails.

Is it possible that the tx will fail(not revert) but the contract that called that function will think that it was successful?

Thanks. If the question isn't clear I'm happy to provide more context.


Solution

  • When you're using an external function call, as in your example, any sub-call revert propagates and reverts the main transaction.

    Example:

    function foo() public {
        // if `transfer()` reverts, `foo()` reverts as well
        token.transfer(recipient, amount);
    }
    

    If you used the low-level .call() method, a sub-call revert would not propagate to your main function. Instead, it would return false as the first return value.

    function foo() public {
        // if `transfer()` reverts,
        // `success` returns `false` and `foo()` does NOT revert
        (bool success, bytes memory returnedData) = address(token).call(
            abi.encodeWithSignature(
                "transfer(address,uint256)",
                recipient,
                amount
            )
        );
    }
    

    And if you catch the sub-call revert with a try/catch, that does not revert the main transaction either.

    function foo() public {
        // if `transfer()` reverts,
        // the `catch` block is invoked and `foo()` does NOT revert
        try token.transfer(recipient, amount) returns (bool) {
    
        } catch Error (string memory reason) {
    
        }
    }