lib

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

commit eec2badb91364f5d4735d0b375aa0ce51c5f23d0
parent 319c978911b90655c3e363b4ac0cd333dfca5cc5
Author: triesap <tyson@radroots.org>
Date:   Sun, 29 Mar 2026 17:08:25 +0000

trade: reduce public crate boundary to workflow ownership

- point trade workflow code at canonical radroots-events and radroots-events-codec trade models
- make the legacy listing codec and contract modules internal to radroots-trade
- replace duplicated trade validation error ownership with canonical trade error types
- wire the required serde_json and std feature plumbing for the shared codec path

Diffstat:
Mcrates/events-codec/src/trade/decode.rs | 12+++++++-----
Mcrates/events-codec/src/trade/encode.rs | 3+++
Mcrates/events-codec/src/trade/mod.rs | 4++--
Mcrates/events-codec/src/trade/tags.rs | 9+++++----
Mcrates/events/src/kinds.rs | 35++++++++++++++++++++++++++++-------
Mcrates/events/src/trade.rs | 31+++++++++++++++++++++----------
Mcrates/trade/Cargo.toml | 10+++++++---
Mcrates/trade/src/listing/codec.rs | 43+++++--------------------------------------
Acrates/trade/src/listing/contract.rs | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/trade/src/listing/mod.rs | 12+++++++-----
Mcrates/trade/src/listing/projection.rs | 17++++++++++-------
Mcrates/trade/src/listing/validation.rs | 96+++----------------------------------------------------------------------------
12 files changed, 160 insertions(+), 174 deletions(-)

diff --git a/crates/events-codec/src/trade/decode.rs b/crates/events-codec/src/trade/decode.rs @@ -1,5 +1,5 @@ -#[cfg(not(feature = "std"))] -use alloc::{format, string::String}; +#[cfg(all(not(feature = "std"), feature = "serde_json"))] +use alloc::{borrow::ToOwned, format, string::String, vec::Vec}; #[cfg(feature = "serde_json")] use radroots_events::{ @@ -188,8 +188,7 @@ pub fn trade_envelope_from_event<T: DeserializeOwned>( #[cfg(all(test, feature = "serde_json"))] mod tests { use super::{ - RadrootsTradeEnvelopeParseError, RadrootsTradeListingAddress, - trade_envelope_from_event, + RadrootsTradeEnvelopeParseError, RadrootsTradeListingAddress, trade_envelope_from_event, }; use crate::trade::encode::trade_envelope_event_build; use radroots_events::{ @@ -245,7 +244,10 @@ mod tests { }; let envelope: RadrootsTradeEnvelope<RadrootsTradeMessagePayload> = trade_envelope_from_event(&event).expect("parse trade envelope"); - assert_eq!(envelope.message_type, RadrootsTradeMessageType::OrderRequest); + assert_eq!( + envelope.message_type, + RadrootsTradeMessageType::OrderRequest + ); assert_eq!(envelope.order_id.as_deref(), Some("order-1")); } diff --git a/crates/events-codec/src/trade/encode.rs b/crates/events-codec/src/trade/encode.rs @@ -1,3 +1,6 @@ +#[cfg(all(not(feature = "std"), feature = "serde_json"))] +use alloc::string::String; + #[cfg(feature = "serde_json")] use radroots_events::trade::{RadrootsTradeEnvelope, RadrootsTradeMessageType}; diff --git a/crates/events-codec/src/trade/mod.rs b/crates/events-codec/src/trade/mod.rs @@ -4,8 +4,8 @@ pub mod tags; #[cfg(feature = "serde_json")] pub use decode::{ - RadrootsTradeEnvelopeParseError, RadrootsTradeListingAddress, - RadrootsTradeListingAddressError, trade_envelope_from_event, + RadrootsTradeEnvelopeParseError, RadrootsTradeListingAddress, RadrootsTradeListingAddressError, + trade_envelope_from_event, }; #[cfg(feature = "serde_json")] pub use encode::trade_envelope_event_build; diff --git a/crates/events-codec/src/trade/tags.rs b/crates/events-codec/src/trade/tags.rs @@ -1,5 +1,5 @@ #[cfg(not(feature = "std"))] -use alloc::{string::String, vec::Vec}; +use alloc::{borrow::ToOwned, string::String, vec::Vec}; use radroots_events::tags::{TAG_D, TAG_E_PREV, TAG_E_ROOT}; @@ -93,10 +93,11 @@ pub fn validate_trade_chain(tags: &[Vec<String>]) -> Result<(), JobParseError> { #[cfg(test)] mod tests { - use super::{ - push_trade_chain_tags, trade_envelope_tags, validate_trade_chain, + use super::{push_trade_chain_tags, trade_envelope_tags, validate_trade_chain}; + use radroots_events::{ + kinds::KIND_LISTING, + tags::{TAG_D, TAG_E_PREV, TAG_E_ROOT}, }; - use radroots_events::{kinds::KIND_LISTING, tags::{TAG_D, TAG_E_PREV, TAG_E_ROOT}}; #[test] fn trade_envelope_tags_build_expected_tags() { diff --git a/crates/events/src/kinds.rs b/crates/events/src/kinds.rs @@ -307,8 +307,14 @@ mod kinds_constants_tests { ("KIND_APP_DATA", KIND_APP_DATA), ("KIND_LISTING", KIND_LISTING), ("KIND_APPLICATION_HANDLER", KIND_APPLICATION_HANDLER), - ("KIND_TRADE_LISTING_VALIDATE_REQ", KIND_TRADE_LISTING_VALIDATE_REQ), - ("KIND_TRADE_LISTING_VALIDATE_RES", KIND_TRADE_LISTING_VALIDATE_RES), + ( + "KIND_TRADE_LISTING_VALIDATE_REQ", + KIND_TRADE_LISTING_VALIDATE_REQ, + ), + ( + "KIND_TRADE_LISTING_VALIDATE_RES", + KIND_TRADE_LISTING_VALIDATE_RES, + ), ("KIND_TRADE_LISTING_ORDER_REQ", KIND_TRADE_LISTING_ORDER_REQ), ("KIND_TRADE_LISTING_ORDER_RES", KIND_TRADE_LISTING_ORDER_RES), ( @@ -319,9 +325,18 @@ mod kinds_constants_tests { "KIND_TRADE_LISTING_ORDER_REVISION_RES", KIND_TRADE_LISTING_ORDER_REVISION_RES, ), - ("KIND_TRADE_LISTING_QUESTION_REQ", KIND_TRADE_LISTING_QUESTION_REQ), - ("KIND_TRADE_LISTING_ANSWER_RES", KIND_TRADE_LISTING_ANSWER_RES), - ("KIND_TRADE_LISTING_DISCOUNT_REQ", KIND_TRADE_LISTING_DISCOUNT_REQ), + ( + "KIND_TRADE_LISTING_QUESTION_REQ", + KIND_TRADE_LISTING_QUESTION_REQ, + ), + ( + "KIND_TRADE_LISTING_ANSWER_RES", + KIND_TRADE_LISTING_ANSWER_RES, + ), + ( + "KIND_TRADE_LISTING_DISCOUNT_REQ", + KIND_TRADE_LISTING_DISCOUNT_REQ, + ), ( "KIND_TRADE_LISTING_DISCOUNT_OFFER_RES", KIND_TRADE_LISTING_DISCOUNT_OFFER_RES, @@ -334,12 +349,18 @@ mod kinds_constants_tests { "KIND_TRADE_LISTING_DISCOUNT_DECLINE_REQ", KIND_TRADE_LISTING_DISCOUNT_DECLINE_REQ, ), - ("KIND_TRADE_LISTING_CANCEL_REQ", KIND_TRADE_LISTING_CANCEL_REQ), + ( + "KIND_TRADE_LISTING_CANCEL_REQ", + KIND_TRADE_LISTING_CANCEL_REQ, + ), ( "KIND_TRADE_LISTING_FULFILLMENT_UPDATE_REQ", KIND_TRADE_LISTING_FULFILLMENT_UPDATE_REQ, ), - ("KIND_TRADE_LISTING_RECEIPT_REQ", KIND_TRADE_LISTING_RECEIPT_REQ), + ( + "KIND_TRADE_LISTING_RECEIPT_REQ", + KIND_TRADE_LISTING_RECEIPT_REQ, + ), ("KIND_JOB_REQUEST_MIN", KIND_JOB_REQUEST_MIN), ("KIND_JOB_REQUEST_MAX", KIND_JOB_REQUEST_MAX), ("KIND_JOB_RESULT_MIN", KIND_JOB_RESULT_MIN), diff --git a/crates/events/src/trade.rs b/crates/events/src/trade.rs @@ -51,11 +51,19 @@ impl std::error::Error for RadrootsTradeListingParseError {} )] #[derive(Clone, Debug, PartialEq, Eq)] pub enum RadrootsTradeListingValidationError { - InvalidKind { kind: u32 }, + InvalidKind { + kind: u32, + }, MissingListingId, - ListingEventNotFound { listing_addr: String }, - ListingEventFetchFailed { listing_addr: String }, - ParseError { error: RadrootsTradeListingParseError }, + ListingEventNotFound { + listing_addr: String, + }, + ListingEventFetchFailed { + listing_addr: String, + }, + ParseError { + error: RadrootsTradeListingParseError, + }, InvalidSeller, MissingFarmProfile, MissingFarmRecord, @@ -309,10 +317,7 @@ pub struct RadrootsTradeListingValidateRequest { #[derive(Clone, Debug, PartialEq, Eq)] pub struct RadrootsTradeListingValidateResult { pub valid: bool, - #[cfg_attr( - feature = "ts-rs", - ts(type = "RadrootsTradeListingValidationError[]") - )] + #[cfg_attr(feature = "ts-rs", ts(type = "RadrootsTradeListingValidationError[]"))] pub errors: Vec<RadrootsTradeListingValidationError>, } @@ -426,7 +431,10 @@ impl RadrootsTradeMessageType { #[inline] pub const fn requires_order_id(self) -> bool { - !matches!(self, Self::ListingValidateRequest | Self::ListingValidateResult) + !matches!( + self, + Self::ListingValidateRequest | Self::ListingValidateResult + ) } #[inline] @@ -516,7 +524,10 @@ impl core::fmt::Display for RadrootsTradeEnvelopeError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::InvalidVersion { expected, got } => { - write!(f, "invalid envelope version: expected {expected}, got {got}") + write!( + f, + "invalid envelope version: expected {expected}, got {got}" + ) } Self::MissingOrderId => write!(f, "missing order_id for order-scoped message"), Self::MissingListingAddr => write!(f, "missing listing_addr"), diff --git a/crates/trade/Cargo.toml b/crates/trade/Cargo.toml @@ -7,7 +7,7 @@ authors = [ ] rust-version.workspace = true license.workspace = true -description = "trade listing models and tag mappings for radroots nostr flows" +description = "workflow validation projections and read models for radroots trade flows" repository.workspace = true homepage.workspace = true documentation = "https://docs.rs/radroots-trade" @@ -16,14 +16,18 @@ build = "build.rs" [features] default = ["std", "serde", "serde_json", "ts-rs"] -std = [] +std = ["radroots-core/std", "radroots-events/std", "radroots-events-codec/std"] serde = [ "dep:serde", "radroots-core/serde", "radroots-events/serde", "radroots-events-codec/serde", ] -serde_json = ["serde", "dep:serde_json"] +serde_json = [ + "serde", + "dep:serde_json", + "radroots-events-codec/serde_json", +] ts-rs = ["dep:ts-rs", "radroots-events/ts-rs", "radroots-events/std"] [dependencies] diff --git a/crates/trade/src/listing/codec.rs b/crates/trade/src/listing/codec.rs @@ -17,11 +17,10 @@ use radroots_events::listing::{ use radroots_events::plot::RadrootsPlotRef; use radroots_events::resource_area::RadrootsResourceAreaRef; use radroots_events::tags::TAG_D; +pub(crate) use radroots_events::trade::RadrootsTradeListingParseError as TradeListingParseError; use radroots_events_codec::d_tag::is_d_tag_base64url; use radroots_events_codec::error::EventEncodeError; -use radroots_events_codec::listing::tags::{ListingTagOptions, listing_tags_with_options}; -#[cfg(feature = "ts-rs")] -use ts_rs::TS; +use radroots_events_codec::listing::tags::listing_tags_full; const TAG_PRICE: &str = "price"; const TAG_RADROOTS_BIN: &str = "radroots:bin"; @@ -41,39 +40,6 @@ const TAG_EXPIRES_AT: &str = "expires_at"; const TAG_P: &str = "p"; const TAG_A: &str = "a"; -#[cfg_attr(feature = "ts-rs", derive(TS))] -#[cfg_attr(feature = "ts-rs", ts(export, export_to = "types.ts"))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TradeListingParseError { - MissingTag(String), - InvalidTag(String), - InvalidNumber(String), - InvalidUnit, - InvalidCurrency, - InvalidJson(String), - InvalidDiscount(String), -} - -impl core::fmt::Display for TradeListingParseError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - TradeListingParseError::MissingTag(tag) => write!(f, "missing required tag: {tag}"), - TradeListingParseError::InvalidTag(tag) => write!(f, "invalid tag: {tag}"), - TradeListingParseError::InvalidNumber(field) => write!(f, "invalid number: {field}"), - TradeListingParseError::InvalidUnit => write!(f, "invalid unit"), - TradeListingParseError::InvalidCurrency => write!(f, "invalid currency"), - TradeListingParseError::InvalidJson(field) => write!(f, "invalid json: {field}"), - TradeListingParseError::InvalidDiscount(kind) => { - write!(f, "invalid discount data for {kind}") - } - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for TradeListingParseError {} - fn parse_decimal(s: &str, field: &str) -> Result<RadrootsCoreDecimal, TradeListingParseError> { s.parse::<RadrootsCoreDecimal>() .map_err(|_| TradeListingParseError::InvalidNumber(field.to_string())) @@ -171,13 +137,14 @@ pub fn listing_from_event_parts( listing_from_tags(tags, d_tag, farm_ref, farm_pubkey, resource_area, plot) } +#[allow(dead_code)] pub fn listing_tags_build( listing: &RadrootsListing, ) -> Result<Vec<Vec<String>>, TradeListingParseError> { - let options = ListingTagOptions::with_trade_fields(); - listing_tags_with_options(listing, options).map_err(map_listing_tags_error) + listing_tags_full(listing).map_err(map_listing_tags_error) } +#[allow(dead_code)] fn map_listing_tags_error(err: EventEncodeError) -> TradeListingParseError { match err { EventEncodeError::EmptyRequiredField(field) => { diff --git a/crates/trade/src/listing/contract.rs b/crates/trade/src/listing/contract.rs @@ -0,0 +1,62 @@ +#![forbid(unsafe_code)] + +#[allow(unused_imports)] +#[cfg(feature = "serde_json")] +use radroots_events::RadrootsNostrEvent; +#[allow(unused_imports)] +pub(crate) use radroots_events::{ + kinds::{ + KIND_TRADE_LISTING_ANSWER_RES, KIND_TRADE_LISTING_CANCEL_REQ, + KIND_TRADE_LISTING_DISCOUNT_ACCEPT_REQ, KIND_TRADE_LISTING_DISCOUNT_DECLINE_REQ, + KIND_TRADE_LISTING_DISCOUNT_OFFER_RES, KIND_TRADE_LISTING_DISCOUNT_REQ, + KIND_TRADE_LISTING_FULFILLMENT_UPDATE_REQ, KIND_TRADE_LISTING_ORDER_REQ, + KIND_TRADE_LISTING_ORDER_RES, KIND_TRADE_LISTING_ORDER_REVISION_REQ, + KIND_TRADE_LISTING_ORDER_REVISION_RES, KIND_TRADE_LISTING_QUESTION_REQ, + KIND_TRADE_LISTING_RECEIPT_REQ, KIND_TRADE_LISTING_VALIDATE_REQ, + KIND_TRADE_LISTING_VALIDATE_RES, TRADE_LISTING_KINDS, is_trade_listing_kind, + }, + trade::{ + RADROOTS_TRADE_ENVELOPE_VERSION as TRADE_LISTING_ENVELOPE_VERSION, + RADROOTS_TRADE_LISTING_DOMAIN as TRADE_LISTING_DOMAIN, RadrootsTradeAnswer as TradeAnswer, + RadrootsTradeDiscountDecision as TradeDiscountDecision, + RadrootsTradeDiscountOffer as TradeDiscountOffer, + RadrootsTradeDiscountRequest as TradeDiscountRequest, + RadrootsTradeEnvelope as TradeListingEnvelope, + RadrootsTradeEnvelopeError as TradeListingEnvelopeError, + RadrootsTradeFulfillmentStatus as TradeFulfillmentStatus, + RadrootsTradeFulfillmentUpdate as TradeFulfillmentUpdate, + RadrootsTradeListingCancel as TradeListingCancel, + RadrootsTradeListingParseError as TradeListingParseError, + RadrootsTradeListingValidateRequest as TradeListingValidateRequest, + RadrootsTradeListingValidateResult as TradeListingValidateResult, + RadrootsTradeListingValidationError as TradeListingValidationError, + RadrootsTradeMessagePayload as TradeListingMessagePayload, + RadrootsTradeMessageType as TradeListingMessageType, RadrootsTradeOrder as TradeOrder, + RadrootsTradeOrderChange as TradeOrderChange, RadrootsTradeOrderItem as TradeOrderItem, + RadrootsTradeOrderResponse as TradeOrderResponse, + RadrootsTradeOrderRevision as TradeOrderRevision, + RadrootsTradeOrderRevisionResponse as TradeOrderRevisionResponse, + RadrootsTradeOrderStatus as TradeOrderStatus, RadrootsTradeQuestion as TradeQuestion, + RadrootsTradeReceipt as TradeReceipt, + }, +}; +#[allow(unused_imports)] +#[cfg(feature = "serde_json")] +pub(crate) use radroots_events_codec::trade::{ + decode::{ + RadrootsTradeEnvelopeParseError as TradeListingEnvelopeParseError, + RadrootsTradeListingAddress as TradeListingAddress, + RadrootsTradeListingAddressError as TradeListingAddressError, trade_envelope_from_event, + }, + encode::trade_envelope_event_build as trade_listing_envelope_event_build, +}; + +#[cfg(feature = "serde_json")] +use serde::de::DeserializeOwned; + +#[cfg(feature = "serde_json")] +pub(crate) fn trade_listing_envelope_from_event<T: DeserializeOwned>( + event: &RadrootsNostrEvent, +) -> Result<TradeListingEnvelope<T>, TradeListingEnvelopeParseError> { + trade_envelope_from_event(event) +} diff --git a/crates/trade/src/listing/mod.rs b/crates/trade/src/listing/mod.rs @@ -1,10 +1,12 @@ -pub mod codec; -pub mod dvm; -pub mod kinds; +mod codec; +pub(crate) mod contract; pub mod model; -pub mod order; pub mod overlay; pub mod price_ext; pub mod projection; -pub mod tags; pub mod validation; + +pub(crate) use self::contract as dvm; +#[allow(unused_imports)] +pub(crate) use self::contract as kinds; +pub(crate) use self::contract as order; diff --git a/crates/trade/src/listing/projection.rs b/crates/trade/src/listing/projection.rs @@ -25,8 +25,8 @@ use ts_rs::TS; use crate::listing::{ codec::{TradeListingParseError, listing_from_event_parts}, dvm::{ - TradeListingEnvelope, TradeListingEnvelopeParseError, TradeListingMessagePayload, - TradeListingMessageType, + TradeListingEnvelopeParseError, TradeListingMessagePayload, TradeListingMessageType, + trade_listing_envelope_from_event, }, model::RadrootsTradeListingTotal, order::{ @@ -109,7 +109,7 @@ pub struct RadrootsTradeOrderWorkflowProjection { pub listing_addr: String, pub buyer_pubkey: String, pub seller_pubkey: String, - #[cfg_attr(feature = "ts-rs", ts(type = "TradeOrderItem[]"))] + #[cfg_attr(feature = "ts-rs", ts(type = "RadrootsTradeOrderItem[]"))] pub items: Vec<TradeOrderItem>, #[cfg_attr( feature = "ts-rs", @@ -136,7 +136,7 @@ pub struct RadrootsTradeOrderWorkflowProjection { pub accepted_discount: Option<RadrootsCoreDiscountValue>, #[cfg_attr( feature = "ts-rs", - ts(optional, type = "TradeFulfillmentStatus | null") + ts(optional, type = "RadrootsTradeFulfillmentStatus | null") )] pub last_fulfillment_status: Option<TradeFulfillmentStatus>, #[cfg_attr(feature = "ts-rs", ts(optional, type = "bool | null"))] @@ -170,7 +170,7 @@ pub struct RadrootsTradeOrderWorkflowMessage { pub listing_addr: String, #[cfg_attr(feature = "ts-rs", ts(optional, type = "string | null"))] pub order_id: Option<String>, - #[cfg_attr(feature = "ts-rs", ts(type = "TradeListingMessagePayload"))] + #[cfg_attr(feature = "ts-rs", ts(type = "RadrootsTradeMessagePayload"))] pub payload: TradeListingMessagePayload, } @@ -263,7 +263,10 @@ pub struct RadrootsTradeOrderQuery { pub buyer_pubkey: Option<String>, #[cfg_attr(feature = "ts-rs", ts(optional, type = "string | null"))] pub seller_pubkey: Option<String>, - #[cfg_attr(feature = "ts-rs", ts(optional, type = "TradeOrderStatus | null"))] + #[cfg_attr( + feature = "ts-rs", + ts(optional, type = "RadrootsTradeOrderStatus | null") + )] pub status: Option<TradeOrderStatus>, } @@ -662,7 +665,7 @@ impl RadrootsTradeOrderWorkflowProjection { impl RadrootsTradeOrderWorkflowMessage { #[cfg(feature = "serde_json")] pub fn from_event(event: &RadrootsNostrEvent) -> Result<Self, TradeListingEnvelopeParseError> { - let envelope = TradeListingEnvelope::<TradeListingMessagePayload>::from_event(event)?; + let envelope = trade_listing_envelope_from_event::<TradeListingMessagePayload>(event)?; Ok(Self { actor_pubkey: event.author.clone(), listing_addr: envelope.listing_addr, diff --git a/crates/trade/src/listing/validation.rs b/crates/trade/src/listing/validation.rs @@ -13,11 +13,12 @@ use radroots_events::{ RadrootsListing, RadrootsListingAvailability, RadrootsListingDeliveryMethod, RadrootsListingLocation, }, + trade::RadrootsTradeListingValidationError as TradeListingValidationError, }; #[cfg(feature = "ts-rs")] use ts_rs::TS; -use crate::listing::codec::{TradeListingParseError, listing_from_event_parts}; +use crate::listing::codec::listing_from_event_parts; use crate::listing::dvm::TradeListingAddress; #[cfg_attr(feature = "ts-rs", derive(TS))] @@ -46,97 +47,6 @@ pub struct RadrootsTradeListing { pub listing: RadrootsListing, } -#[cfg_attr(feature = "ts-rs", derive(TS))] -#[cfg_attr(feature = "ts-rs", ts(export, export_to = "types.ts"))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "serde", - serde(rename_all = "snake_case", tag = "kind", content = "amount") -)] -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum TradeListingValidationError { - InvalidKind { kind: u32 }, - MissingListingId, - ListingEventNotFound { listing_addr: String }, - ListingEventFetchFailed { listing_addr: String }, - ParseError { error: TradeListingParseError }, - InvalidSeller, - MissingFarmProfile, - MissingFarmRecord, - MissingTitle, - MissingDescription, - MissingProductType, - MissingBins, - MissingPrimaryBin, - InvalidBin, - MissingPrice, - InvalidPrice, - MissingInventory, - InvalidInventory, - MissingAvailability, - MissingLocation, - MissingDeliveryMethod, -} - -impl core::fmt::Display for TradeListingValidationError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - TradeListingValidationError::InvalidKind { kind } => { - write!(f, "invalid listing kind: {kind}") - } - TradeListingValidationError::MissingListingId => write!(f, "missing listing id"), - TradeListingValidationError::ListingEventNotFound { listing_addr } => { - write!(f, "listing event not found: {listing_addr}") - } - TradeListingValidationError::ListingEventFetchFailed { listing_addr } => { - write!(f, "listing event fetch failed: {listing_addr}") - } - TradeListingValidationError::ParseError { error } => { - write!(f, "invalid listing data: {error}") - } - TradeListingValidationError::InvalidSeller => { - write!(f, "listing author does not match farm pubkey") - } - TradeListingValidationError::MissingFarmProfile => { - write!(f, "missing farm profile") - } - TradeListingValidationError::MissingFarmRecord => { - write!(f, "missing farm record") - } - TradeListingValidationError::MissingTitle => write!(f, "missing listing title"), - TradeListingValidationError::MissingDescription => { - write!(f, "missing listing description") - } - TradeListingValidationError::MissingProductType => { - write!(f, "missing listing product type") - } - TradeListingValidationError::MissingBins => write!(f, "missing listing bins"), - TradeListingValidationError::MissingPrimaryBin => { - write!(f, "missing primary listing bin") - } - TradeListingValidationError::InvalidBin => write!(f, "invalid listing bin"), - TradeListingValidationError::MissingPrice => write!(f, "missing listing price"), - TradeListingValidationError::InvalidPrice => write!(f, "invalid listing price"), - TradeListingValidationError::MissingInventory => { - write!(f, "missing listing inventory") - } - TradeListingValidationError::InvalidInventory => { - write!(f, "invalid listing inventory") - } - TradeListingValidationError::MissingAvailability => { - write!(f, "missing listing availability") - } - TradeListingValidationError::MissingLocation => write!(f, "missing listing location"), - TradeListingValidationError::MissingDeliveryMethod => { - write!(f, "missing listing delivery method") - } - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for TradeListingValidationError {} - pub fn validate_listing_event( event: &RadrootsNostrEvent, ) -> Result<RadrootsTradeListing, TradeListingValidationError> { @@ -153,7 +63,7 @@ pub fn validate_listing_event( return Err(TradeListingValidationError::InvalidSeller); } let listing_addr = TradeListingAddress { - kind: KIND_LISTING as u16, + kind: KIND_LISTING, seller_pubkey: seller_pubkey.clone(), listing_id: listing_id.clone(), }