Event Emission
Events are the primary mechanism for making contract state changes observable to off-chain services like indexers, wallets, and dApps. Well-designed events make your contract easy to integrate with.
The Event Pattern
Define the Event
Events are structs with the #[event] attribute and the drop and store abilities:
module my_addr::marketplace {
use aptos_framework::event;
#[event]
struct ItemListed has drop, store {
seller: address,
item_id: u64,
price: u64,
}
#[event]
struct ItemSold has drop, store {
seller: address,
buyer: address,
item_id: u64,
price: u64,
}
}
Emit the Event
Use event::emit to emit events during function execution:
public entry fun list_item(
seller: &signer,
item_id: u64,
price: u64,
) {
let seller_addr = signer::address_of(seller);
// Business logic...
event::emit(ItemListed {
seller: seller_addr,
item_id,
price,
});
}
public entry fun buy_item(
buyer: &signer,
seller_addr: address,
item_id: u64,
) {
let buyer_addr = signer::address_of(buyer);
let price = get_item_price(seller_addr, item_id);
// Transfer logic...
event::emit(ItemSold {
seller: seller_addr,
buyer: buyer_addr,
item_id,
price,
});
}
What to Include in Events
Good events contain enough information for off-chain consumers to understand what happened:
- Who: The addresses of the parties involved.
- What: The specific action that occurred.
- Details: Relevant data like amounts, IDs, and timestamps.
#[event]
struct Transfer has drop, store {
from: address,
to: address,
amount: u64,
}
Event Design Guidelines
- One event per significant action: Emit an event for every state change that external observers might care about.
- Include all relevant data: Don't force indexers to make additional API calls to reconstruct what happened.
- Use descriptive names: Event struct names should clearly describe the action (e.g.,
TokenMinted,OrderFilled). - Keep events small: Don't include large data structures -- include IDs and references instead.
- Be consistent: Use consistent naming and field ordering across all events in your module.
Testing Events
You can verify event emission in tests:
#[test(seller = @0x1)]
fun test_list_emits_event(seller: &signer) {
list_item(seller, 1, 100);
// The event is emitted during execution
// Indexers will pick it up from the transaction output
}
Best Practices
- Always emit events for entry functions: Any user-facing action should emit an event.
- Don't emit events for view functions: View functions don't change state.
- Use module events (not handle events): The
#[event]attribute withevent::emitis the modern approach. - Document your events: Include doc comments on event structs so consumers know what each field means.