进阶

合约事件

监听和解析合约发出的事件日志

概述

Sophia 语言提供了在函数中发出 Events 的能力。本页将教你如何访问和解码特定交易的事件日志。

示例合约:EventEmitter

以下示例合约用于演示事件发出:

contract EventEmitter =

    // 定义事件类型
    datatype event =
        FirstEvent(int)
        | AnotherEvent(indexed address, string)

    entrypoint emitEvents(value: int, msg: string) =
        Chain.event(FirstEvent(value))
        Chain.event(AnotherEvent(Call.caller, msg))
indexed 关键字:indexed 标记的参数会被索引,便于后续过滤和搜索。
使用 ACI 解码事件

使用源代码初始化合约实例时,SDK 会自动解码事件:

// 调用合约方法时,事件会自动解码
const tx = await contract.emitEvents(1337, '这条消息未被索引');
console.log(tx.decodedEvents);

/*
输出:
[
  {
    name: 'AnotherEvent',
    args: [
      'fUq2NesPXcYZ1CcqBcGC3StpdnQw3iVxMA3YSeCNAwfN4myQk',
      '这条消息未被索引'
    ],
    contract: {
      name: 'EventEmitter',
      address: 'ct_6y3N9KqQb74QsvR9NrESyhWeLNiA9aJgJ7ua8CvsTuGot6uzh'
    }
  },
  {
    name: 'FirstEvent',
    args: [1337n],
    contract: {
      name: 'EventEmitter',
      address: 'ct_6y3N9KqQb74QsvR9NrESyhWeLNiA9aJgJ7ua8CvsTuGot6uzh'
    }
  }
]
*/
从交易哈希解码事件

也可以从已上链的交易中获取并解码事件日志:

const txHash = 'th_2YV3AmAz2kXdTnQxXtR2uxQi3KuLS9wfvXyqKkQQ2Y6dE6RnET';

// 从节点获取交易详情
const txInfo = await aeSdk.api.getTransactionInfoByHash(txHash);

// 使用合约实例解码事件
const decodedEvents = contract.$decodeEvents(txInfo.callInfo.log);
console.log(decodedEvents);

/*
输出:
[
  {
    name: 'AnotherEvent',
    args: [
      'fUq2NesPXcYZ1CcqBcGC3StpdnQw3iVxMA3YSeCNAwfN4myQk',
      'this message is not indexed'
    ],
    contract: {
      name: 'EventEmitter',
      address: 'ct_fKhQBiNQkDfoZcVF1ZzPzY7Lig6FnHDCLyFYBY33ZjfzGYPps'
    }
  },
  {
    name: 'FirstEvent',
    args: [1337n],
    contract: {
      name: 'EventEmitter',
      address: 'ct_fKhQBiNQkDfoZcVF1ZzPzY7Lig6FnHDCLyFYBY33ZjfzGYPps'
    }
  }
]
*/
事件数据结构

解码后的事件包含以下字段:

字段 类型 说明
name string 事件名称(如 FirstEvent
args Array 事件参数数组,已解码为 JS 类型
contract.name string 发出事件的合约名称
contract.address string 合约地址
常见应用场景
交易通知

监听转账事件,实时通知用户

数据同步

将链上事件同步到链下数据库

审计日志

记录重要操作的历史

状态变更追踪

跟踪合约状态变化