| Chapter 10 | 事件 Event

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

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

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

  • 事件是一個合約跟外部前端 app(或說使用者 interface)溝通的方法,可以在前端聆聽(listening)合約裡的特定事件或者動作,當他們被啟動或者改變的時候。

  • 同步於資料啟動某些動作

  • 相同資料量的情況下,比儲存在 storage 更便宜

  • 如果我們今天要 debug 或者測試的時候,也可以利用 event 來模擬一個 Javascript console.log 的功能。

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) 時:

    • sendToken() returns boolean: true

    • 因為其是模擬一個「瀏覽器」環境

  • 使用Injected Web3 時:

    • sendToken() 不會returns任何東西

    • 因為其是在真實的區塊鏈上運作

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

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;
    }

}

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

Event 具有以下的性質:

  • 應用程式可以透過Ethereum 客戶端的RPC interface,以subscribe來聆聽這些事件

  • Events是作為合約的一部分是可繼承的

  • 合約不可以存取自己Event被啟動之後的logs和任何相關data。

  • 被標示indexed的Event 參數可以在未來被檢索

Last updated