Skip to content

Emit per-account revenue events via EventHandle in payment_revenue to enable account-scoped queries #3740

@jolestar

Description

@jolestar
  • Area: Move contracts, rooch_framework::payment_revenue, events/indexer
  • Labels: enhancement, contracts, events, indexer

Summary
Revenue events (RevenueDepositedEvent, RevenueWithdrawnEvent, RevenueHubCreatedEvent) are currently emitted without a per-account handle, making it hard for clients to query history for a specific account (agent). We propose emitting events using moveos_std::event::emit_with_handle with a per-account handle ID derived from the account’s revenue hub_id, so indexers and clients can fetch account-scoped streams efficiently.

Problem

  • All revenue events share global streams per event type; frontend needs to query by type and client-filter by owner, which is inefficient and mixes accounts.
  • The UI currently shows all events because there’s no per-account event handle to filter on.

Proposal
Use moveos_std::event with custom per-account handle IDs:

  • For each event type, compute a per-account handle ID using the hub_id:
    • deposited: custom_event_handle_id<ObjectID, RevenueDepositedEvent>(hub_id)
    • withdrawn: custom_event_handle_id<ObjectID, RevenueWithdrawnEvent>(hub_id)
    • hub created: custom_event_handle_id<ObjectID, RevenueHubCreatedEvent>(hub_id)
  • Emit via emit_with_handle(handle_id, event) instead of emit(event).
  • No need to store EventHandle fields in state; handle IDs are computed from hub_id on the fly.

Design Details

  • Update deposit:
use moveos_std::event;

let hub_obj = borrow_or_create_revenue_hub(account);
let hub_id = object::id(hub_obj);

/* ... state updates ... */

let handle_id = event::custom_event_handle_id<ObjectID, RevenueDepositedEvent>(hub_id);
event::emit_with_handle<RevenueDepositedEvent>(
  handle_id,
  RevenueDepositedEvent {
    hub_id,
    owner: account,
    coin_type,
    amount,
    source_type: source.source_type,
    source_id: source.source_id,
    source_description: source.description,
  },
);
  • Update withdraw:
let hub_obj = borrow_mut_revenue_hub(owner_addr);
let hub_id = object::id(hub_obj);

/* ... withdraw ... */

let handle_id = event::custom_event_handle_id<ObjectID, RevenueWithdrawnEvent>(hub_id);
event::emit_with_handle<RevenueWithdrawnEvent>(
  handle_id,
  RevenueWithdrawnEvent {
    hub_id,
    owner: owner_addr,
    coin_type,
    amount,
    fee_amount: 0u256,
    net_amount: amount,
    fee_rate_bps: 0u16,
  },
);
  • Hub creation:
let hub_obj = borrow_or_create_revenue_hub(sender);
let hub_id = object::id(hub_obj);

let handle_id = event::custom_event_handle_id<ObjectID, RevenueHubCreatedEvent>(hub_id);
event::emit_with_handle<RevenueHubCreatedEvent>(
  handle_id,
  RevenueHubCreatedEvent { hub_id, owner: sender },
);

Client/Indexer Impact

  • Indexer already exposes event_id.event_handle_id and event_seq.
  • Frontends can filter by event_handle_id = custom_event_handle_id<ObjectID, T>(hub_id) to fetch only the target account’s events.
  • Total count per account can be inferred from event_seq (0-based), or exposed via a view in the future if needed.

Backward Compatibility

  • Option A: Temporarily double-emit (legacy emit + new emit_with_handle) for one release window to avoid breaking existing consumers.
  • Option B: Hard switch to emit_with_handle with a minor version bump and release notes.

Acceptance Criteria

  • Each account’s events have distinct event_handle_id based on hub_id.
  • Frontend can reliably query only the current agent’s events.
  • No regressions in deposit/withdraw functionality.
  • Tests updated to validate handle-based emissions.

Risks/Notes

  • This approach avoids storing EventHandle in state and does not require &signer for handle creation; handle IDs are derived deterministically from hub_id.
  • If existing hubs need migration to “start” handle-based streams, no state change is required—just begin emitting with the computed handle IDs.

References

  • Contract: frameworks/rooch-framework/sources/payment_revenue.move
  • Event lib: frameworks/moveos-stdlib/sources/event.move (moveos_std::event)

Tasks

  • Switch all revenue event emissions to moveos_std::event::emit_with_handle using custom_event_handle_id<ObjectID, T>(hub_id).
  • Optional: double-emit during a deprecation window.
  • Update tests and docs.
  • Update frontend queries to filter by event_handle_id for account-scoped history.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:stdlibMove stdlib or framework issues

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions