# 【Fallback】

`fallback` 是一個沒有任何參數也不會回傳任何值的函數

他在以下情況會被執行：

* 當一筆非由呼叫函式引起的交易被送往合約時
* 當呼叫的函式不存在且`fallback` 函式存在時
* 合約直接匯出 ether 但是 `receive()` 不存在或 `msg.data` 非為空時

若是合約接收到了ether卻沒有任何的Fallback Function也沒有任何呼叫函式的行為，將會Throw Exception

`fallback` 有 2300 gas 限制

```solidity
pragma solidity ^0.8.10;

contract Fallback {
    event Log(uint gas);

    // Fallback function must be declared as external.
    fallback() external payable {
        // send / transfer (forwards 2300 gas to this fallback function)
        // call (forwards all of the gas)
        emit Log(gasleft());
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

contract SendToFallback {
    function transferToFallback(address payable _to) public payable {
        _to.transfer(msg.value);
    }

    function callFallback(address payable _to) public payable {
        (bool sent, ) = _to.call{value: msg.value}("");
        require(sent, "Failed to send Ether");
    }
}
```

Fallback Function 有以下的特性：

* 可視性只能為`external`
* 當我們沒有任何`payable` 的 Function 符合調用，那就會觸發例外處理（exception），除非我們擁有 Fallback function
* Fallback Function 就像`catch`，當我們沒有和任何payable function互動，或沒有任何函式符合交易的encoded data field，就會觸發

```solidity
pragma solidity ^0.8.11;

contract FunctionsExample{
    
    mapping(address => uint) public balanceReceived;
    
    address payable owner;
    
    constructor() public {
        owner = payable(msg.sender);
    }
    
    function getOwner () public view returns(address){
        return owner;
    }
    
    function convertWeiToEther(uint _amountInWei) public pure returns(uint){
        return _amountInWei / 1 ether;
        // alternatively:
        // return _amountInWei / 10**18;
        
        // pure function call only interacte with the variables in this scope like _amountInWei, but not the state variables outside the scope
    
    }
    
    function destroyContract() public {
        require(msg.sender == owner, "You are not the owner");
        selfdestruct(owner);
    }
    
    function receiveMoney() public payable {
        assert(balanceReceived[msg.sender] + msg.value >= balanceReceived[msg.sender]);
        balanceReceived[msg.sender] += msg.value;
    }
    
    function withdrawMoney(address payable _to, uint _amount) public {
        require(balanceReceived[msg.sender] <= _amount, "You don't have enough ether");
        assert(balanceReceived[msg.sender] >= balanceReceived[msg.sender] - _amount);
        balanceReceived[msg.sender] -= _amount;
        _to.transfer(_amount);
    }
    
    fallback () external payable{
        receiveMoney();
        
        // fallback function will have input fill(in remix IDE) even we didn't declare any input arguments in function
        // because the fallback function is triggered automatically no matter have arguments or not.
        // arguments data is in msg.data
    }
}
```

Fallback Function存在最大的原因是我們沒辦法避免接收ether，常見情況下我們有至少三種的方式可以接收來自外部的ether：

1. 當我們呼叫了`selfdistructor` 解構其他合約並把自己的合約地址當作參數傳入
2. 挖礦，我們將智能合約的地址設為礦工地址
3. 在智能合約被部屬之前就先將ether傳至其地址（機率不高但有可能發生）

最糟的情況下，我們還可以依賴2300 gas的限制：

* `_contractAddress.trasfer(1 ether);`

當Contract Data被呼叫時使其強制地避免函式執行

* `require(msg.data.length == 0)`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chihaolu.gitbook.io/all-in-one-solidity/part-i-basic/chapter-5-han-shi-function/fallback.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
