Transport migration (v1 → v2)
Mostro is moving its wire transport from protocol v1 (NIP-59 gift wrap,
kind 1059) to protocol v2 (NIP-44 direct message, kind 14). This
page is the practical guide for client developers: what changes, how to
detect which transport a node speaks, and how to support both during the
transition.
The logical messages, key derivation, indexing and rotation rules are unchanged — only the envelope differs. The two formats are documented side by side in Keys management (the v2 wire format is under Protocol v2 — NIP-44 direct messages) and the message tuples in Overview.
Why the change
Gift wraps give strong metadata privacy, but their outer event is signed by a random throwaway key, so neither relays nor the daemon can tell legitimate traffic from garbage without paying the full NIP-44 decrypt cost — a spam flood ("Gift Wrap Apocalypse") cannot be rate-limited by sender. Protocol v2 makes the trade key the visible author of the event. Because trade keys are already single-trade and rotated, exposing one leaks little, while enabling relay-side rate limiting by sender and cheap daemon-side pre-validation before decryption. See the threat model in issue #626.
Capability discovery
A node speaks exactly one transport — there is no dual mode. It
advertises which in its instance-info event
(kind 38385) via the protocol_version tag:
["protocol_version", "1"]→ gift wrap (kind1059)["protocol_version", "2"]→ NIP-44 direct (kind14)
A client should read this tag before sending anything and use the matching wire format. Old daemons that predate the tag emit nothing; treat their absence as v1.
What a client must change
- Read
protocol_versionfrom the node's kind-38385event and branch on it. - Subscribe to the right kind:
1059for v1,14for v2 (authored by the node,#p-tagged to your trade keys for node replies). - Wrap/unwrap with the matching path.
mostro-core0.13.0 ships both —wrap_message_with(transport, …)/unwrap_incoming(event, …)dispatch on the transport (or event kind), so a client holding both paths needs only to pass the node's transport. - Set
version: 2in the message on the v2 transport (1on v1). - On v2, build the 3-element content tuple — message, trade signature
(or
null), identity proof["<identity pubkey>", "<identity sig>"](ornullfor full-privacy mode). The identity proof is a signature over the domain-tagged payloadmostro-transport-v2-identity:<trade pubkey hex>:<message JSON>; see Keys management → Identity proof. - On v2, add a NIP-40
expirationtag to outgoing events. Mostro fills a default (the node'sdm_days, 30 days) on its own messages when none is supplied.
Full-privacy mode and reputation mode work the same way as in v1: omit the
identity key (proof and trade signature both null) for full privacy, or
include them to maintain reputation.
Release timeline
- v0.18.0 — protocol v2 ships. Default
transport = "gift-wrap", so nothing changes for existing clients. Protocol v1 is DEPRECATED. Client developers have the 0.18.x cycle to ship v2 support. - v0.19.0 — protocol v2 becomes the default and only protocol.
mostrod removes the v1 path entirely.
mostro-corekeeps its gift-wrap helpers so clients can still migrate at their own pace, but nodes will no longer accept kind-1059traffic.
The recommendation is therefore: keep both wrap paths now and select per
node from protocol_version. A client that supports both will work against
every node throughout the transition, and against v2-only nodes after the
v0.19.0 cutover with no further change.