lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit ade82b9f7cd01d4e85db455fd61a472dbd3f2e1a
parent 4968ac9ef76b64ec646e3ff968efdd3d1d8f378f
Author: triesap <tyson@radroots.org>
Date:   Sun, 15 Feb 2026 18:20:52 +0000

trade: add shared envelope event builder


- add a reusable helper to build listing envelope event kind content and tags
- keep helper behind serde_json to preserve no_std and feature boundaries
- add unit tests for order-scoped and non-order-scoped envelope emission
- verify with cargo fmt cargo check and cargo test for `radroots-trade`

Diffstat:
Mtrade/src/listing/dvm.rs | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+), 0 deletions(-)

diff --git a/trade/src/listing/dvm.rs b/trade/src/listing/dvm.rs @@ -22,6 +22,8 @@ use crate::listing::order::{ TradeAnswer, TradeDiscountDecision, TradeDiscountOffer, TradeDiscountRequest, TradeFulfillmentUpdate, TradeOrder, TradeOrderRevision, TradeQuestion, TradeReceipt, }; +#[cfg(feature = "serde_json")] +use crate::listing::tags::trade_listing_dvm_tags; use crate::listing::validation::TradeListingValidationError; pub const TRADE_LISTING_DOMAIN: &str = "trade:listing"; @@ -169,6 +171,38 @@ impl<T> TradeListingEnvelope<T> { } } +#[cfg(feature = "serde_json")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TradeListingEnvelopeEvent { + pub kind: u16, + pub content: String, + pub tags: Vec<Vec<String>>, +} + +#[cfg(feature = "serde_json")] +pub fn trade_listing_envelope_event_build<T: serde::Serialize + Clone>( + recipient_pubkey: impl Into<String>, + message_type: TradeListingMessageType, + listing_addr: impl Into<String>, + order_id: Option<String>, + payload: &T, +) -> Result<TradeListingEnvelopeEvent, serde_json::Error> { + let listing_addr = listing_addr.into(); + let envelope = TradeListingEnvelope::new( + message_type, + listing_addr.clone(), + order_id.clone(), + payload.clone(), + ); + let content = serde_json::to_string(&envelope)?; + let tags = trade_listing_dvm_tags(recipient_pubkey, &listing_addr, order_id.as_deref()); + Ok(TradeListingEnvelopeEvent { + kind: message_type.kind(), + content, + tags, + }) +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum TradeListingEnvelopeError { InvalidVersion { expected: u16, got: u16 }, @@ -376,4 +410,57 @@ mod tests { TradeListingEnvelopeError::MissingOrderId ); } + + #[cfg(feature = "serde_json")] + #[test] + fn envelope_event_build_includes_order_tag() { + let listing_addr = format!("{KIND_LISTING}:pubkey:AAAAAAAAAAAAAAAAAAAAAg"); + let payload = TradeListingValidateRequest { + listing_event: None, + }; + let built = super::trade_listing_envelope_event_build( + "pubkey", + TradeListingMessageType::OrderRequest, + listing_addr.clone(), + Some(String::from("order-1")), + &payload, + ) + .unwrap(); + + assert_eq!(built.kind, TradeListingMessageType::OrderRequest.kind()); + + let envelope: TradeListingEnvelope<TradeListingValidateRequest> = + serde_json::from_str(&built.content).unwrap(); + assert_eq!(envelope.listing_addr, listing_addr.clone()); + assert_eq!(envelope.order_id.as_deref(), Some("order-1")); + assert_eq!(built.tags.len(), 3); + } + + #[cfg(feature = "serde_json")] + #[test] + fn envelope_event_build_omits_order_tag_when_missing() { + let listing_addr = format!("{KIND_LISTING}:pubkey:AAAAAAAAAAAAAAAAAAAAAg"); + let payload = TradeListingValidateRequest { + listing_event: None, + }; + let built = super::trade_listing_envelope_event_build( + "pubkey", + TradeListingMessageType::ListingValidateRequest, + listing_addr.clone(), + None, + &payload, + ) + .unwrap(); + + assert_eq!( + built.kind, + TradeListingMessageType::ListingValidateRequest.kind() + ); + + let envelope: TradeListingEnvelope<TradeListingValidateRequest> = + serde_json::from_str(&built.content).unwrap(); + assert_eq!(envelope.listing_addr, listing_addr); + assert!(envelope.order_id.is_none()); + assert_eq!(built.tags.len(), 2); + } }