Skip to content

feat: Separate Nostr event kinds for orders, ratings, info, and disputes#566

Merged
grunch merged 3 commits into
mainfrom
separate-kind-events
Jan 16, 2026
Merged

feat: Separate Nostr event kinds for orders, ratings, info, and disputes#566
grunch merged 3 commits into
mainfrom
separate-kind-events

Conversation

@grunch

@grunch grunch commented Jan 15, 2026

Copy link
Copy Markdown
Member

Previously, all Mostro events used the same replaceable event kind (38383), differentiated only by the z tag. This caused inefficiencies for clients that needed to download all event types and filter locally.

This change introduces dedicated event kinds for each event type:

  • Orders: 38383 (unchanged)
  • Ratings: 38384 (new)
  • Info: 38385 (new)
  • Disputes: 38386 (new)

Benefits:

  • Clients can subscribe to specific event types at the relay level
  • Reduced bandwidth for orderbook-only clients
  • More efficient relay filtering without tag parsing
  • Better separation of concerns

Changes:

  • Add new event kind constants in src/config/constants.rs
  • Create kind-specific event builders in src/nip33.rs: new_order_event(), new_rating_event(), new_info_event(), new_dispute_event()
  • Update all event publishing call sites to use appropriate functions
  • Add technical specification document

Summary by CodeRabbit

Release Notes

  • New Features

    • Separate event kinds now used for different operation types: orders (38383), ratings (38384), info (38385), and disputes (38386), enabling improved relay-level filtering by event type.
  • Chores

    • Updated mostro-core dependency from 0.6.57 to 0.7.0.

✏️ Tip: You can customize this high-level summary in your review settings.

Fix #565

Previously, all Mostro events used the same replaceable event kind (38383),
differentiated only by the `z` tag. This caused inefficiencies for clients
that needed to download all event types and filter locally.

This change introduces dedicated event kinds for each event type:
- Orders: 38383 (unchanged)
- Ratings: 38384 (new)
- Info: 38385 (new)
- Disputes: 38386 (new)

Benefits:
- Clients can subscribe to specific event types at the relay level
- Reduced bandwidth for orderbook-only clients
- More efficient relay filtering without tag parsing
- Better separation of concerns

Changes:
- Add new event kind constants in src/config/constants.rs
- Create kind-specific event builders in src/nip33.rs:
  new_order_event(), new_rating_event(), new_info_event(), new_dispute_event()
- Update all event publishing call sites to use appropriate functions
- Add technical specification document

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jan 15, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR implements separate Nostr event kinds for Mostro event types by introducing kind constants 38384 (ratings), 38385 (info), and 38386 (disputes) while maintaining orders at 38383. It adds type-specific event builder functions in nip33.rs and updates all call sites across the codebase to use the appropriate builder for each event type.

Changes

Cohort / File(s) Summary
Specification
docs/SEPARATE_EVENT_KINDS_SPEC.md
Added comprehensive specification document outlining the rationale, implementation plan, kind mappings, example payloads, migration strategy, and required changes across mostro_core and client tooling.
Event Kind Constants
mostro_core/src/lib.rs (external)
Added three new public constants: NOSTR_RATING_EVENT_KIND (38384), NOSTR_INFO_EVENT_KIND (38385), NOSTR_DISPUTE_EVENT_KIND (38386).
NIP-33 Event Builders
src/nip33.rs
Added internal create_event helper function to centralize event construction logic. Introduced four public builder functions: new_order_event, new_rating_event, new_info_event, new_dispute_event, each delegating to create_event with the appropriate kind constant.
Dispute Event Usage
src/app/admin_cancel.rs, src/app/admin_settle.rs, src/app/admin_take_dispute.rs, src/app/dispute.rs
Updated imports and function calls from new_event to new_dispute_event for creating dispute-related events (kind 38386).
Order Event Usage
src/app/release.rs
Updated import and function call from new_event to new_order_event for creating order events.
Event Publishing
src/scheduler.rs, src/util.rs
Updated event creation calls: scheduler.rs now uses new_info_event for info events; util.rs imports and uses both new_order_event and new_rating_event for their respective event types.
Dependency
Cargo.toml
Bumped mostro-core version from 0.6.57 to 0.7.0 to access the new event kind constants.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Suggested reviewers

  • Catrya

Poem

🐰 Kinds hop along the Nostr path,
No more just thirty-eight-three-eight-three's wrath!
Orders, ratings, info, disputes so keen,
Each finds their number, clean and pristine.
The builders now guide them home just right,
With relays that filter pure delight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: introducing separate Nostr event kinds for different Mostro event types (orders, ratings, info, disputes).
Linked Issues check ✅ Passed The pull request fully implements the coding requirements from issue #565: introduces separate event kinds (38383 for orders, 38384 for ratings, 38385 for info, 38386 for disputes), creates kind-specific event builders in nip33.rs (new_order_event, new_rating_event, new_info_event, new_dispute_event), and updates all publishing sites to use the new builders.
Out of Scope Changes check ✅ Passed All changes are directly related to the PR objectives: adding event kind constants, creating type-specific builders, updating call sites across app modules, updating the technical specification document, and bumping mostro-core dependency to 0.7.0.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a78ae6 and d357f18.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • Cargo.toml
  • docs/SEPARATE_EVENT_KINDS_SPEC.md
  • src/nip33.rs
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Runtime code lives in src/ directory with subdirectories: src/app/ for order flows and business logic, src/lightning/ for LND bindings and Lightning helpers, src/rpc/ for gRPC service and types, and src/config/ for settings and loaders

Files:

  • src/nip33.rs
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use 4-space indent, snake_case for functions, PascalCase for types, and SCREAMING_SNAKE_CASE for constants in Rust code (Rust 2021 edition)
Document non-obvious public APIs with triple-slash /// documentation comments
Prefer tracing spans over ad-hoc logging in Rust code
Co-locate tests in their modules under mod tests blocks and name tests descriptively

Files:

  • src/nip33.rs
🧠 Learnings (5)
📓 Common learnings
Learnt from: grunch
Repo: MostroP2P/mostro PR: 566
File: src/nip33.rs:1-3
Timestamp: 2026-01-16T12:05:43.533Z
Learning: In the Mostro codebase (MostroP2P/mostro), the constant `NOSTR_REPLACEABLE_EVENT_KIND` is available through the `mostro_core::prelude::*` wildcard import and does not need to be defined locally in `src/config/constants.rs` or explicitly imported in files that use `mostro_core::prelude::*`.
📚 Learning: 2026-01-16T12:05:43.533Z
Learnt from: grunch
Repo: MostroP2P/mostro PR: 566
File: src/nip33.rs:1-3
Timestamp: 2026-01-16T12:05:43.533Z
Learning: In the Mostro codebase (MostroP2P/mostro), the constant `NOSTR_REPLACEABLE_EVENT_KIND` is available through the `mostro_core::prelude::*` wildcard import and does not need to be defined locally in `src/config/constants.rs` or explicitly imported in files that use `mostro_core::prelude::*`.

Applied to files:

  • docs/SEPARATE_EVENT_KINDS_SPEC.md
📚 Learning: 2025-12-17T13:04:13.036Z
Learnt from: grunch
Repo: MostroP2P/mostro PR: 554
File: docs/DEV_FEE_TECHNICAL_SPEC.md:1-434
Timestamp: 2025-12-17T13:04:13.036Z
Learning: In the Mostro development fee implementation, the Lightning address `mostro_p2psats.mobi` in src/config/constants.rs is temporary for testing purposes. The production address will be `developmentmostro.network` as documented in docs/DEV_FEE_TECHNICAL_SPEC.md. This intentional mismatch is planned to be resolved before production deployment.

Applied to files:

  • docs/SEPARATE_EVENT_KINDS_SPEC.md
📚 Learning: 2026-01-16T12:05:35.401Z
Learnt from: grunch
Repo: MostroP2P/mostro PR: 566
File: src/nip33.rs:1-3
Timestamp: 2026-01-16T12:05:35.401Z
Learning: Do not redefine NOSTR_REPLACEABLE_EVENT_KIND in files like src/config/constants.rs or import it explicitly. If mostro_core::prelude::* is imported, the constant is available automatically. Rely on the prelude wildcard import across Rust files; if a file compiles without a local definition, no import or definition is needed.

Applied to files:

  • src/nip33.rs
📚 Learning: 2025-06-25T22:48:44.741Z
Learnt from: Catrya
Repo: MostroP2P/mostro PR: 502
File: src/app/release.rs:52-55
Timestamp: 2025-06-25T22:48:44.741Z
Learning: Cross-repository dependencies in Mostro project: when PRs introduce new types like PaymentFailedInfo from mostro-core, compilation errors are expected until the dependency PR is merged and the version is updated in the consuming repository.

Applied to files:

  • src/nip33.rs
🪛 LanguageTool
docs/SEPARATE_EVENT_KINDS_SPEC.md

[style] ~254-~254: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...Notice**: Document that kind 38383 will only be used for orders after transition ##...

(ONLY_EXCLUSIVELY_STYLE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (4)
src/nip33.rs (2)

12-28: Clean helper extraction for NIP-33 event construction.

Centralizing tag assembly and signing here keeps the public constructors simple and consistent.


30-125: All verified for dispute and info events; rating event z-tag depends on external library.

Call sites for new_dispute_event all include the z tag with value "dispute" (admin_settle.rs, dispute.rs, admin_cancel.rs, admin_take_dispute.rs). The new_info_event call site in scheduler.rs uses info_to_tags(), which correctly includes z tag with value "info".

However, the new_rating_event call site in util.rs:619 passes tags constructed from Rating::new().to_tags() (from the external mostro_core library), which cannot be inspected in this repository. The concern about lack of constructor-level enforcement is valid, but the correctness of the rating event path depends on the external crate's implementation.

docs/SEPARATE_EVENT_KINDS_SPEC.md (1)

232-233: Confirm implementation matches the z-tag requirement for ratings.

The spec calls out adding a z: "rating" tag. Please verify the actual rating event tag builder includes this (or update the spec if intentionally omitted).

Cargo.toml (1)

72-72: mostro-core 0.7.0 is compatible and properly integrated.

The three event kind constants (NOSTR_RATING_EVENT_KIND, NOSTR_INFO_EVENT_KIND, NOSTR_DISPUTE_EVENT_KIND) are available through the mostro_core::prelude::* wildcard import in src/nip33.rs and used without compilation errors. The recent commit "Update to mostro-core 0.7.0 and use new event kind constants" confirms intentional integration. Cargo.lock has been updated accordingly.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@docs/SEPARATE_EVENT_KINDS_SPEC.md`:
- Around line 42-58: The spec says add new constants (NOSTR_RATING_EVENT_KIND,
NOSTR_INFO_EVENT_KIND, NOSTR_DISPUTE_EVENT_KIND) to the external crate
mostro_core but the implementation placed them in src/config/constants.rs;
either move the new constants from src/config/constants.rs into the mostro_core
crate (adding pub const NOSTR_RATING_EVENT_KIND: u16 = 38384; pub const
NOSTR_INFO_EVENT_KIND: u16 = 38385; pub const NOSTR_DISPUTE_EVENT_KIND: u16 =
38386;) so all consumers import them from mostro_core, or update the
SEPARATE_EVENT_KINDS_SPEC.md to state that the authoritative location is
src/config/constants.rs (and note any plan to upstream to mostro_core), and
ensure references in code (where NOSTR_REPLACEABLE_EVENT_KIND,
NOSTR_RATING_EVENT_KIND, NOSTR_INFO_EVENT_KIND, NOSTR_DISPUTE_EVENT_KIND are
used) import from the chosen module.

In `@src/nip33.rs`:
- Around line 1-3: Add the missing NOSTR_REPLACEABLE_EVENT_KIND constant to the
constants module and import it into nip33 so the symbol used in nip33.rs
resolves; specifically, define pub const NOSTR_REPLACEABLE_EVENT_KIND: u16 =
38383; in the config/constants module (near the other NOSTR_* constants) and add
NOSTR_REPLACEABLE_EVENT_KIND to the existing import list in nip33.rs alongside
NOSTR_DISPUTE_EVENT_KIND, NOSTR_INFO_EVENT_KIND, and NOSTR_RATING_EVENT_KIND.
🧹 Nitpick comments (1)
src/nip33.rs (1)

131-156: Good backward compatibility approach.

The legacy new_event() now delegates to new_order_event() maintaining existing behavior. The documentation clearly directs users to the type-specific builders.

Consider adding a #[deprecated] attribute to guide future callers toward the specific functions:

#[deprecated(since = "0.x.x", note = "Use new_order_event(), new_rating_event(), new_info_event(), or new_dispute_event() instead")]
pub fn new_event(...) -> Result<Event, Error> {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75c7146 and 257f81a.

📒 Files selected for processing (10)
  • docs/SEPARATE_EVENT_KINDS_SPEC.md
  • src/app/admin_cancel.rs
  • src/app/admin_settle.rs
  • src/app/admin_take_dispute.rs
  • src/app/dispute.rs
  • src/app/release.rs
  • src/config/constants.rs
  • src/nip33.rs
  • src/scheduler.rs
  • src/util.rs
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Runtime code lives in src/ directory with subdirectories: src/app/ for order flows and business logic, src/lightning/ for LND bindings and Lightning helpers, src/rpc/ for gRPC service and types, and src/config/ for settings and loaders

Files:

  • src/app/dispute.rs
  • src/app/release.rs
  • src/app/admin_cancel.rs
  • src/app/admin_take_dispute.rs
  • src/app/admin_settle.rs
  • src/util.rs
  • src/config/constants.rs
  • src/scheduler.rs
  • src/nip33.rs
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use 4-space indent, snake_case for functions, PascalCase for types, and SCREAMING_SNAKE_CASE for constants in Rust code (Rust 2021 edition)
Document non-obvious public APIs with triple-slash /// documentation comments
Prefer tracing spans over ad-hoc logging in Rust code
Co-locate tests in their modules under mod tests blocks and name tests descriptively

Files:

  • src/app/dispute.rs
  • src/app/release.rs
  • src/app/admin_cancel.rs
  • src/app/admin_take_dispute.rs
  • src/app/admin_settle.rs
  • src/util.rs
  • src/config/constants.rs
  • src/scheduler.rs
  • src/nip33.rs
src/app/**

📄 CodeRabbit inference engine (AGENTS.md)

Mirror test fixtures under src/app/ directory where applicable

Files:

  • src/app/dispute.rs
  • src/app/release.rs
  • src/app/admin_cancel.rs
  • src/app/admin_take_dispute.rs
  • src/app/admin_settle.rs
🧠 Learnings (3)
📚 Learning: 2025-09-04T18:55:53.663Z
Learnt from: grunch
Repo: MostroP2P/mostro PR: 516
File: src/app/dispute.rs:171-172
Timestamp: 2025-09-04T18:55:53.663Z
Learning: In the Mostro codebase, Dispute::new(order_id, order_status) internally initializes the dispute with "Initiated" status while storing the provided order_status (like "Active" or "FiatSent") as historical data in the dispute table to track what status the order had before the dispute was created.

Applied to files:

  • src/app/dispute.rs
  • src/app/admin_cancel.rs
  • src/app/admin_take_dispute.rs
  • src/app/admin_settle.rs
📚 Learning: 2025-03-11T23:26:33.763Z
Learnt from: bilthon
Repo: MostroP2P/mostro PR: 464
File: src/app/add_invoice.rs:73-82
Timestamp: 2025-03-11T23:26:33.763Z
Learning: In the Mostro codebase, the `update_order_event` function does not perform database operations - it only updates an order in memory and sends a Nostr event. The actual database update happens separately when calling `.update(pool)` afterward.

Applied to files:

  • src/app/release.rs
  • src/util.rs
📚 Learning: 2025-10-14T12:21:25.634Z
Learnt from: grunch
Repo: MostroP2P/mostro PR: 534
File: src/app/orders.rs:8-53
Timestamp: 2025-10-14T12:21:25.634Z
Learning: In NIP-59 gift wrap handling, `event.sender` represents the identity key (persistent pubkey saved in master_seller_pubkey/master_buyer_pubkey), while `event.rumor.pubkey` is the trade key (rotated per order). When querying user orders, use the identity key (`event.sender`) to find all orders belonging to the user, but send responses to the trade key (`event.rumor.pubkey`) for privacy.

Applied to files:

  • src/util.rs
🧬 Code graph analysis (7)
src/app/dispute.rs (1)
src/nip33.rs (1)
  • new_dispute_event (116-129)
src/app/release.rs (1)
src/nip33.rs (2)
  • new_order_event (44-57)
  • order_to_tags (305-400)
src/app/admin_cancel.rs (1)
src/nip33.rs (1)
  • new_dispute_event (116-129)
src/app/admin_take_dispute.rs (1)
src/nip33.rs (1)
  • new_dispute_event (116-129)
src/app/admin_settle.rs (1)
src/nip33.rs (1)
  • new_dispute_event (116-129)
src/util.rs (1)
src/nip33.rs (3)
  • new_order_event (44-57)
  • new_rating_event (70-83)
  • order_to_tags (305-400)
src/scheduler.rs (1)
src/nip33.rs (1)
  • new_info_event (96-103)
🪛 LanguageTool
docs/SEPARATE_EVENT_KINDS_SPEC.md

[style] ~254-~254: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...Notice**: Document that kind 38383 will only be used for orders after transition ##...

(ONLY_EXCLUSIVELY_STYLE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (19)
src/config/constants.rs (1)

15-26: LGTM! Well-documented constants following Rust conventions.

The new event kind constants are properly documented with triple-slash comments and use SCREAMING_SNAKE_CASE as per coding guidelines. The sequential kind values (38384-38386) within the NIP-33 replaceable range are appropriate.

src/nip33.rs (2)

15-31: Well-designed internal helper.

The create_event helper properly encapsulates the common event creation logic with efficient tag pre-allocation (Vec::with_capacity). Keeping it private (fn without pub) ensures a clean API surface.


44-129: LGTM! Clean builder pattern with comprehensive documentation.

The kind-specific event builders follow a consistent pattern with proper delegation to create_event. The documentation clearly explains the purpose of each identifier type (order ID, user pubkey, mostro pubkey, dispute ID).

docs/SEPARATE_EVENT_KINDS_SPEC.md (1)

1-494: Comprehensive technical specification.

The document thoroughly covers the rationale, implementation details, migration strategy, and testing plan. The event examples and client query comparisons effectively demonstrate the benefits of the change.

src/app/admin_settle.rs (2)

3-3: LGTM! Correct import for dispute event builder.


117-119: Correct usage of new_dispute_event for dispute status publishing.

The change correctly uses the new dispute-specific event builder with kind 38386. The z: "dispute" tag is retained for backward compatibility as specified.

src/app/admin_cancel.rs (2)

6-6: LGTM! Consistent import update.


109-111: Correct usage of new_dispute_event for admin cancel flow.

Consistent with the changes in admin_settle.rs. The dispute event is correctly published with kind 38386 while preserving backward-compatible tags.

src/scheduler.rs (1)

161-166: Info-specific builder usage is correct.
Switching to new_info_event aligns the info publish path with the new kind while preserving existing inputs.

src/app/admin_take_dispute.rs (2)

1-4: Import update looks good.
Using new_dispute_event is consistent with the new kind-specific API.


241-243: Dispute event construction aligns with new kind.
The builder swap keeps identifiers/tags intact while targeting the dispute kind.

src/app/dispute.rs (2)

5-7: Import update is appropriate.
Switching to new_dispute_event matches the new builder surface.


55-58: Dispute event builder swap is correct.
This keeps event payloads unchanged while targeting the dispute kind.

src/app/release.rs (2)

6-8: Order-specific builder import is correct.
Aligns order publishing with the new constructor API.


767-770: Child order event now uses the correct kind.
new_order_event keeps tags/identifier intact while mapping to order kind.

src/util.rs (4)

13-15: Builder imports look correct.
This keeps order/rating event creation explicit and kind-specific.


342-348: Order publish path uses the correct kind-specific builder.
No behavioral changes beyond the intended kind separation.


618-620: Rating event creation now targets the rating kind as intended.
Good alignment with the new NIP-33 builder surface.


691-693: Order update event now uses the order-specific builder.
This matches the new event-kind separation without changing payloads.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread docs/SEPARATE_EVENT_KINDS_SPEC.md
Comment thread src/nip33.rs Outdated
- Upgrade mostro-core dependency from 0.6.57 to 0.7.0
- Remove locally defined event kind constants (NOSTR_RATING_EVENT_KIND,
  NOSTR_INFO_EVENT_KIND, NOSTR_DISPUTE_EVENT_KIND) as they are now
  provided by mostro-core
- Replace NOSTR_REPLACEABLE_EVENT_KIND with NOSTR_ORDER_EVENT_KIND
  for clarity, as this constant is specifically used for order events
- Update documentation to reflect the new constant naming
@grunch grunch merged commit 7b5c6e5 into main Jan 16, 2026
6 checks passed
@grunch grunch deleted the separate-kind-events branch January 16, 2026 19:52
@coderabbitai coderabbitai Bot mentioned this pull request Mar 25, 2026
5 tasks
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.

Separate event kinds for orders, ratings, info, and disputes

1 participant