# | Chapter 10 | 事件 Event

在 Solidity 中，當一個 `event` 被 call 之後它的參數就會被置於區塊鏈之中。

事件是合約的可繼承成員，發出一個事件可以使用合約的地址訪問事件，生成的事件不能從合約內部訪問。

以下是我們使用事件的用途：

* 事件是一個合約跟外部前端 app（或說使用者 interface）溝通的方法，可以在前端聆聽（listening）合約裡的特定事件或者動作，當他們被啟動或者改變的時候。
* 同步於資料啟動某些動作
* 相同資料量的情況下，比儲存在 `storage` 更便宜
* 如果我們今天要 debug 或者測試的時候，也可以利用 `event` 來模擬一個 Javascript `console.log` 的功能。

```solidity
pragma solidity ^0.8.11;
contract EventExample {

    mapping(address => uint) public tokenBalance;

    constructor() public {
        tokenBalance[msg.sender] = 100;
    }

    function sendToken(address _to, uint _amount) public returns(bool) {
        require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
        assert(tokenBalance[_to] + _amount >= tokenBalance[_to]);
        assert(tokenBalance[msg.sender] - _amount <= tokenBalance[msg.sender]);
        tokenBalance[msg.sender] -= _amount;
        tokenBalance[_to] += _amount;

        return true;
    }

}
```

當我們呼叫了 `sendToken()` 這個函式，在不同的環境它會回傳不同的結果：

* 使用Javascript VM(Virtural Machine) 時：
  * &#x20;`sendToken()` returns `boolean: true`
  * 因為其是模擬一個「瀏覽器」環境
* 使用Injected Web3 時：
  * `sendToken()` 不會returns任何東西
  * 因為其是在真實的區塊鏈上運作&#x20;

這也就是說，如果我們希望在真實的區塊鏈上聆聽回傳結果，必須透過Event，並將其`emit`置於函數之中（記得要在函數`return`之前）。而Event也可以被像是MetaMask之類的Provider聆聽。

```solidity
pragma solidity ^0.8.11;
contract EventExample {

    mapping(address => uint) public tokenBalance;
    
    event TokenSent(address _from, address _to, uint _amount);

    constructor() public {
        tokenBalance[msg.sender] = 100;
    }

    function sendToken(address _to, uint _amount) public returns(bool) {
        require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
        assert(tokenBalance[_to] + _amount >= tokenBalance[_to]);
        assert(tokenBalance[msg.sender] - _amount <= tokenBalance[msg.sender]);
        tokenBalance[msg.sender] -= _amount;
        tokenBalance[_to] += _amount;
        
        emit TokenSent(msg.sender, _to, _amount);

        return true;
    }

}
```

在以上的例子之中當我們呼叫了具有`emit`的`sendToken()`，我們可以在**Transaction Information**中看見`logs`，而在`logs`中會看見我們`emit`的資訊。

Event 具有以下的性質：

* 應用程式可以透過Ethereum 客戶端的RPC interface，以`subscribe`來聆聽這些事件
* Events是作為合約的一部分是可繼承的
* 合約不可以存取自己Event被啟動之後的`logs`和任何相關data。
* 被標示`indexed`的Event 參數可以在未來被檢索
