Events

Events are emitted during the execution of a transaction. Each Move module can define its own events and choose when to emit the events upon execution of the module. Endless Move supports two form of events: module events and EventHandle events. Module events are the modern event mechanism and shipped in the framework release 1.7. EventHandle events are deprecated and shipped with the original framework. Because of how blockchains work, EventHandle events will likely never be fully removed from Endless.

Module Events

Module events are global event streams identified by a struct type. To define an event struct, add the attribute #[event] to a normal Move struct that has drop and store abilities. For example,

/// 0xcafe::my_module_name
/// An example module event struct denotes a coin transfer.
#[event]
struct TransferEvent has drop, store {
    sender: address,
    receiver: address,
    amount: u64
}

And then create and emit the event:

// Define an event.
let event = TransferEvent {
    sender: 0xcafe,
    receiver: 0xface,
    amount: 100
};
// Emit the event just defined.
0x1::event::emit(event);

Examples of coin transfer on testnet is here(https://scan.endless.link/txn/3143636/events?network=testnet) . Indices 0(Withdraw), 1(Deposit) are module events of type 0x1::fungible_asset.

Access in Tests

Events are stored in a separate merkle tree called event accumulator for each transaction. As it is ephemeral and hence independent of the state tree, MoveVM does not have read access to events when executing transaction in production. But in tests, Endless Move supports two native functions that read emitted events for testing and debugging purposes:

/// Return all emitted module events with type T as a vector.
# [test_only]
public native fun emitted_events<T: drop + store>(): vector<T>;

/// Return true iff `msg` was emitted.
# [test_only]
public fun was_event_emitted<T: drop + store>(msg: & T): bool

API Access

There is support for querying both module events and EventHandle events using the RPC API.

Event-Handle Event

EventHandle is identified by a globally unique value, GUID, and a per-event sequence number and stored within a resource. Each event within a stream has a unique sequence number derived from the EventHandle sequence number.

For example, during a EDS Coin transfer, 0x1::fungible_assert module will emit event of Withdraw and Deposit associated with the sender and receiver's EDS CoinStore. This data is stored within the ledger and can be queried via the REST interface's Get events by event handle.

Assuming that an account GinLHfukKufLYJ757NfyCLpeDvjeNjLPQwc7waco3o7b had sent coins to another account, the following query could be made to the REST interface: https://rpc-test.endless.link/v1/accounts/GinLHfukKufLYJ757NfyCLpeDvjeNjLPQwc7waco3o7b/events/0x1::fungible_asset::FungibleStore<0x1::endless_coin::EndlessCoin>/owner. The output would be all WithdrawEvents stored on that account, it would look like

[
  {
    "key": "0x0000000000000000caa60eb4a01756955ab9b2d1caca52ed",
    "sequence_number": "0",
    "type": "0x1::endless_coin::WithdrawEvent",
    "data": {
      "amount": "1000"
    }
  }
]

Each registered event has a unique key. The key 0x0000000000000000caa60eb4a01756955ab9b2d1caca52ed maps to the event 0x1::fungible_asset::FungibleStore<0x1::endless_coin::EndlessCoin>/sent_events registered on account GinLHfukKufLYJ757NfyCLpeDvjeNjLPQwc7waco3o7b.

These represent event streams, or a list of events with each entry containing a sequentially increasing sequence_number beginning at 0, a type, and data. Each event must be defined by some type. There may be multiple events defined by the same or similar types especially when using generics. Events have associated data. The general principle is to include all data necessary to understand the changes to the underlying resources before and after the execution of the transaction that changed the data and emitted the event.

Migration to Module Events

With the release of module events, EventHandle events are deprecated. To support migration to the module events, projects should emit a module event wherever they currently emit EventHandle events. Once external systems have sufficiently adopted module events, the legacy event may no longer need to be emitted.

Note, the EventHandle events cannot and will not be deleted and hence projects that are unable to upgrade will continue to be able to leverage them.

Last updated