Skip to content

Standardize versioned event schema for payment, enrollment, governance, and role actions - #1053

Merged
ayomideadeniran merged 2 commits into
StellarDevHub:mainfrom
Junirezz:fix/918-stable-event-schema
Aug 2, 2026
Merged

Standardize versioned event schema for payment, enrollment, governance, and role actions#1053
ayomideadeniran merged 2 commits into
StellarDevHub:mainfrom
Junirezz:fix/918-stable-event-schema

Conversation

@Junirezz

Copy link
Copy Markdown
Contributor

Closes #918

Summary

Events across the payment, enrollment, governance, and role-management domains were ad hoc: raw Address/Symbol values stuffed directly into topics, no schema version, no timestamps, and no test ever asserted on event contents. There was also an existing, well-built versioned EventPublisher module (contracts/src/events.rs) that nothing in the codebase actually called.

Every event now follows one shape, documented at the top of events.rs:

topics: (event_name: Symbol, schema_version: Symbol, ..indexed fields)
data:   a single #[contracttype] struct with the full field list (actors, amounts, timestamps)

schema_version only bumps on a breaking payload change (field removed/renamed/retyped) — adding a field is non-breaking. This lets indexers detect incompatible changes instead of guessing from payload shape.

Wired up:

  • payment_gateway.rs: payment_processed / payment_released / payment_refunded / payment_disputed / dispute_resolved
  • enrollment.rs: student_enrolled / enrollment_completed / enrollment_dropped
  • governance.rs: gov_initialized / credits_deposited / proposal_created / vote_cast / proposal_finalized / proposal_executed
  • rbac.rs: rbac_role_granted (previously not emitted at all for init_rbac or grant_role) / rbac_role_revoked

Also fixes two pre-existing bugs found while adding coverage:

  • get_default_roles() in rbac.rs built role data with its own internal Env::default() instead of the contract's real Env, so init_rbac() failed on every call.
  • governance_test.rs (18 tests) existed on disk but was never wired into the module tree, so it silently never compiled or ran.

Known gap, explicitly left out of scope: certificate-lifecycle events already have a complete, well-designed schema in events.rs (Minted/Revoked/Renewed/BatchMinted/etc.), but the certificate-minting contract that would call it could not be located as compiled/reachable code in this snapshot — the only reference is contracts/src/tests.rs, which is itself unwired and references functions (e.g. batch_issue) that don't exist anywhere in the crate. Wiring that up is a separate, larger undertaking and is flagged here rather than guessed at.

Test plan

  • New event-content assertion tests (env.events().all()) added for each domain — none existed before
  • cargo test in contracts/ — all 277 tests pass
  • cargo fmt --check / cargo clippy clean

…e, and role actions (StellarDevHub#918)

Events across these domains were previously ad hoc: raw Address/Symbol
values stuffed directly into topics, no schema version, no timestamps,
and no test ever asserted on event contents. There was also an
existing, well-built versioned EventPublisher module (events.rs) that
nothing in the codebase actually called.

Every event now follows one shape: topics carry (event_name,
schema_version, ...indexed fields), and the payload is a single
documented #[contracttype] struct with a full field list (actors,
amounts, timestamps). schema_version only bumps on breaking payload
changes, so indexers can detect incompatible changes instead of
guessing from shape. The convention is documented at the top of
events.rs.

Wired up:
- payment_gateway.rs (root crate module): payment_processed/released/
  refunded/disputed, dispute_resolved
- enrollment.rs: student_enrolled/enrollment_completed/
  enrollment_dropped
- governance.rs: gov_initialized/credits_deposited/proposal_created/
  vote_cast/proposal_finalized/proposal_executed
- rbac.rs: rbac_role_granted (previously not emitted at all for
  init_rbac or grant_role) and rbac_role_revoked

Also fixes two pre-existing bugs found while adding coverage:
- get_default_roles() in rbac.rs built role data with its own internal
  Env::default() instead of the contract's real Env, so init_rbac()
  failed on every call.
- governance_test.rs (18 tests) existed on disk but was never wired
  into the module tree, so it silently never compiled or ran.

Added event-content assertion tests (env.events().all()) for each
domain, since none existed before.

Known gap, left out of scope: certificate-lifecycle events already
have a complete, well-designed schema in events.rs (Minted/Revoked/
Renewed/BatchMinted/etc.), but the certificate-minting contract that
would call it could not be located as compiled/reachable code in this
snapshot — the only reference is contracts/src/tests.rs, which is
itself unwired and references functions (e.g. batch_issue) that don't
exist anywhere in the crate. Wiring that up is a separate, larger
undertaking and is flagged here rather than guessed at.
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

@Junirezz is attempting to deploy a commit to the Ayomide Adeniran's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jul 30, 2026

Copy link
Copy Markdown

@Junirezz Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@ayomideadeniran

Copy link
Copy Markdown
Contributor

Pr under review

@ayomideadeniran
ayomideadeniran merged commit 2a45f6c into StellarDevHub:main Aug 2, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Smart Contracts] Define and test a stable event schema for critical contract actions

3 participants