DEV Community

Cover image for Fall Back Functions in Solidity
Mansoor Ahmed
Mansoor Ahmed

Posted on

Fall Back Functions in Solidity

Introduction
The solidity fallback function is executed if no one of the opposite functions matches the function identifier. It is executed if no data was given the call. Just one unnamed function is frequently assigned to a contract. It’s executed whenever the contract receives plain Ether with no data. The fallback function must be marked payable to receive Ether and add it to the entire balance of the contract.
In this article, we’ll study the Fall Back Function in Solidity intimately.

Description
A contract may have at the most one fallback function. It is declared using fallback () external [payable] . This function cannot have arguments. It may not return anything and must have external visibility. If none of the opposite functions matches the given function signature, it’s executed on a call to the contract. It may be executed if no data was supplied in the least and there’s no receive Ether function. The fallback function remains to receive data. But so as to also receive Ether, it must be marked payable.
Like any function, the callback function can execute complex operations as long as there’s enough gas passed on thereto. In the worst case, if a payable fallback function is additionally utilized in place of a receive function, it can only believe 2300 gas being available.

Features
The fallback function may be a special function available to a contract. It’s the subsequent features:

It is called when a non-existent function is named on the contract.
Required to be marked external.
Has no name.
Has no arguments
Can’t return anything.
It is often defined together per contract.
It’ll throw an exception if the contract receives plain ether without data if not marked payable.
Example
pragma solidity ^0.5.0;
contract Test {
uint public x ;
function() external { x = 1; }
}
contract Sink {
function() external payable { }
}
contract Caller {
function callTest(Test test) public returns (bool) {
(bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
require(success);
// test.x is now 1

address payable testPayable = address(uint160(address(test)));

// Sending ether to check contract,
// the transfer will fail, i.e. this returns false here.
return (testPayable.send(2 ether));
}
function callSink(Sink sink) public returns (bool) {
address payable sinkPayable = address(sink);
return (sinkPayable.send(2 ether));
}

}
Fall Back Functions in Solidity
Execution
Fallback functions in Solidity are executed;

When a function identifier doesn’t match any of the available functions during a smart contract,
Or if there was no data supplied in the least.
They’re unnamed.
They can’t accept arguments.
They can’t return anything.
There can only ever be one callback function during a smart contract.
In short, they’re a security valve of sorts.
Solidity developers designed a default design choice with fallback functions. That’s importantly interesting because:

Fallback functions are executed if a specific contract receives plain Ether by no other data associated with the transaction.
This default design choice is sensible and supports protect users.
However, counting on our use case, it’s going to be critical that our smart contract receive plain Ether via a fallback function.
To do this the fallback function must comprise the payable modifier:

contract ExampleContract {
function() payable {
...
}
}
The contract will issue an exception and return the Ether to the sender if there’s no payable fallback function.
Therefore the contract receives plain Ether with no other data.
The fallback function may only believe 2300 gas being available.
This doesn’t have much room to do other operations.
Other operations like writing to storage, creating contracts, calling external functions, and sending Ether.
Hence, fallback functions must be simplistic and easy.
One may still use msg.data to retrieve any payload furnished with the decision even though the fallback function cannot have arguments.
We‘ll use abi.decode alongside the array slice syntax to decode ABI-encoded data: (c, d) = abi.decode(msg.data[4:], (uint256, uint256)); after having checked the primary four bytes of msg.data.
Note that this could only be used as a final resort and proper functions should be used instead.
pragma solidity >0.6.1
pragma solidity >0.6.1
pragma solidity >0.6.1 <0.7.0;

contract Test {
// This function is called for all messages sent to
// this contract (there is no other function).
// Sending Ether to this contract will cause an exception,
// because the fallback function does not have the payable
// modifier.
fallback() external { x = 1; }
uint x;
}

contract TestPayable {
// This function is called for all messages sent to
// this contract, except plain Ether transfers
// (there is no other function except the receive function).
// Any call with non-empty calldata to this contract will execute
// the fallback function (even if Ether is sent along with the call).
fallback() external payable { x = 1; y = msg.value; }

// This function is called for plain Ether transfers, i.e.
// for every call with empty calldata.
receive() external payable { x = 2; y = msg.value; }
uint x;
uint y;
Enter fullscreen mode Exit fullscreen mode

}

contract Caller {
function callTest(Test test) public returns (bool) {
(bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
require(success);
// results in test.x becoming == 1.

    // address(test) will not allow to call ``send`` directly, since ``test`` has no payable
    // fallback function.
    // It has to be converted to the ``address payable`` type to even allow calling ``send`` on it.
    address payable testPayable = payable(address(test));

    // If someone sends Ether to that contract,
    // the transfer will fail, i.e. this returns false here.
    return testPayable.send(2 ether);
}

function callTestPayable(TestPayable test) public returns (bool) {
    (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
    require(success);
    // results in test.x becoming == 1 and test.y becoming 0.
    (success,) = address(test).call{value: 1}(abi.encodeWithSignature("nonExistingFunction()"));
    require(success);
    // results in test.x becoming == 1 and test.y becoming 1.

    // If someone sends Ether to that contract, the receive function in TestPayable will be called.
    require(address(test).send(2 ether));
    // results in test.x becoming == 2 and test.y becoming 2 ether.
}
Enter fullscreen mode Exit fullscreen mode

}
For more details visit:https://www.technologiesinindustry4.com/2021/08/fall-back-function-in-solidity.html

Discussion (0)