feat: Separate Nostr event kinds for orders, ratings, info, and disputes#566
Conversation
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>
WalkthroughThis 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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
🧰 Additional context used📓 Path-based instructions (2)src/**/*.rs📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.rs📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (5)📓 Common learnings📚 Learning: 2026-01-16T12:05:43.533ZApplied to files:
📚 Learning: 2025-12-17T13:04:13.036ZApplied to files:
📚 Learning: 2026-01-16T12:05:35.401ZApplied to files:
📚 Learning: 2025-06-25T22:48:44.741ZApplied to files:
🪛 LanguageTooldocs/SEPARATE_EVENT_KINDS_SPEC.md[style] ~254-~254: Consider replacing ‘only’ with a different word to let your writing stand out. (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)
🔇 Additional comments (4)
✏️ Tip: You can disable this entire section by setting 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. Comment |
There was a problem hiding this comment.
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 tonew_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
📒 Files selected for processing (10)
docs/SEPARATE_EVENT_KINDS_SPEC.mdsrc/app/admin_cancel.rssrc/app/admin_settle.rssrc/app/admin_take_dispute.rssrc/app/dispute.rssrc/app/release.rssrc/config/constants.rssrc/nip33.rssrc/scheduler.rssrc/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, andsrc/config/for settings and loaders
Files:
src/app/dispute.rssrc/app/release.rssrc/app/admin_cancel.rssrc/app/admin_take_dispute.rssrc/app/admin_settle.rssrc/util.rssrc/config/constants.rssrc/scheduler.rssrc/nip33.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Use 4-space indent,snake_casefor functions,PascalCasefor types, andSCREAMING_SNAKE_CASEfor constants in Rust code (Rust 2021 edition)
Document non-obvious public APIs with triple-slash///documentation comments
Prefertracingspans over ad-hoc logging in Rust code
Co-locate tests in their modules undermod testsblocks and name tests descriptively
Files:
src/app/dispute.rssrc/app/release.rssrc/app/admin_cancel.rssrc/app/admin_take_dispute.rssrc/app/admin_settle.rssrc/util.rssrc/config/constants.rssrc/scheduler.rssrc/nip33.rs
src/app/**
📄 CodeRabbit inference engine (AGENTS.md)
Mirror test fixtures under
src/app/directory where applicable
Files:
src/app/dispute.rssrc/app/release.rssrc/app/admin_cancel.rssrc/app/admin_take_dispute.rssrc/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.rssrc/app/admin_cancel.rssrc/app/admin_take_dispute.rssrc/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.rssrc/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_CASEas 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_eventhelper properly encapsulates the common event creation logic with efficient tag pre-allocation (Vec::with_capacity). Keeping it private (fnwithoutpub) 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 ofnew_dispute_eventfor 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 ofnew_dispute_eventfor 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 tonew_info_eventaligns 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.
Usingnew_dispute_eventis 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 tonew_dispute_eventmatches 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_eventkeeps 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.
- 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
Previously, all Mostro events used the same replaceable event kind (38383), differentiated only by the
ztag. 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:
Benefits:
Changes:
Summary by CodeRabbit
Release Notes
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.
Fix #565