sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit f57001e3f45ed07e1fa0e4ac6456abc997c72dc4
parent e60c2aaa76955bdee99983001e8b7a9fec3eef58
Author: triesap <tyson@radroots.org>
Date:   Fri, 19 Jun 2026 00:19:25 -0700

sdk: remove direct order publish facade

- remove the obsolete root TradeClient export for migrated order workflows
- delete relay-direct order publish and draft facade methods from the legacy SDK client
- drop SDK-local tests that exercised replaced direct order publish APIs
- add source-boundary guards for removed direct order client methods

Diffstat:
Mcrates/sdk/src/client.rs | 471+------------------------------------------------------------------------------
Mcrates/sdk/src/lib.rs | 2+-
Mcrates/sdk/tests/client.rs | 533+------------------------------------------------------------------------------
Mcrates/sdk/tests/relay_direct.rs | 856-------------------------------------------------------------------------------
Mcrates/sdk/tests/source_boundary.rs | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 70 insertions(+), 1852 deletions(-)

diff --git a/crates/sdk/src/client.rs b/crates/sdk/src/client.rs @@ -21,8 +21,10 @@ use crate::config::{RadrootsSdkConfig, SdkConfigError, SdkTransportMode}; ))] use crate::identity::RadrootsIdentity; use crate::listing; +#[cfg(feature = "radrootsd-client")] +use crate::order; #[cfg(feature = "serde_json")] -use crate::{farm, order, profile}; +use crate::{farm, profile}; #[cfg(any( feature = "radrootsd-client", all( @@ -34,17 +36,13 @@ use crate::{farm, order, profile}; use core::time::Duration; use radroots_events::RadrootsNostrEvent; #[cfg(feature = "radrootsd-client")] +use radroots_events::RadrootsNostrEventPtr; +#[cfg(feature = "radrootsd-client")] use radroots_events::kinds::{KIND_FARM, KIND_LISTING}; #[cfg(feature = "serde_json")] -use radroots_events::{ - RadrootsNostrEventPtr, - ids::RadrootsEventId, - profile::{RadrootsProfile, RadrootsProfileType}, -}; +use radroots_events::profile::{RadrootsProfile, RadrootsProfileType}; #[cfg(feature = "serde_json")] use radroots_events_codec::wire::WireEventParts; -#[cfg(feature = "serde_json")] -use radroots_trade::listing::validation::RadrootsTradeListing as TradeListingValidateResult; type NostrTags = Vec<Vec<String>>; @@ -1996,463 +1994,6 @@ impl<'a> TradeClient<'a> { self.client.signer() } - #[cfg(feature = "serde_json")] - pub fn parse_listing_address( - &self, - listing_addr: &str, - ) -> Result<order::RadrootsListingAddress, order::RadrootsIdParseError> { - order::parse_listing_address(listing_addr) - } - - #[cfg(feature = "serde_json")] - pub fn validate_listing_event( - &self, - event: &RadrootsNostrEvent, - ) -> Result<TradeListingValidateResult, order::RadrootsTradeValidationListingError> { - order::validate_listing_event(event) - } - - #[cfg(feature = "serde_json")] - pub fn build_order_request_draft( - &self, - listing_event: &RadrootsNostrEventPtr, - payload: &order::RadrootsOrderRequest, - ) -> Result<order::RadrootsOrderRequestDraft, order::EventEncodeError> { - order::build_order_request_draft(listing_event, payload) - } - - #[cfg(feature = "serde_json")] - pub fn build_order_decision_draft( - &self, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderDecision, - ) -> Result<order::RadrootsOrderDecisionDraft, order::EventEncodeError> { - order::build_order_decision_draft(root_event_id, prev_event_id, payload) - } - - #[cfg(feature = "serde_json")] - pub fn build_order_revision_proposal_draft( - &self, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderRevisionProposal, - ) -> Result<order::RadrootsOrderRevisionProposalDraft, order::EventEncodeError> { - order::build_order_revision_proposal_draft(root_event_id, prev_event_id, payload) - } - - #[cfg(feature = "serde_json")] - pub fn build_order_revision_decision_draft( - &self, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderRevisionDecision, - ) -> Result<order::RadrootsOrderRevisionDecisionDraft, order::EventEncodeError> { - order::build_order_revision_decision_draft(root_event_id, prev_event_id, payload) - } - - #[cfg(feature = "serde_json")] - pub fn build_fulfillment_update_draft( - &self, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderFulfillmentUpdate, - ) -> Result<order::RadrootsOrderFulfillmentUpdateDraft, order::EventEncodeError> { - order::build_fulfillment_update_draft(root_event_id, prev_event_id, payload) - } - - #[cfg(feature = "serde_json")] - pub fn build_order_cancellation_draft( - &self, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderCancellation, - ) -> Result<order::RadrootsOrderCancellationDraft, order::EventEncodeError> { - order::build_order_cancellation_draft(root_event_id, prev_event_id, payload) - } - - #[cfg(feature = "serde_json")] - pub fn build_buyer_receipt_draft( - &self, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderReceipt, - ) -> Result<order::RadrootsOrderReceiptDraft, order::EventEncodeError> { - order::build_buyer_receipt_draft(root_event_id, prev_event_id, payload) - } - - #[cfg(feature = "serde_json")] - pub fn parse_order_request( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderRequest>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_order_request(event) - } - - #[cfg(feature = "serde_json")] - pub fn parse_order_decision( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderDecision>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_order_decision(event) - } - - #[cfg(feature = "serde_json")] - pub fn parse_order_revision_proposal( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderRevisionProposal>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_order_revision_proposal(event) - } - - #[cfg(feature = "serde_json")] - pub fn parse_order_revision_decision( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderRevisionDecision>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_order_revision_decision(event) - } - - #[cfg(feature = "serde_json")] - pub fn parse_fulfillment_update( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderFulfillmentUpdate>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_fulfillment_update(event) - } - - #[cfg(feature = "serde_json")] - pub fn parse_order_cancellation( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderCancellation>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_order_cancellation(event) - } - - #[cfg(feature = "serde_json")] - pub fn parse_buyer_receipt( - &self, - event: &RadrootsNostrEvent, - ) -> Result< - order::RadrootsOrderEnvelope<order::RadrootsOrderReceipt>, - order::RadrootsOrderEnvelopeParseError, - > { - order::parse_buyer_receipt(event) - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_request_with_identity( - &self, - identity: &RadrootsIdentity, - listing_event: &RadrootsNostrEventPtr, - payload: &order::RadrootsOrderRequest, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = order::build_order_request_draft(listing_event, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_request_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_revision_proposal_with_identity( - &self, - identity: &RadrootsIdentity, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderRevisionProposal, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = - order::build_order_revision_proposal_draft(root_event_id, prev_event_id, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_revision_proposal_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_revision_decision_with_identity( - &self, - identity: &RadrootsIdentity, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderRevisionDecision, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = - order::build_order_revision_decision_draft(root_event_id, prev_event_id, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_revision_decision_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_decision_with_identity( - &self, - identity: &RadrootsIdentity, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderDecision, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = order::build_order_decision_draft(root_event_id, prev_event_id, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_decision_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_fulfillment_update_with_identity( - &self, - identity: &RadrootsIdentity, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderFulfillmentUpdate, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = order::build_fulfillment_update_draft(root_event_id, prev_event_id, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_fulfillment_update_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_revision_proposal_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderRevisionProposalDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_revision_proposal_draft_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_revision_decision_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderRevisionDecisionDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_revision_decision_draft_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_cancellation_with_identity( - &self, - identity: &RadrootsIdentity, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderCancellation, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = order::build_order_cancellation_draft(root_event_id, prev_event_id, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_cancellation_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_buyer_receipt_with_identity( - &self, - identity: &RadrootsIdentity, - root_event_id: &RadrootsEventId, - prev_event_id: &RadrootsEventId, - payload: &order::RadrootsOrderReceipt, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - let draft = order::build_buyer_receipt_draft(root_event_id, prev_event_id, payload) - .map_err(|err| SdkPublishError::Encode(err.to_string()))?; - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_buyer_receipt_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_request_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderRequestDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_request_draft_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_decision_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderDecisionDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_decision_draft_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_fulfillment_update_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderFulfillmentUpdateDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_fulfillment_update_draft_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_order_cancellation_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderCancellationDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_order_cancellation_draft_with_identity", - ) - .await - } - - #[cfg(all( - feature = "identity-models", - feature = "relay-client", - feature = "signing" - ))] - pub async fn publish_buyer_receipt_draft_with_identity( - &self, - identity: &RadrootsIdentity, - draft: order::RadrootsOrderReceiptDraft, - ) -> Result<SdkPublishReceipt, SdkPublishError> { - self.client - .publish_parts_via_relay_with_identity( - identity, - draft.into_wire_parts(), - "order.publish_buyer_receipt_draft_with_identity", - ) - .await - } - #[cfg(feature = "radrootsd-client")] pub async fn publish_order_request_via_radrootsd( &self, diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs @@ -46,7 +46,7 @@ mod workflow_runtime; pub use crate::client::{ FarmClient, ListingClient, ProfileClient, RadrootsSdkClient, SdkPublishError, SdkPublishReceipt, SdkRadrootsdPublishReceipt, SdkRelayFailure, SdkRelayPublishReceipt, - SdkResolvedTransportTarget, SdkTransportReceipt, TradeClient, + SdkResolvedTransportTarget, SdkTransportReceipt, }; #[cfg(feature = "radrootsd-client")] pub use crate::client::{ diff --git a/crates/sdk/tests/client.rs b/crates/sdk/tests/client.rs @@ -3,24 +3,12 @@ use radroots_core::{ RadrootsCoreQuantityPrice, RadrootsCoreUnit, }; use radroots_events::farm::{RadrootsFarm, RadrootsFarmRef}; -use radroots_events::ids::{RadrootsEventId, RadrootsPublicKey}; -use radroots_events::kinds::{ - KIND_FARM, KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, - KIND_ORDER_FULFILLMENT_UPDATE, KIND_ORDER_RECEIPT, KIND_ORDER_REQUEST, - KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL, KIND_PROFILE, -}; +use radroots_events::kinds::{KIND_FARM, KIND_LISTING, KIND_PROFILE}; use radroots_events::listing::{ RadrootsListing, RadrootsListingAvailability, RadrootsListingBin, RadrootsListingDeliveryMethod, RadrootsListingLocation, RadrootsListingProduct, RadrootsListingStatus, }; -use radroots_events::order::{ - RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome, - RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderFulfillmentState, - RadrootsOrderFulfillmentUpdate, RadrootsOrderInventoryCommitment, RadrootsOrderItem, - RadrootsOrderPricingBasis, RadrootsOrderReceipt, RadrootsOrderRequest, - RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal, -}; use radroots_events::profile::{RadrootsProfile, RadrootsProfileType}; use radroots_sdk::client::{ RadrootsSdkClient, SdkPublishError, SdkRadrootsdPublishReceipt, SdkRelayFailure, @@ -30,8 +18,7 @@ use radroots_sdk::config::{ RADROOTS_SDK_PRODUCTION_RELAY_URL, RadrootsSdkConfig, RelayConfig, SdkConfigError, SdkEnvironment, SdkTransportMode, SignerConfig, }; -use radroots_sdk::protocol::events::{RadrootsNostrEvent, RadrootsNostrEventPtr}; -use radroots_sdk::protocol::wire::WireEventParts; +use radroots_sdk::protocol::events::RadrootsNostrEvent; fn sample_farm() -> RadrootsFarm { RadrootsFarm { @@ -124,223 +111,6 @@ fn sample_profile() -> RadrootsProfile { } } -fn decimal(raw: &str) -> RadrootsCoreDecimal { - raw.parse().expect("decimal") -} - -fn usd(raw: &str) -> RadrootsCoreMoney { - RadrootsCoreMoney::new(decimal(raw), RadrootsCoreCurrency::USD) -} - -fn listing_event_ptr() -> RadrootsNostrEventPtr { - RadrootsNostrEventPtr { - id: event_id_wire('a'), - relays: Some("wss://listing.relay.example".into()), - } -} - -fn public_key(value: String) -> RadrootsPublicKey { - value.parse().expect("public key") -} - -fn event_id(character: char) -> RadrootsEventId { - core::iter::repeat_n(character, 64) - .collect::<String>() - .parse() - .expect("event id") -} - -fn event_id_wire(character: char) -> String { - event_id(character).into_string() -} - -fn sample_order_request(buyer_pubkey: String, seller_pubkey: String) -> RadrootsOrderRequest { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderRequest { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("{KIND_LISTING}:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - items: vec![RadrootsOrderItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 2, - }], - economics: RadrootsOrderEconomics { - quote_id: "quote-1".parse().expect("quote id"), - quote_version: 1, - pricing_basis: RadrootsOrderPricingBasis::ListingEvent, - currency: RadrootsCoreCurrency::USD, - items: vec![RadrootsOrderEconomicItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 2, - quantity_amount: decimal("1"), - quantity_unit: RadrootsCoreUnit::Each, - unit_price_amount: decimal("5"), - unit_price_currency: RadrootsCoreCurrency::USD, - line_subtotal: usd("10"), - }], - discounts: Vec::new(), - adjustments: Vec::new(), - subtotal: usd("10"), - discount_total: usd("0"), - adjustment_total: usd("0"), - total: usd("10"), - }, - } -} - -fn sample_order_decision(buyer_pubkey: String, seller_pubkey: String) -> RadrootsOrderDecision { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderDecision { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("{KIND_LISTING}:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - decision: RadrootsOrderDecisionOutcome::Accepted { - inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 2, - }], - }, - } -} - -fn sample_order_revision_proposal( - buyer_pubkey: String, - seller_pubkey: String, - root_event_id: String, - prev_event_id: String, -) -> RadrootsOrderRevisionProposal { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderRevisionProposal { - revision_id: "revision-1".parse().expect("revision id"), - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("{KIND_LISTING}:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - root_event_id: root_event_id.parse().expect("root event id"), - prev_event_id: prev_event_id.parse().expect("previous event id"), - items: vec![RadrootsOrderItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 3, - }], - economics: RadrootsOrderEconomics { - quote_id: "revision-quote-1".parse().expect("revision quote id"), - quote_version: 2, - pricing_basis: RadrootsOrderPricingBasis::ListingEvent, - currency: RadrootsCoreCurrency::USD, - items: vec![RadrootsOrderEconomicItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 3, - quantity_amount: decimal("1"), - quantity_unit: RadrootsCoreUnit::Each, - unit_price_amount: decimal("5"), - unit_price_currency: RadrootsCoreCurrency::USD, - line_subtotal: usd("15"), - }], - discounts: Vec::new(), - adjustments: Vec::new(), - subtotal: usd("15"), - discount_total: usd("0"), - adjustment_total: usd("0"), - total: usd("15"), - }, - reason: "update count".into(), - } -} - -fn sample_order_revision_decision( - proposal: &RadrootsOrderRevisionProposal, - decision: RadrootsOrderRevisionOutcome, -) -> RadrootsOrderRevisionDecision { - RadrootsOrderRevisionDecision { - revision_id: proposal.revision_id.clone(), - order_id: proposal.order_id.clone(), - listing_addr: proposal.listing_addr.clone(), - buyer_pubkey: proposal.buyer_pubkey.clone(), - seller_pubkey: proposal.seller_pubkey.clone(), - root_event_id: proposal.root_event_id.clone(), - prev_event_id: event_id('3'), - decision, - } -} - -fn sample_fulfillment_update( - buyer_pubkey: String, - seller_pubkey: String, -) -> RadrootsOrderFulfillmentUpdate { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderFulfillmentUpdate { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("{KIND_LISTING}:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - status: RadrootsOrderFulfillmentState::ReadyForPickup, - } -} - -fn sample_order_cancellation( - buyer_pubkey: String, - seller_pubkey: String, -) -> RadrootsOrderCancellation { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderCancellation { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("{KIND_LISTING}:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - reason: "schedule changed".into(), - } -} - -fn sample_buyer_receipt(buyer_pubkey: String, seller_pubkey: String) -> RadrootsOrderReceipt { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderReceipt { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("{KIND_LISTING}:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - received: true, - issue: None, - received_at: 1_785_000_000, - } -} - -fn event_from_parts( - id: &str, - author: &str, - created_at: u32, - parts: WireEventParts, -) -> RadrootsNostrEvent { - RadrootsNostrEvent { - id: id.into(), - author: author.into(), - created_at, - kind: parts.kind, - tags: parts.tags, - content: parts.content, - sig: String::new(), - } -} - #[test] fn client_default_config_uses_production_relay_direct() { let client = RadrootsSdkClient::from_config(RadrootsSdkConfig::default()).expect("sdk client"); @@ -434,14 +204,12 @@ fn namespace_clients_reflect_explicit_transport_mode() { assert_eq!(client.profile().transport(), SdkTransportMode::Radrootsd); assert_eq!(client.farm().transport(), SdkTransportMode::Radrootsd); assert_eq!(client.listing().transport(), SdkTransportMode::Radrootsd); - assert_eq!(client.order().transport(), SdkTransportMode::Radrootsd); #[cfg(feature = "radrootsd-client")] assert_eq!(client.radrootsd().transport(), SdkTransportMode::Radrootsd); assert_eq!(client.signer(), SignerConfig::LocalIdentity); assert_eq!(client.profile().signer(), SignerConfig::LocalIdentity); assert_eq!(client.farm().signer(), SignerConfig::LocalIdentity); assert_eq!(client.listing().signer(), SignerConfig::LocalIdentity); - assert_eq!(client.order().signer(), SignerConfig::LocalIdentity); #[cfg(feature = "radrootsd-client")] assert_eq!(client.radrootsd().signer(), SignerConfig::LocalIdentity); } @@ -453,13 +221,11 @@ fn namespace_clients_expose_parent_sdk_and_draft_facades() { let profile = client.profile(); let farm = client.farm(); let listing = client.listing(); - let order = client.order(); assert_eq!(client.config().environment, SdkEnvironment::Production); assert!(std::ptr::eq(profile.sdk(), &client)); assert!(std::ptr::eq(farm.sdk(), &client)); assert!(std::ptr::eq(listing.sdk(), &client)); - assert!(std::ptr::eq(order.sdk(), &client)); let profile_draft = profile .build_draft(&sample_profile(), Some(RadrootsProfileType::Farm)) @@ -481,11 +247,9 @@ fn namespace_clients_expose_parent_sdk_and_draft_facades() { } #[test] -fn listing_and_order_clients_wrap_existing_sdk_facades() { +fn listing_client_wraps_existing_sdk_facade() { let client = RadrootsSdkClient::from_config(RadrootsSdkConfig::local()).expect("sdk client"); let listing_value = sample_listing(); - let buyer_pubkey = "b".repeat(64); - let seller_pubkey = "a".repeat(64); let tags = client .listing() @@ -513,297 +277,6 @@ fn listing_and_order_clients_wrap_existing_sdk_facades() { .parse_event(&event) .expect("parsed listing"); assert_eq!(parsed.d_tag, listing_value.d_tag); - - let validated = client - .order() - .validate_listing_event(&event) - .expect("validated listing"); - assert_eq!(validated.listing_id, listing_value.d_tag); - - let listing_addr = format!("{KIND_LISTING}:{seller_pubkey}:{}", listing_value.d_tag); - let payload = sample_order_request(buyer_pubkey.clone(), seller_pubkey.clone()); - let envelope = client - .order() - .build_order_request_draft(&listing_event_ptr(), &payload) - .expect("order draft"); - assert_eq!(envelope.as_wire_parts().kind, KIND_ORDER_REQUEST); - let envelope_event = RadrootsNostrEvent { - id: "order-event-1".into(), - author: buyer_pubkey, - created_at: 2, - kind: envelope.as_wire_parts().kind, - tags: envelope.as_wire_parts().tags.clone(), - content: envelope.as_wire_parts().content.clone(), - sig: String::new(), - }; - assert_eq!( - client - .order() - .parse_order_request(&envelope_event) - .expect("order envelope") - .payload - .order_id, - payload.order_id - ); - let parsed_addr = client - .order() - .parse_listing_address(&listing_addr) - .expect("listing address"); - assert_eq!(parsed_addr, listing_addr); -} - -#[test] -fn order_facades_round_trip_all_draft_types() { - let client = - RadrootsSdkClient::from_config(RadrootsSdkConfig::production()).expect("sdk client"); - let order_client = client.order(); - let buyer_pubkey = "b".repeat(64); - let seller_pubkey = "a".repeat(64); - let root_event_id = event_id('1'); - let decision_event_id = event_id('2'); - let proposal_event_id = event_id('3'); - let fulfillment_event_id = event_id('4'); - - let order_request = sample_order_request(buyer_pubkey.clone(), seller_pubkey.clone()); - let order_draft = order_client - .build_order_request_draft(&listing_event_ptr(), &order_request) - .expect("order request draft"); - assert_eq!(order_draft.as_wire_parts().kind, KIND_ORDER_REQUEST); - let order_event = event_from_parts( - root_event_id.as_str(), - &buyer_pubkey, - 1, - order_draft.clone().into_wire_parts(), - ); - let order_envelope = order_client - .parse_order_request(&order_event) - .expect("order request envelope"); - assert_eq!(order_envelope.payload.economics.total, usd("10")); - - let decision = sample_order_decision(buyer_pubkey.clone(), seller_pubkey.clone()); - let decision_draft = order_client - .build_order_decision_draft(&root_event_id, &root_event_id, &decision) - .expect("order decision draft"); - assert_eq!(decision_draft.as_wire_parts().kind, KIND_ORDER_DECISION); - let decision_event = event_from_parts( - decision_event_id.as_str(), - &seller_pubkey, - 2, - decision_draft.clone().into_wire_parts(), - ); - assert_eq!( - order_client - .parse_order_decision(&decision_event) - .expect("order decision envelope") - .payload - .decision, - decision.decision - ); - - let proposal = sample_order_revision_proposal( - buyer_pubkey.clone(), - seller_pubkey.clone(), - root_event_id.to_string(), - decision_event_id.to_string(), - ); - let proposal_draft = order_client - .build_order_revision_proposal_draft(&root_event_id, &decision_event_id, &proposal) - .expect("revision proposal draft"); - assert_eq!( - proposal_draft.as_wire_parts().kind, - KIND_ORDER_REVISION_PROPOSAL - ); - let proposal_event = event_from_parts( - proposal_event_id.as_str(), - &seller_pubkey, - 3, - proposal_draft.clone().into_wire_parts(), - ); - assert_eq!( - order_client - .parse_order_revision_proposal(&proposal_event) - .expect("revision proposal envelope") - .payload - .economics - .total, - usd("15") - ); - - let revision_decision = - sample_order_revision_decision(&proposal, RadrootsOrderRevisionOutcome::Accepted); - let revision_decision_draft = order_client - .build_order_revision_decision_draft( - &root_event_id, - &revision_decision.prev_event_id, - &revision_decision, - ) - .expect("revision decision draft"); - assert_eq!( - revision_decision_draft.as_wire_parts().kind, - KIND_ORDER_REVISION_DECISION - ); - let revision_decision_event = event_from_parts( - "order-revision-decision-event-1", - &buyer_pubkey, - 4, - revision_decision_draft.clone().into_wire_parts(), - ); - assert_eq!( - order_client - .parse_order_revision_decision(&revision_decision_event) - .expect("revision decision envelope") - .payload - .revision_id, - revision_decision.revision_id - ); - - let fulfillment = sample_fulfillment_update(buyer_pubkey.clone(), seller_pubkey.clone()); - let fulfillment_draft = order_client - .build_fulfillment_update_draft(&root_event_id, &decision_event_id, &fulfillment) - .expect("fulfillment draft"); - assert_eq!( - fulfillment_draft.as_wire_parts().kind, - KIND_ORDER_FULFILLMENT_UPDATE - ); - let fulfillment_event = event_from_parts( - fulfillment_event_id.as_str(), - &seller_pubkey, - 5, - fulfillment_draft.clone().into_wire_parts(), - ); - assert_eq!( - order_client - .parse_fulfillment_update(&fulfillment_event) - .expect("fulfillment envelope") - .payload - .status, - fulfillment.status - ); - - let cancellation = sample_order_cancellation(buyer_pubkey.clone(), seller_pubkey.clone()); - let cancellation_draft = order_client - .build_order_cancellation_draft(&root_event_id, &decision_event_id, &cancellation) - .expect("cancellation draft"); - assert_eq!( - cancellation_draft.as_wire_parts().kind, - KIND_ORDER_CANCELLATION - ); - let cancellation_event = event_from_parts( - "order-cancellation-event-1", - &buyer_pubkey, - 6, - cancellation_draft.clone().into_wire_parts(), - ); - assert_eq!( - order_client - .parse_order_cancellation(&cancellation_event) - .expect("cancellation envelope") - .payload - .reason, - cancellation.reason - ); - - let receipt = sample_buyer_receipt(buyer_pubkey.clone(), seller_pubkey.clone()); - let receipt_draft = order_client - .build_buyer_receipt_draft(&root_event_id, &fulfillment_event_id, &receipt) - .expect("receipt draft"); - assert_eq!(receipt_draft.as_wire_parts().kind, KIND_ORDER_RECEIPT); - let receipt_event = event_from_parts( - "receipt-event-1", - &buyer_pubkey, - 7, - receipt_draft.clone().into_wire_parts(), - ); - assert!( - order_client - .parse_buyer_receipt(&receipt_event) - .expect("receipt envelope") - .payload - .received - ); -} - -#[test] -fn order_draft_facades_return_encoder_errors() { - let client = - RadrootsSdkClient::from_config(RadrootsSdkConfig::production()).expect("sdk client"); - let order = client.order(); - let buyer_pubkey = "b".repeat(64); - let seller_pubkey = "a".repeat(64); - let root_event_id = event_id('1'); - let decision_event_id = event_id('2'); - - let mut invalid_order = sample_order_request(buyer_pubkey.clone(), seller_pubkey.clone()); - invalid_order.items.clear(); - assert!( - order - .build_order_request_draft(&listing_event_ptr(), &invalid_order) - .is_err() - ); - - let mut invalid_decision = sample_order_decision(buyer_pubkey.clone(), seller_pubkey.clone()); - invalid_decision.decision = RadrootsOrderDecisionOutcome::Accepted { - inventory_commitments: Vec::new(), - }; - assert!( - order - .build_order_decision_draft(&root_event_id, &root_event_id, &invalid_decision) - .is_err() - ); - - let proposal = sample_order_revision_proposal( - buyer_pubkey.clone(), - seller_pubkey.clone(), - root_event_id.to_string(), - decision_event_id.to_string(), - ); - let different_root_event_id = event_id('d'); - assert!( - order - .build_order_revision_proposal_draft( - &different_root_event_id, - &decision_event_id, - &proposal, - ) - .is_err() - ); - - let revision_decision = - sample_order_revision_decision(&proposal, RadrootsOrderRevisionOutcome::Accepted); - let different_prev_event_id = event_id('e'); - assert!( - order - .build_order_revision_decision_draft( - &root_event_id, - &different_prev_event_id, - &revision_decision, - ) - .is_err() - ); - - let mut fulfillment = sample_fulfillment_update(buyer_pubkey.clone(), seller_pubkey.clone()); - fulfillment.status = RadrootsOrderFulfillmentState::AcceptedNotFulfilled; - assert!( - order - .build_fulfillment_update_draft(&root_event_id, &decision_event_id, &fulfillment) - .is_err() - ); - - let mut cancellation = sample_order_cancellation(buyer_pubkey.clone(), seller_pubkey.clone()); - cancellation.reason.clear(); - assert!( - order - .build_order_cancellation_draft(&root_event_id, &decision_event_id, &cancellation) - .is_err() - ); - - let mut receipt = sample_buyer_receipt(buyer_pubkey, seller_pubkey); - receipt.received = false; - assert!( - order - .build_buyer_receipt_draft(&root_event_id, &decision_event_id, &receipt) - .is_err() - ); } #[test] diff --git a/crates/sdk/tests/relay_direct.rs b/crates/sdk/tests/relay_direct.rs @@ -10,12 +10,10 @@ use radroots_core::{ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreQuantity, RadrootsCoreQuantityPrice, RadrootsCoreUnit, }; -use radroots_events::ids::{RadrootsEventId, RadrootsPublicKey}; use radroots_sdk::client::{RadrootsSdkClient, SdkPublishError, SdkTransportReceipt}; use radroots_sdk::config::{ RadrootsSdkConfig, RelayConfig, SdkEnvironment, SdkTransportMode, SignerConfig, }; -use radroots_sdk::protocol::events::RadrootsNostrEventPtr; use radroots_sdk::protocol::farm::{RadrootsFarm, RadrootsFarmLocation, RadrootsFarmRef}; use radroots_sdk::protocol::identity::RadrootsIdentity; use radroots_sdk::protocol::listing::{ @@ -23,13 +21,6 @@ use radroots_sdk::protocol::listing::{ RadrootsListingDeliveryMethod, RadrootsListingLocation, RadrootsListingProduct, RadrootsListingStatus, }; -use radroots_sdk::protocol::order::{ - RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome, - RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderFulfillmentState, - RadrootsOrderFulfillmentUpdate, RadrootsOrderInventoryCommitment, RadrootsOrderItem, - RadrootsOrderPricingBasis, RadrootsOrderReceipt, RadrootsOrderRequest, - RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal, -}; use radroots_sdk::protocol::profile::{RadrootsProfile, RadrootsProfileType}; use tokio::net::TcpListener; use tokio::sync::oneshot; @@ -206,206 +197,6 @@ fn sample_farm() -> RadrootsFarm { } } -fn decimal(raw: &str) -> RadrootsCoreDecimal { - raw.parse().expect("decimal") -} - -fn usd(raw: &str) -> RadrootsCoreMoney { - RadrootsCoreMoney::new(decimal(raw), RadrootsCoreCurrency::USD) -} - -fn listing_event_ptr() -> RadrootsNostrEventPtr { - RadrootsNostrEventPtr { - id: event_id_wire('a'), - relays: Some("wss://listing.relay.example".into()), - } -} - -fn public_key(value: String) -> RadrootsPublicKey { - value.parse().expect("public key") -} - -fn event_id(character: char) -> RadrootsEventId { - core::iter::repeat_n(character, 64) - .collect::<String>() - .parse() - .expect("event id") -} - -fn event_id_wire(character: char) -> String { - event_id(character).into_string() -} - -fn sample_order_request(buyer_pubkey: String, seller_pubkey: String) -> RadrootsOrderRequest { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderRequest { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - items: vec![RadrootsOrderItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 2, - }], - economics: RadrootsOrderEconomics { - quote_id: "quote-1".parse().expect("quote id"), - quote_version: 1, - pricing_basis: RadrootsOrderPricingBasis::ListingEvent, - currency: RadrootsCoreCurrency::USD, - items: vec![RadrootsOrderEconomicItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 2, - quantity_amount: decimal("1"), - quantity_unit: RadrootsCoreUnit::Each, - unit_price_amount: decimal("5"), - unit_price_currency: RadrootsCoreCurrency::USD, - line_subtotal: usd("10"), - }], - discounts: Vec::new(), - adjustments: Vec::new(), - subtotal: usd("10"), - discount_total: usd("0"), - adjustment_total: usd("0"), - total: usd("10"), - }, - } -} - -fn sample_order_decision(buyer_pubkey: String, seller_pubkey: String) -> RadrootsOrderDecision { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderDecision { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - decision: RadrootsOrderDecisionOutcome::Accepted { - inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 2, - }], - }, - } -} - -fn sample_order_revision_proposal( - buyer_pubkey: String, - seller_pubkey: String, - root_event_id: String, - prev_event_id: String, -) -> RadrootsOrderRevisionProposal { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderRevisionProposal { - revision_id: "revision-1".parse().expect("revision id"), - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - root_event_id: root_event_id.parse().expect("root event id"), - prev_event_id: prev_event_id.parse().expect("previous event id"), - items: vec![RadrootsOrderItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 3, - }], - economics: RadrootsOrderEconomics { - quote_id: "revision-quote-1".parse().expect("revision quote id"), - quote_version: 2, - pricing_basis: RadrootsOrderPricingBasis::ListingEvent, - currency: RadrootsCoreCurrency::USD, - items: vec![RadrootsOrderEconomicItem { - bin_id: "bin-1".parse().expect("bin id"), - bin_count: 3, - quantity_amount: decimal("1"), - quantity_unit: RadrootsCoreUnit::Each, - unit_price_amount: decimal("5"), - unit_price_currency: RadrootsCoreCurrency::USD, - line_subtotal: usd("15"), - }], - discounts: Vec::new(), - adjustments: Vec::new(), - subtotal: usd("15"), - discount_total: usd("0"), - adjustment_total: usd("0"), - total: usd("15"), - }, - reason: "update count".into(), - } -} - -fn sample_order_revision_decision( - proposal: &RadrootsOrderRevisionProposal, - decision: RadrootsOrderRevisionOutcome, -) -> RadrootsOrderRevisionDecision { - RadrootsOrderRevisionDecision { - revision_id: proposal.revision_id.clone(), - order_id: proposal.order_id.clone(), - listing_addr: proposal.listing_addr.clone(), - buyer_pubkey: proposal.buyer_pubkey.clone(), - seller_pubkey: proposal.seller_pubkey.clone(), - root_event_id: proposal.root_event_id.clone(), - prev_event_id: event_id('3'), - decision, - } -} - -fn sample_fulfillment_update( - buyer_pubkey: String, - seller_pubkey: String, -) -> RadrootsOrderFulfillmentUpdate { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderFulfillmentUpdate { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - status: RadrootsOrderFulfillmentState::ReadyForPickup, - } -} - -fn sample_order_cancellation( - buyer_pubkey: String, - seller_pubkey: String, -) -> RadrootsOrderCancellation { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderCancellation { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - reason: "schedule changed".into(), - } -} - -fn sample_buyer_receipt(buyer_pubkey: String, seller_pubkey: String) -> RadrootsOrderReceipt { - let buyer_pubkey = public_key(buyer_pubkey); - let seller_pubkey = public_key(seller_pubkey); - RadrootsOrderReceipt { - order_id: "order-1".parse().expect("order id"), - listing_addr: format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg") - .parse() - .expect("listing address"), - buyer_pubkey, - seller_pubkey, - received: true, - issue: None, - received_at: 1_785_000_000, - } -} - #[tokio::test] async fn relay_direct_farm_publish_accepts_sdk_built_draft() -> TestResult<()> { let relay = AckRelay::spawn().await?; @@ -457,653 +248,6 @@ async fn relay_direct_farm_publish_accepts_sdk_built_draft() -> TestResult<()> { } #[tokio::test] -async fn relay_direct_order_request_publish_accepts_sdk_built_draft() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let listing_event = listing_event_ptr(); - let payload = sample_order_request( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - let draft = client - .order() - .build_order_request_draft(&listing_event, &payload)?; - assert_eq!(draft.as_wire_parts().kind, 3422); - - let receipt = client - .order() - .publish_order_request_draft_with_identity(&buyer_identity, draft) - .await?; - - assert_eq!(receipt.transport, SdkTransportMode::RelayDirect); - assert_eq!(receipt.event_kind, Some(3422)); - assert!(receipt.event_id.is_some()); - match receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!( - receipt.event_id.as_deref(), - Some(relay_receipt.event_id.as_str()) - ); - assert_eq!(receipt.event_kind, Some(relay_receipt.event_kind)); - assert_eq!(relay_receipt.event.kind, 3422); - assert_eq!(relay_receipt.event_id, relay_receipt.event.id); - assert_eq!(relay_receipt.signature, relay_receipt.event.sig); - assert_eq!(relay_receipt.created_at, relay_receipt.event.created_at); - assert_eq!(relay_receipt.event.author, buyer_identity.public_key_hex()); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), seller_identity.public_key_hex()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["a".to_owned(), payload.listing_addr.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["d".to_owned(), payload.order_id.to_string()]) - ); - assert!(relay_receipt.event.tags.contains(&vec![ - "listing_event".to_owned(), - listing_event.id.clone(), - listing_event.relays.clone().expect("listing relay") - ])); - assert_eq!(relay_receipt.target_relays, vec![relay.url().to_owned()]); - assert_eq!(relay_receipt.connected_relays, vec![relay.url().to_owned()]); - assert_eq!( - relay_receipt.acknowledged_relays, - vec![relay.url().to_owned()] - ); - assert!(relay_receipt.failed_relays.is_empty()); - let envelope = client - .order() - .parse_order_request(&relay_receipt.event) - .expect("order request"); - assert_eq!(envelope.order_id, payload.order_id); - assert_eq!(envelope.listing_addr, payload.listing_addr); - assert_eq!(envelope.payload.economics.quote_id, "quote-1"); - assert_eq!(envelope.payload.economics.total, usd("10")); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_decision_publish_accepts_sdk_built_draft() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let root_event_id = event_id('1'); - let payload = sample_order_decision( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - let draft = - client - .order() - .build_order_decision_draft(&root_event_id, &root_event_id, &payload)?; - assert_eq!(draft.as_wire_parts().kind, 3423); - - let receipt = client - .order() - .publish_order_decision_draft_with_identity(&seller_identity, draft) - .await?; - - assert_eq!(receipt.transport, SdkTransportMode::RelayDirect); - assert_eq!(receipt.event_kind, Some(3423)); - assert!(receipt.event_id.is_some()); - match receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!( - receipt.event_id.as_deref(), - Some(relay_receipt.event_id.as_str()) - ); - assert_eq!(receipt.event_kind, Some(relay_receipt.event_kind)); - assert_eq!(relay_receipt.event.kind, 3423); - assert_eq!(relay_receipt.event.author, seller_identity.public_key_hex()); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), buyer_identity.public_key_hex()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["a".to_owned(), payload.listing_addr.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["d".to_owned(), payload.order_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_root".to_owned(), root_event_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_prev".to_owned(), root_event_id.to_string()]) - ); - assert_eq!(relay_receipt.target_relays, vec![relay.url().to_owned()]); - assert_eq!(relay_receipt.connected_relays, vec![relay.url().to_owned()]); - assert_eq!( - relay_receipt.acknowledged_relays, - vec![relay.url().to_owned()] - ); - assert!(relay_receipt.failed_relays.is_empty()); - let envelope = client - .order() - .parse_order_decision(&relay_receipt.event) - .expect("order decision"); - assert_eq!(envelope.order_id, payload.order_id); - assert_eq!(envelope.listing_addr, payload.listing_addr); - assert_eq!(envelope.payload.decision, payload.decision); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_revision_publish_accepts_sdk_built_payloads() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let buyer_pubkey = buyer_identity.public_key_hex(); - let seller_pubkey = seller_identity.public_key_hex(); - let root_event_id = event_id('1'); - let decision_event_id = event_id('2'); - let proposal = sample_order_revision_proposal( - buyer_pubkey.clone(), - seller_pubkey.clone(), - root_event_id.to_string(), - decision_event_id.to_string(), - ); - let decision = - sample_order_revision_decision(&proposal, RadrootsOrderRevisionOutcome::Accepted); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - - let proposal_receipt = client - .order() - .publish_order_revision_proposal_with_identity( - &seller_identity, - &root_event_id, - &decision_event_id, - &proposal, - ) - .await?; - let decision_receipt = client - .order() - .publish_order_revision_decision_with_identity( - &buyer_identity, - &root_event_id, - &decision.prev_event_id, - &decision, - ) - .await?; - - assert_eq!(proposal_receipt.event_kind, Some(3424)); - assert_eq!(decision_receipt.event_kind, Some(3425)); - - match proposal_receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!(relay_receipt.event.kind, 3424); - assert_eq!(relay_receipt.event.author, seller_pubkey); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), buyer_pubkey.clone()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_root".to_owned(), root_event_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_prev".to_owned(), decision_event_id.to_string()]) - ); - let envelope = client - .order() - .parse_order_revision_proposal(&relay_receipt.event) - .expect("order revision proposal"); - assert_eq!(envelope.order_id, proposal.order_id); - assert_eq!(envelope.listing_addr, proposal.listing_addr); - assert_eq!(envelope.payload.revision_id, "revision-1"); - assert_eq!(envelope.payload.economics.total, usd("15")); - assert_eq!(envelope.payload.reason, "update count"); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - match decision_receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!(relay_receipt.event.kind, 3425); - assert_eq!(relay_receipt.event.author, buyer_pubkey); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), seller_pubkey]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_root".to_owned(), root_event_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_prev".to_owned(), event_id_wire('3')]) - ); - let envelope = client - .order() - .parse_order_revision_decision(&relay_receipt.event) - .expect("order revision decision"); - assert_eq!(envelope.order_id, decision.order_id); - assert_eq!(envelope.listing_addr, decision.listing_addr); - assert_eq!(envelope.payload.revision_id, decision.revision_id); - assert_eq!( - envelope.payload.decision, - RadrootsOrderRevisionOutcome::Accepted - ); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_lifecycle_publish_accepts_sdk_built_payloads() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let buyer_pubkey = buyer_identity.public_key_hex(); - let seller_pubkey = seller_identity.public_key_hex(); - let root_event_id = event_id('1'); - let decision_event_id = event_id('2'); - let fulfillment_event_id = event_id('4'); - let fulfillment = sample_fulfillment_update(buyer_pubkey.clone(), seller_pubkey.clone()); - let cancellation = sample_order_cancellation(buyer_pubkey.clone(), seller_pubkey.clone()); - let receipt = sample_buyer_receipt(buyer_pubkey.clone(), seller_pubkey.clone()); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - - let fulfillment_receipt = client - .order() - .publish_fulfillment_update_with_identity( - &seller_identity, - &root_event_id, - &decision_event_id, - &fulfillment, - ) - .await?; - let cancellation_receipt = client - .order() - .publish_order_cancellation_with_identity( - &buyer_identity, - &root_event_id, - &root_event_id, - &cancellation, - ) - .await?; - let buyer_receipt = client - .order() - .publish_buyer_receipt_with_identity( - &buyer_identity, - &root_event_id, - &fulfillment_event_id, - &receipt, - ) - .await?; - - assert_eq!(fulfillment_receipt.event_kind, Some(3433)); - assert_eq!(cancellation_receipt.event_kind, Some(3432)); - assert_eq!(buyer_receipt.event_kind, Some(3434)); - - match fulfillment_receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!(relay_receipt.event.kind, 3433); - assert_eq!(relay_receipt.event.author, seller_pubkey); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), buyer_pubkey.clone()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_root".to_owned(), root_event_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_prev".to_owned(), decision_event_id.to_string()]) - ); - let envelope = client - .order() - .parse_fulfillment_update(&relay_receipt.event) - .expect("active fulfillment update"); - assert_eq!(envelope.order_id, fulfillment.order_id); - assert_eq!(envelope.listing_addr, fulfillment.listing_addr); - assert_eq!(envelope.payload.status, fulfillment.status); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - match cancellation_receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!(relay_receipt.event.kind, 3432); - assert_eq!(relay_receipt.event.author, buyer_pubkey); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), seller_pubkey.clone()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_root".to_owned(), root_event_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_prev".to_owned(), root_event_id.to_string()]) - ); - let envelope = client - .order() - .parse_order_cancellation(&relay_receipt.event) - .expect("order cancellation"); - assert_eq!(envelope.order_id, cancellation.order_id); - assert_eq!(envelope.listing_addr, cancellation.listing_addr); - assert_eq!(envelope.payload.reason, cancellation.reason); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - match buyer_receipt.transport_receipt { - SdkTransportReceipt::RelayDirect(relay_receipt) => { - assert_eq!(relay_receipt.event.kind, 3434); - assert_eq!(relay_receipt.event.author, buyer_pubkey); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["p".to_owned(), seller_pubkey]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_root".to_owned(), root_event_id.to_string()]) - ); - assert!( - relay_receipt - .event - .tags - .contains(&vec!["e_prev".to_owned(), fulfillment_event_id.to_string()]) - ); - let envelope = client - .order() - .parse_buyer_receipt(&relay_receipt.event) - .expect("active buyer receipt"); - assert_eq!(envelope.order_id, receipt.order_id); - assert_eq!(envelope.listing_addr, receipt.listing_addr); - assert_eq!(envelope.payload.received, receipt.received); - } - SdkTransportReceipt::Radrootsd(_) => panic!("unexpected radrootsd receipt"), - } - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_decision_publish_builds_and_publishes_payload() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let payload = sample_order_decision( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - let root_event_id = event_id('1'); - - let receipt = client - .order() - .publish_order_decision_with_identity( - &seller_identity, - &root_event_id, - &root_event_id, - &payload, - ) - .await?; - - assert_eq!(receipt.transport, SdkTransportMode::RelayDirect); - assert_eq!(receipt.event_kind, Some(3423)); - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_request_publish_builds_and_publishes_payload() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let payload = sample_order_request( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - - let receipt = client - .order() - .publish_order_request_with_identity(&buyer_identity, &listing_event_ptr(), &payload) - .await?; - - assert_eq!(receipt.transport, SdkTransportMode::RelayDirect); - assert_eq!(receipt.event_kind, Some(3422)); - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_request_publish_rejects_radrootsd_transport_mode() -> TestResult<()> { - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let payload = sample_order_request( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::production(); - config.transport = SdkTransportMode::Radrootsd; - config.signer = SignerConfig::LocalIdentity; - let client = RadrootsSdkClient::from_config(config)?; - - let error = client - .order() - .publish_order_request_with_identity(&buyer_identity, &listing_event_ptr(), &payload) - .await - .expect_err("unsupported transport"); - - assert!(matches!( - error, - SdkPublishError::UnsupportedTransport { - transport: SdkTransportMode::Radrootsd, - operation: "order.publish_order_request_with_identity", - } - )); - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_request_publish_rejects_draft_only_signer_mode() -> TestResult<()> { - let relay = AckRelay::spawn().await?; - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let payload = sample_order_request( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::DraftOnly; - config.relay = RelayConfig { - urls: vec![relay.url().to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - - let error = client - .order() - .publish_order_request_with_identity(&buyer_identity, &listing_event_ptr(), &payload) - .await - .expect_err("unsupported signer mode"); - - assert!(matches!( - error, - SdkPublishError::UnsupportedSignerMode { - transport: SdkTransportMode::RelayDirect, - signer: SignerConfig::DraftOnly, - required: SignerConfig::LocalIdentity, - operation: "order.publish_order_request_with_identity", - } - )); - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_request_publish_rejects_invalid_economics() -> TestResult<()> { - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let mut payload = sample_order_request( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - payload.economics.items[0].bin_count = 1; - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.relay = RelayConfig { - urls: vec!["ws://127.0.0.1:9".to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - - let error = client - .order() - .publish_order_request_with_identity(&buyer_identity, &listing_event_ptr(), &payload) - .await - .expect_err("invalid economics"); - - assert!(matches!(error, SdkPublishError::Encode(_))); - - Ok(()) -} - -#[tokio::test] -async fn relay_direct_order_request_publish_reports_setup_error_detail() -> TestResult<()> { - let buyer_identity = RadrootsIdentity::generate(); - let seller_identity = RadrootsIdentity::generate(); - let payload = sample_order_request( - buyer_identity.public_key_hex(), - seller_identity.public_key_hex(), - ); - let mut config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom); - config.transport = SdkTransportMode::RelayDirect; - config.signer = SignerConfig::LocalIdentity; - config.network.timeout_ms = 10; - config.relay = RelayConfig { - urls: vec!["ws://127.0.0.1:9".to_owned()], - }; - let client = RadrootsSdkClient::from_config(config)?; - - let error = client - .order() - .publish_order_request_with_identity(&buyer_identity, &listing_event_ptr(), &payload) - .await - .expect_err("relay setup error"); - - assert!(matches!( - error, - SdkPublishError::RelaySetup { - transport: SdkTransportMode::RelayDirect, - operation: "order.publish_order_request_with_identity", - target_relays, - error: _, - } if target_relays == vec!["ws://127.0.0.1:9".to_owned()] - )); - - Ok(()) -} - -#[tokio::test] async fn relay_direct_farm_publish_rejects_radrootsd_transport_mode() -> TestResult<()> { let identity = RadrootsIdentity::generate(); let mut config = RadrootsSdkConfig::production(); diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs @@ -85,6 +85,66 @@ fn migrated_runtime_tests_stay_on_product_runtime_boundary() { } } +#[test] +fn legacy_order_direct_publish_facades_are_removed_from_sdk_client() { + let source = read_source( + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("src/client.rs") + .as_path(), + ); + + for forbidden in [ + "publish_order_request_with_identity", + "publish_order_decision_with_identity", + "publish_order_revision_proposal_with_identity", + "publish_order_revision_decision_with_identity", + "publish_order_cancellation_with_identity", + "publish_fulfillment_update_with_identity", + "publish_buyer_receipt_with_identity", + "publish_order_request_draft_with_identity", + "publish_order_decision_draft_with_identity", + "publish_order_revision_proposal_draft_with_identity", + "publish_order_revision_decision_draft_with_identity", + "publish_order_cancellation_draft_with_identity", + "publish_fulfillment_update_draft_with_identity", + "publish_buyer_receipt_draft_with_identity", + "build_order_request_draft", + "build_order_decision_draft", + "build_order_revision_proposal_draft", + "build_order_revision_decision_draft", + "build_order_cancellation_draft", + "build_fulfillment_update_draft", + "build_buyer_receipt_draft", + "parse_order_request", + "parse_order_decision", + "parse_order_revision_proposal", + "parse_order_revision_decision", + "parse_order_cancellation", + "parse_fulfillment_update", + "parse_buyer_receipt", + "validate_listing_event", + ] { + assert!( + !source.contains(forbidden), + "src/client.rs must not expose legacy order direct facade `{forbidden}`" + ); + } +} + +#[test] +fn legacy_trade_client_root_export_is_removed() { + let source = read_source( + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("src/lib.rs") + .as_path(), + ); + + assert!( + !source.contains("TradeClient"), + "src/lib.rs must not re-export the legacy TradeClient facade" + ); +} + fn product_runtime_file_stays_on_boundary(relative_path: &str) { let source = read_source( Path::new(env!("CARGO_MANIFEST_DIR"))