Fallback function in Solidity


Fallback function execute when another contract call it with unknown function. Below is basic syntax for fallback function. There are two fallback functions, first one is simple and second is payable who can receive ethers.

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract fallbackContract{
    uint x;
    fallback() external {
        x =1;
    }
}

contract fallbackContractPayable{
    uint x;
    fallback() external payable{
        x =1;
    }
}

Three ways to call a method from another contract:


//first one
(bool success, ) = address(otherContract).call(abi.encodeWithSignature("methodOfOtherContract()"));

//second one with ether transfer
(bool success, ) = address(otherContract).call{value: 1}(abi.encodeWithSignature("methodOfOtherContract()"));

//third with ether transfer and no method call, so if there is a fallback in receiver contract then that will execute
(bool success, ) = address(otherContract).call{value: 1 ether}("");

Example of fallback function:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract testFallBack{
    uint public x = 1;
    
    function existing()public returns(string memory){
        x++;
        return "existing Test";
    }
    
    fallback() external {
        x += 5;
    }
}


contract CallerContract{
    
    
    function callOtherContractMethod(testFallBack testObj)public returns(bool success){
        (success,) = address(testObj).call(abi.encodeWithSignature("existing()"));
        
    }
    
      function callOtherContractunknownMethod(testFallBack testObj)public returns(bool success){
        (success,) = address(testObj).call(abi.encodeWithSignature("Non_existing()"));
        
    }
}

when we transfer ether using fallback then we have to make fallback as a payable. If sender contract has no ether then it will not call the method in the other contract.

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract testFallBack{
    uint public x = 1;

    function getBalance()public view returns(uint balance){
        balance = address(this).balance;
    }
    fallback() external payable{
        x++;
    }
}


contract CallerContract{
    
    constructor() payable{}
    
    function callOtherContractunknownMethod(testFallBack testObj)public returns(bool success){
        (success,) = address(testObj).call{value: 1 ether}(abi.encodeWithSignature("Non_existing()"));
    }
    //only sending ethers not calling a method
    function onlySendEtherToOtherContract(testFallBack testObj)public returns(bool success){
        (success, ) = address(testObj).call{value: 1 ether}("");
    }
}