Skip to main content


Events are the main way to track actions on chain. The following example includes comments to document the logic of the code. The example extends the donut example used elsewhere in the documentation to include events that are emitted when someone purchases a donut and when the DonutShop collects coins from that sale. You could then set up subscriptions to listen for these events, then trigger logic when those events fire.

/// Extended example of a shared object. Now with addition of events!
module examples::donuts_with_events {
use sui::transfer;
use sui::sui::SUI;
use sui::coin::{Self, Coin};
use sui::object::{Self, ID, UID};
use sui::balance::{Self, Balance};
use sui::tx_context::{Self, TxContext};

// This is the only dependency you need for events.
use sui::event;

/// For when Coin balance is too low.
const ENotEnough: u64 = 0;

/// Capability that grants an owner the right to collect profits.
struct ShopOwnerCap has key { id: UID }

/// A purchasable Donut. For simplicity's sake we ignore implementation.
struct Donut has key { id: UID }

struct DonutShop has key {
id: UID,
price: u64,
balance: Balance<SUI>

// ====== Events ======

/// For when someone has purchased a donut.
struct DonutBought has copy, drop {
id: ID

/// For when DonutShop owner has collected profits.
struct ProfitsCollected has copy, drop {
amount: u64

// ====== Functions ======

fun init(ctx: &mut TxContext) {
transfer::transfer(ShopOwnerCap {
id: object::new(ctx)
}, tx_context::sender(ctx));

transfer::share_object(DonutShop {
id: object::new(ctx),
price: 1000,
balance: balance::zero()

/// Buy a donut.
public fun buy_donut(
shop: &mut DonutShop,
payment: &mut Coin<SUI>,
ctx: &mut TxContext,
): Donut {
assert!(coin::value(payment) >= shop.price, ENotEnough);

let coin_balance = coin::balance_mut(payment);
let paid = balance::split(coin_balance, shop.price);
let id = object::new(ctx);

balance::join(&mut shop.balance, paid);

// Emit the event using future object's ID.
event::emit(DonutBought { id: object::uid_to_inner(&id) });
Donut { id }

/// Consume donut and get nothing...
public fun eat_donut(d: Donut) {
let Donut { id } = d;

/// Take coin from `DonutShop` and transfer it to tx sender.
/// Requires authorization with `ShopOwnerCap`.
public fun collect_profits(
_: &ShopOwnerCap,
shop: &mut DonutShop,
ctx: &mut TxContext,
): Coin<SUI> {
let amount = balance::value(&shop.balance);
let profits = coin::take(&mut shop.balance, amount, ctx);

// simply create new type instance and emit it
event::emit(ProfitsCollected { amount });

  • Using Events: A guide to leveraging Sui events in your smart contracts.