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.
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) {
}
}