事件 event

本章学习 Solidity 事件 event 的定义和使用方法。

视频Bilibili  |  Youtube
官网binschool.app
推特@BinSchool    DiscordBinDAO   微信:bkra50 

Solidity 中,事件(event)是智能合约的一种通知机制,用于向外部程序或其它合约通知某个事件的发生。

触发一个事件后,相关数据就会存储到区块链的收据中,并与交易关联,记录在区块链上,以便外部应用监听和处理。

事件常常用于调试合约、追踪交易和数据统计等场景。比如:区块浏览器会使用 ERC20 代币合约的事件,对交易数据进行统计。

1. 定义语法

Solidity 代码中,使用 event 关键字来定义一个事件,语法如下:

event event-name(<parameter list>);

例如,在 ERC20 代币合约中,定义了一个用来记录转账的事件。

event Transfer(address indexed from, address indexed to, uint256 value);

其中,事件名称为 Transfer,事件中包含 3 个参数:fromtovalue,分别代表转出者地址、接收者地址和转账金额。

2. 使用方法

Solidity 代码中,使用 emit 关键字来触发事件,语法如下:

emit event-name(<parameter list>);

例如,触发 ERC20 代币合约中的 Transfer 事件。

emit Transfer(0xAb...b2, 0x4B...db, 1000);

以下,我们使用一个完整的合约范例来展示事件的定义和使用方法。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Event {
  mapping (address => uint256) balances;

  // 定义转账事件
  event Transfer(address indexed from, address indexed to, uint256 value);

  // 构造函数,设置合约部署者的余额无限大
  constructor() {
    balances[msg.sender] = type(uint256).max;
  }

  // 由调用者账户转账到 `to` 地址
  function tranfer(address to, uint256 value) external {
    // 转账操作
    balances[msg.sender] -= value;
    balances[to] += value;

    // 触发转账事件
    emit Transfer(msg.sender, to, value);
  }
}

我们把合约代码复制到 Remix,进行编译,并部署到区块链上:

我们输入参数 to 的地址,比如 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02d,再输入转账数量 1000,点击 transact 按钮,就会在右下方输出执行结果。

执行结果显示,产生了 1 条事件日志,我们可以继续查看详情。

3. indexed

Solidity 中,使用 emit 触发的事件中,有一种特殊形式称为索引事件,语法如下:

event event-name(type-name indexed parameter-name,...);

例如,在 ERC20 代币合约中,定义了一个用来记录转账的索引事件。

event Transfer(address indexed from, address indexed to, uint256 value);

外部应用程序可以根据 indexed 标记过的参数进行高效的过滤和搜索事件。比如,可以应用于以下场景:

    • 过滤事件

通过索引参数,外部应用程序可以过滤感兴趣的事件。例如,根据发送者或接收者地址过滤特定用户的交易事件。

    • 高效搜索

通过索引参数,外部应用程序可以快速搜索具有特定属性或条件的事件。例如,按照特定金额范围搜索交易事件。

注意:

1. 没有使用 indexed 标记过的参数,不能作为过滤或者搜索的字段。

2. 一个事件中 indexed 标记的参数最多有 3 个。

3. 记录区块链的日志,也可以使用状态变量,但事件耗费的 gas 要低。