Secure Account Existence check for Low-level Calls
Low-level calls are methods that work on raw addresses to call other contracts’ functions in Solidity. “call”, “delegatecall”, “callcode”, “send”, “transfer”, etc are some examples of low-level functions.
The call() method allows you to call any function you want on the address specified, and if the function is implemented on that address, it will be executed.
delegatecall() method calls a function of contract B from contract A with contract A’s storage, balance and address passed to the function. This allows us to use the function in contract B as library code. Read more
staticcall() is another low-level function. The only difference between a staticcall and a call is that a staticcall cannot change the state of the contract it is calling.
For example:
In the example above, a function foo()
is being called on the address _addr
with two parameters. A custom gas amount is also defined along with some Ether value in the “msg.value” field to be sent along with the transaction.
This call is particularly useful in cases where the destination contract’s code is not available to us allowing us to directly make a function call just by knowing the function name without creating an instance of the contract.
Pitfalls of using Low-Level Calls
Low-level call usage has a high chance of erroring out and does not check for call success or code existence. Because it avoids type checking, function existence checks, and argument packing, calling a contract function is generally not advised. It is recommended to import the contract’s interface before calling any of its functions.
Unchecked Call Return Value:
Solidity generally “handles errors via state-reverting exceptions.” Changes made to the current call and its sub-calls are undone by these exceptions. The low-level operations call, delegatecall, staticcall, send, and transfer do not throw exceptions. Instead, when faults are encountered, these return the Boolean value false and carry on with the operation. For instance, if a contract uses the send call to call another, an out-of-gas exception may occur since the call is restricted to 2300 gas, but it may cost more to execute the receiver’s fallback function, where the call is aimed.
Both receive() and fallback() are defined:
The contract’s fallback function is called if the function given to the call method doesn’t exist. If the contract doesn’t provide a fallback function, the call method will return the success state as false.
Sending value or calldata will be accepted if the receive is designated as payable and the fallback is nonpayable. When value and calldata are delivered simultaneously, a run-time error is generated because the fallback will be called with the calldata but cannot accept value because it is not payable.
King of the Ether and Etherpot: Case Scenario:
Similar to various attacks in smart contracts, Etherpot was a smart contract lottery. The failure of this contract was primarily due to the erroneous use of block hashes (only the last 256 block hashes are usable). However, the contract was vulnerable to unchecked call value.
Lets take a look at the function SendCash in the following code snippet.
It is important to note that the winner.send
method does not validate the send function’s return value before setting a Boolean to true to signify that the winner has received their winnings. This flaw can lead to a situation in which the winner isn’t actually paid in ether, but the contract’s state shows that they have.
The contract was exploited because it only transferred 2300 gas due to which the send transaction failed because of insufficient gas.
Best Practices to Check for Code Existence in Low-Level Calls:
The following are the best practices to check for code existence in low-level calls:
Check for Call Success:
Our cloud-based smart contract security scanner SolidityScan can automatically find vulnerabilities related to Account Existence check for Low-level Calls.

Conclusion:
Solidity low level call are basic functions that can be used to communicate with other contracts. This article discusses the implications of using these calls without their return value validations. SolidityScan will ensure that the proper steps are taken to reach the highest level of smart contract security so that you can rely on them.