External Calls Explained in Detail
An external call is any interaction where a contract calls another address. This includes interface calls, token transfers, Ether transfers, call, delegatecall, staticcall, and calls made through hooks or callbacks.
Smart contract example
The withdrawal function below sends Ether before clearing the user's balance:
function withdraw() external {
uint256 amount = balances[msg.sender];
(bool ok,) = msg.sender.call{value: amount}("");
require(ok);
balances[msg.sender] = 0;
}
The receiver can reenter before the balance is cleared.
External Calls in Auditing
External calls give another address control. That address can revert, consume gas, return false, reenter, trigger hooks, or change state in a dependency.
Red flags in code
-
State updates happen after an external call.
-
Low-level call return value is ignored.
-
External call target or calldata is user-controlled.
-
Calls are made inside unbounded loops.
-
Token transfers assume standard ERC-20 behavior.
-
Hooks such as ERC-777, ERC-721, or ERC-1155 callbacks are not considered.
-
Contract relies on external state after making a call.
How to test or review it
-
List every external call and mark whether the target is trusted, untrusted, or user-controlled.
-
Check ordering with checks-effects-interactions.
-
Test with malicious receiver contracts that reenter, revert, return false, consume gas, and call dependent contracts.
-
Verify return values from low-level calls and non-standard tokens are handled correctly.
-
Review delegatecall separately because it changes the caller's storage.