> For the complete documentation index, see [llms.txt](https://chihaolu.gitbook.io/all-in-one-solidity/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://chihaolu.gitbook.io/all-in-one-solidity/part-ii-medium/chapter-9-yi-chang-chu-li-handling-exception.md).

# | Chapter 9 | 異常處理 Handling Exception

面對異常處理，我們得先簡單理解交易以及錯誤（Transactions and Errors），並且條列一些在Solidity中異常處理的性質。

* 交易是自動化的，一旦送出便沒有辦法在過程中透過人為終止
* 拋出Errors是會回復狀態的行為，並不會讓錯誤發生。
* 語法包含 `require`, `assert`, `revert`，在更早的版本還有`throw;`
* 除了以下 Low-Level 的函數以外，皆為接連發生的（cascade）
  * `Address.send`, `address.call`, `address.delegatecall`, `address.staticcall`
* `Revert` 和 `require` 可以回傳錯誤訊息

0.4.10 版的 Solidity 新增了 `require()`, `assert()`, `revert()` 這三個語法

* `require()` 用來檢查較不嚴重的錯誤，通常是在執行前就檢驗合理的輸入或條件，可以退回為使用到的 gas
* `assert()` 用來檢查較嚴重的錯誤，會像以前一樣拿走所有的 gasLimit 的手續費
* `revert()` 跟 `require()` 基本上相同，但是 `revert()` 沒有包括狀態檢查

0.6 之後新增了 `try/catch` 可以使用

```solidity
pragma solidity ^0.8.11;

contract Exception{
    
    mapping(address => uint64) public balanceReveived;
    
    function receiveMoney() public payable {
        assert(balanceReceived[msg.sender] + uint64(msg.value) >= balanceReceived[msg.sender])
        balanceReveived[msg.sender] += uint64(msg.value);
    }
    
    function withdrawMoney(address payable _to, uint64 _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);
    }
}
```

以上例子之中我們可以發現：

* 在加上 `assert` 之前，當我們想要匯入10ethers兩次，實際上合約不會收到20ethers，原因是來自於`uint64`
* 在我們加上 `assert` 之後，當我們想要匯入10ethers兩次，便會在第二次動作時接收到回傳的錯誤。

#### Throw

* 於Solidity 0.4.10版本後移除

```solidity
if (msg.sender != owner) {
    throw;
}
```
