commit 93ca97a75b53d83a4c4fcc8d23e7b5437d5dbab5
parent 731029342394b7253a20818d07806f06a7c68f29
Author: triesap <tyson@radroots.org>
Date: Thu, 16 Jul 2026 12:46:45 +0000
sdk: harden release product bindings
- remove retired order operations and DTO roots from active package contracts
- publish canonical trade capability and error catalog surfaces
- switch MYC NIP-46 permissions to canonical trade mutation kinds
- regenerate TypeScript bindings with canonical trade counters
Diffstat:
14 files changed, 733 insertions(+), 82 deletions(-)
diff --git a/crates/event_bindings/src/lib.rs b/crates/event_bindings/src/lib.rs
@@ -18,7 +18,8 @@ mod tests {
assert!(constants.contains(RADROOTS_LISTING_PRODUCT_TAG_KEYS[0]));
assert!(kinds_ts.contains("KIND_LISTING"));
assert!(kinds_ts.contains(&kinds::KIND_LISTING.to_string()));
- assert!(kinds_ts.contains("KIND_ORDER_REQUEST"));
- assert!(kinds_ts.contains(&kinds::KIND_ORDER_REQUEST.to_string()));
+ assert!(kinds_ts.contains("KIND_TRADE_PROPOSAL"));
+ assert!(kinds_ts.contains(&kinds::KIND_TRADE_PROPOSAL.to_string()));
+ assert!(!kinds_ts.contains("KIND_ORDER_REQUEST"));
}
}
diff --git a/crates/event_bindings/src/model.rs b/crates/event_bindings/src/model.rs
@@ -113,12 +113,20 @@ const EVENT_KIND_EXPORTS: &[(&str, u32)] = &[
("KIND_APP_DATA", kinds::KIND_APP_DATA),
("KIND_LISTING", kinds::KIND_LISTING),
("KIND_APPLICATION_HANDLER", kinds::KIND_APPLICATION_HANDLER),
- ("KIND_ORDER_REQUEST", kinds::KIND_ORDER_REQUEST),
- ("KIND_ORDER_DECISION", kinds::KIND_ORDER_DECISION),
- ("KIND_ORDER_CANCELLATION", kinds::KIND_ORDER_CANCELLATION),
+ ("KIND_TRADE_PROPOSAL", kinds::KIND_TRADE_PROPOSAL),
+ ("KIND_TRADE_DECISION", kinds::KIND_TRADE_DECISION),
(
- "KIND_TRADE_FORBIDDEN_3431",
- kinds::KIND_TRADE_FORBIDDEN_3431,
+ "KIND_TRADE_REVISION_PROPOSAL",
+ kinds::KIND_TRADE_REVISION_PROPOSAL,
+ ),
+ (
+ "KIND_TRADE_REVISION_DECISION",
+ kinds::KIND_TRADE_REVISION_DECISION,
+ ),
+ ("KIND_TRADE_CANCELLATION", kinds::KIND_TRADE_CANCELLATION),
+ (
+ "KIND_TRADE_SELLER_RESERVATION_ASSERTION",
+ kinds::KIND_TRADE_SELLER_RESERVATION_ASSERTION,
),
(
"KIND_TRADE_VALIDATION_RECEIPT",
diff --git a/crates/sdk/README b/crates/sdk/README
@@ -41,18 +41,17 @@ and radrootsd execution consume signed outbox events; neither path owns signing.
`push_outbox_with_transport(...)` remains available for tests and controlled transport-level
substrate checks. `radrootsd-execution` adds daemon-resolved publishing through `publish.event`.
-`sdk.trades()` exposes the local trade runtime surface. With `runtime`, callers can ingest local trade
-evidence, read `sdk.trades().status(...)`, resync through `sdk.trades().resync()`, inspect
-validation receipts through `sdk.trades().validation_receipts()`, and read seller inbox projections
-through `sdk.trades().seller()`.
-`sdk.trades().status(...)` accepts `TradeStatusRequest` and reads local projections; it returns typed
-source, event count, limit state, event IDs, ambiguity candidates, eligibility, next-action, and
-reducer issue data. Status is not a network fetch.
-
-Configured-signer trade writes compile when both `runtime` and `signer-adapters` are enabled. Buyer
-write workflows use `sdk.trades().buyer()` for propose and cancel actions. Seller write workflows
-use `sdk.trades().seller()` for accept and decline actions. Runtime-only builds intentionally expose
-no buyer write handle and no trade mutation request DTOs.
+`sdk.trades()` exposes the local trade runtime surface. With `runtime`, callers can read
+`sdk.trades().capabilities()`, seal/open/delete protected private artifacts, issue semantic trade
+commands through `sdk.trades().commands()`, and read semantic projections through
+`sdk.trades().queries()`. Query methods read local projections and evidence; they are not network
+fetches.
+
+Configured-signer trade writes compile when both `runtime` and `signer-adapters` are enabled.
+Trade write workflows use `SubmitProposalRequest`, `ProposeRevisionRequest`,
+`DecideCandidateRequest`, `CancelTradeRequest`, and `ResumeOperationRequest` through the command
+service. Runtime-only builds keep explicit-signer methods available and do not expose a parallel
+buyer/seller workflow namespace.
The `local-runtime` feature is the curated feature bundle for local product runtime consumers. It
enables `std`, `serde`, `serde_json`, `runtime`, `signer-adapters`, `transport-nostr-runtime`, and
@@ -64,7 +63,7 @@ targets Nostr relay URLs. `local-runtime-radrootsd-execution` uses daemon-resolv
`radroots_sdk_myc_nip46_product_permissions()` and
`radroots_sdk_myc_nip46_product_permission_strings()` expose the SDK product NIP-46
`sign_event:<kind>` permission set for Myc connection setup. The set is derived from the farm,
-listing, and trade event kinds the SDK can write.
+listing, and canonical trade mutation event kinds the SDK can write.
Relay URL policy is explicit. Public relay URLs must use `wss://`. Local development `ws://` relay
URLs are accepted only under `NostrRelayUrlPolicy::Localhost` and only for `localhost`, `127.0.0.1`,
@@ -92,7 +91,7 @@ preparation, signed-event verification, decoded event matching, and manifest has
local runtime storage.
`sdk_v1_local_enqueue_and_mock_sync` shows localhost Nostr target selection, configured local-key
signing, prepared listing enqueue, `push_outbox_with_transport(...)` with a Nostr transport facade, and
-`TradeStatusRequest`. `sdk_v1_myc_nip46_signer_setup` shows Myc NIP-46 signer provider setup and
+queued outbox sync. `sdk_v1_myc_nip46_signer_setup` shows Myc NIP-46 signer provider setup and
product permission derivation at the SDK boundary. The examples stay on product APIs and do not use
wire-event internals.
@@ -118,7 +117,9 @@ stable method surface: `code`, `class`, `retryable`, `detail_json`, and `recover
## Runtime DTO Stability
Runtime request DTOs are constructor-led and marked non-exhaustive where they carry public fields:
-`ListingPreparePublishRequest`, `ListingEnqueuePublishRequest`, `TradeStatusRequest`,
+`ListingPreparePublishRequest`, `ListingEnqueuePublishRequest`, `SubmitProposalRequest`,
+`ProposeRevisionRequest`, `DecideCandidateRequest`, `CancelTradeRequest`, `ResumeOperationRequest`,
+`GetTradeRequest`, `ListTradesRequest`, `RefreshTradeEvidenceRequest`, `InspectEvidenceRequest`,
`StorageStatusRequest`, `BackupRequest`, `IntegrityRequest`, `SyncStatusRequest`, and
`PushOutboxRequest`. Restore uses the same request posture through `RestoreRequest`. Use `new`,
`parse`, `default`, and `with_*` methods rather than struct literals.
diff --git a/crates/sdk/examples/sdk_v1_myc_nip46_signer_setup.rs b/crates/sdk/examples/sdk_v1_myc_nip46_signer_setup.rs
@@ -1,3 +1,4 @@
+use radroots_event::kinds::KIND_TRADE_PROPOSAL;
use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys};
use radroots_nostr_connect::prelude::{
RadrootsNostrConnectClientTarget, RadrootsNostrConnectError,
@@ -50,6 +51,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(status.mode, RadrootsSdkSignerMode::MycNip46);
assert!(permissions.iter().any(|value| value == "sign_event:30340"));
+ assert!(
+ permissions
+ .iter()
+ .any(|value| value == &format!("sign_event:{KIND_TRADE_PROPOSAL}"))
+ );
+ assert!(!permissions.iter().any(|value| value == "sign_event:3422"));
println!("configured signer mode: {}", status.mode.as_str());
println!("requested permissions: {}", permissions.join(","));
Ok(())
diff --git a/crates/sdk/src/error.rs b/crates/sdk/src/error.rs
@@ -88,6 +88,353 @@ impl RadrootsSdkTradeErrorKind {
}
#[cfg(feature = "runtime")]
+const RECOVERY_INSPECT_LOCAL_STORES: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::InspectLocalStores];
+#[cfg(feature = "runtime")]
+const RECOVERY_INSPECT_GEONAMES_ASSET: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::InspectGeoNamesAsset];
+#[cfg(feature = "runtime")]
+const RECOVERY_RETRY_OPERATION_WITH_SAME_IDEMPOTENCY_KEY: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::RetryOperationWithSameIdempotencyKey];
+#[cfg(feature = "runtime")]
+const RECOVERY_CONFIGURE_TRANSPORT_TARGETS: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::ConfigureTransportTargets];
+#[cfg(feature = "runtime")]
+const RECOVERY_CONFIGURE_GEONAMES_CACHE: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::ConfigureGeoNamesCache];
+#[cfg(feature = "runtime")]
+const RECOVERY_CONFIGURE_SIGNER: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::ConfigureSigner];
+#[cfg(feature = "runtime")]
+const RECOVERY_FIX_REQUEST: &[RadrootsSdkRecoveryAction] = &[RadrootsSdkRecoveryAction::FixRequest];
+#[cfg(feature = "runtime")]
+const RECOVERY_SELECT_AUTHORIZED_ACTOR: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::SelectAuthorizedActor];
+#[cfg(feature = "runtime")]
+const RECOVERY_COMPLETE_SIGNER_AUTHENTICATION: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::CompleteSignerAuthentication];
+#[cfg(feature = "runtime")]
+const RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::RetryAfterTransportFailure];
+#[cfg(feature = "runtime")]
+const RECOVERY_RETRY_GEONAMES_DOWNLOAD: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::RetryGeoNamesDownload];
+#[cfg(feature = "runtime")]
+const RECOVERY_ENABLE_REQUIRED_FEATURE: &[RadrootsSdkRecoveryAction] =
+ &[RadrootsSdkRecoveryAction::EnableRequiredFeature];
+
+#[cfg(feature = "runtime")]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
+pub struct RadrootsSdkErrorCatalogEntry {
+ pub code: &'static str,
+ pub class: RadrootsSdkErrorClass,
+ pub retryable: bool,
+ pub recovery_actions: &'static [RadrootsSdkRecoveryAction],
+}
+
+#[cfg(feature = "runtime")]
+impl RadrootsSdkErrorCatalogEntry {
+ const fn new(
+ code: &'static str,
+ class: RadrootsSdkErrorClass,
+ retryable: bool,
+ recovery_actions: &'static [RadrootsSdkRecoveryAction],
+ ) -> Self {
+ Self {
+ code,
+ class,
+ retryable,
+ recovery_actions,
+ }
+ }
+}
+
+#[cfg(feature = "runtime")]
+pub const RADROOTS_SDK_ERROR_CATALOG: &[RadrootsSdkErrorCatalogEntry] = &[
+ RadrootsSdkErrorCatalogEntry::new(
+ "io",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "clock_before_unix_epoch",
+ RadrootsSdkErrorClass::Clock,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "timestamp_out_of_range",
+ RadrootsSdkErrorClass::Clock,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "unauthorized_actor",
+ RadrootsSdkErrorClass::Authorization,
+ false,
+ RECOVERY_SELECT_AUTHORIZED_ACTOR,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_pubkey_mismatch",
+ RadrootsSdkErrorClass::Authorization,
+ false,
+ RECOVERY_SELECT_AUTHORIZED_ACTOR,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_unavailable",
+ RadrootsSdkErrorClass::Configuration,
+ false,
+ RECOVERY_CONFIGURE_SIGNER,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_request_rejected",
+ RadrootsSdkErrorClass::Authorization,
+ false,
+ RECOVERY_SELECT_AUTHORIZED_ACTOR,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_request_timed_out",
+ RadrootsSdkErrorClass::Transport,
+ true,
+ RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_auth_challenge_pending",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_COMPLETE_SIGNER_AUTHENTICATION,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_transport",
+ RadrootsSdkErrorClass::Transport,
+ true,
+ RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_protocol",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "signer_returned_event_drift",
+ RadrootsSdkErrorClass::Authorization,
+ false,
+ RECOVERY_SELECT_AUTHORIZED_ACTOR,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "empty_transport_targets",
+ RadrootsSdkErrorClass::Configuration,
+ false,
+ RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "transport_target_limit_exceeded",
+ RadrootsSdkErrorClass::Configuration,
+ false,
+ RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "invalid_relay_url",
+ RadrootsSdkErrorClass::Configuration,
+ false,
+ RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "idempotency_conflict",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_RETRY_OPERATION_WITH_SAME_IDEMPOTENCY_KEY,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_invalid_envelope",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_invalid_command_body",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_private_artifact_missing",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_private_artifact_commitment_mismatch",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_private_artifact_acknowledgement_missing",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_not_found",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_query_limit_invalid",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "trade_cursor_invalid",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "privacy_preflight",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "product_sync_unsupported",
+ RadrootsSdkErrorClass::Unsupported,
+ false,
+ RECOVERY_ENABLE_REQUIRED_FEATURE,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "reticulum_transport_unavailable",
+ RadrootsSdkErrorClass::Unsupported,
+ false,
+ RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "reticulum_transport_deferred",
+ RadrootsSdkErrorClass::Unsupported,
+ false,
+ RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "product_sync_transport_setup_failure",
+ RadrootsSdkErrorClass::Transport,
+ true,
+ RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "authority",
+ RadrootsSdkErrorClass::Authorization,
+ false,
+ RECOVERY_SELECT_AUTHORIZED_ACTOR,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "event_store",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "invalid_request",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "unsupported_profile_schema",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "listing_edit",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "listing_mutation",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "outbox",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "private_store",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "studio_store",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "geonames_configuration",
+ RadrootsSdkErrorClass::Configuration,
+ false,
+ RECOVERY_CONFIGURE_GEONAMES_CACHE,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "geonames_download",
+ RadrootsSdkErrorClass::Transport,
+ true,
+ RECOVERY_RETRY_GEONAMES_DOWNLOAD,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "geonames_cache",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_GEONAMES_ASSET,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "geonames_integrity",
+ RadrootsSdkErrorClass::Storage,
+ false,
+ RECOVERY_INSPECT_GEONAMES_ASSET,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "geonames_schema",
+ RadrootsSdkErrorClass::Storage,
+ false,
+ RECOVERY_INSPECT_GEONAMES_ASSET,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "geonames_lookup",
+ RadrootsSdkErrorClass::Request,
+ false,
+ RECOVERY_FIX_REQUEST,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "transport",
+ RadrootsSdkErrorClass::Transport,
+ true,
+ RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
+ ),
+ RadrootsSdkErrorCatalogEntry::new(
+ "projection",
+ RadrootsSdkErrorClass::Storage,
+ true,
+ RECOVERY_INSPECT_LOCAL_STORES,
+ ),
+];
+
+#[cfg(feature = "runtime")]
+pub fn radroots_sdk_error_catalog() -> &'static [RadrootsSdkErrorCatalogEntry] {
+ RADROOTS_SDK_ERROR_CATALOG
+}
+
+#[cfg(feature = "runtime")]
#[derive(Debug)]
#[non_exhaustive]
pub enum RadrootsSdkError {
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
@@ -60,8 +60,9 @@ pub use radroots_runtime_contract_v1 as runtime_contract_v1;
#[cfg(feature = "runtime")]
pub use crate::error::{
- RadrootsSdkError, RadrootsSdkErrorClass, RadrootsSdkGeoNamesErrorKind,
- RadrootsSdkRecoveryAction, RadrootsSdkTradeErrorKind,
+ RADROOTS_SDK_ERROR_CATALOG, RadrootsSdkError, RadrootsSdkErrorCatalogEntry,
+ RadrootsSdkErrorClass, RadrootsSdkGeoNamesErrorKind, RadrootsSdkRecoveryAction,
+ RadrootsSdkTradeErrorKind, radroots_sdk_error_catalog,
};
#[cfg(feature = "runtime")]
pub use crate::farms_runtime::{
@@ -178,12 +179,17 @@ pub use crate::trade_runtime::{
RefreshTradeEvidenceRequest, ResumeOperationRequest, SubmitProposalRequest,
TRADE_CANCEL_OPERATION_KIND, TRADE_DECIDE_CANDIDATE_OPERATION_KIND,
TRADE_PROPOSE_REVISION_OPERATION_KIND, TRADE_QUERY_DEFAULT_LIMIT, TRADE_QUERY_MAX_LIMIT,
- TRADE_RESUME_OPERATION_KIND, TRADE_SUBMIT_PROPOSAL_OPERATION_KIND, TradeCommandLifecycleState,
- TradeCommandReceipt, TradeCommandService, TradeListAnyOf, TradeListFilter, TradeListSort,
- TradePrivateArtifactDeleteReceipt, TradePrivateArtifactDeleteRequest, TradePrivateArtifactKind,
- TradePrivateArtifactOpenReceipt, TradePrivateArtifactOpenRequest,
- TradePrivateArtifactSealReceipt, TradePrivateArtifactSealRequest,
- TradePrivateTermsAvailabilityView, TradeQueryService, TradeStatusView, TradeSummaryView,
+ TRADE_RESUME_OPERATION_KIND, TRADE_RUNTIME_CAPABILITY_API_VERSION,
+ TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID, TRADE_RUNTIME_PROTOCOL_PROFILE_ID,
+ TRADE_RUNTIME_STORAGE_PROFILE_ID, TRADE_RUNTIME_WIRE_PROFILE_ID,
+ TRADE_SUBMIT_PROPOSAL_OPERATION_KIND, TradeCommandLifecycleState, TradeCommandReceipt,
+ TradeCommandService, TradeCoreMvpCapabilityReport, TradeListAnyOf, TradeListFilter,
+ TradeListSort, TradeOptionalIntegrationCapabilityReport, TradePrivateArtifactDeleteReceipt,
+ TradePrivateArtifactDeleteRequest, TradePrivateArtifactKind, TradePrivateArtifactOpenReceipt,
+ TradePrivateArtifactOpenRequest, TradePrivateArtifactSealReceipt,
+ TradePrivateArtifactSealRequest, TradePrivateTermsAvailabilityView,
+ TradeProtocolCapabilityReport, TradeQueryService, TradeRuntimeCapabilityReport,
+ TradeStatusView, TradeStorageCapabilityReport, TradeSummaryView,
};
#[cfg(feature = "runtime")]
pub use crate::transport::{
diff --git a/crates/sdk/src/signer_provider.rs b/crates/sdk/src/signer_provider.rs
@@ -7,7 +7,8 @@ use radroots_authority::{
use radroots_event::draft::{RadrootsEventDraft, RadrootsSignedEvent};
use radroots_event::ids::RadrootsPublicKey;
use radroots_event::kinds::{
- KIND_FARM, KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
+ KIND_FARM, KIND_LISTING, KIND_TRADE_CANCELLATION, KIND_TRADE_DECISION, KIND_TRADE_PROPOSAL,
+ KIND_TRADE_REVISION_DECISION, KIND_TRADE_REVISION_PROPOSAL,
};
use radroots_event::wire::RadrootsNip01EventWire;
use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys};
@@ -26,12 +27,14 @@ use uuid::Uuid;
pub type RadrootsSdkNip46TransportFuture<'a, T> = RadrootsNostrConnectClientTransportFuture<'a, T>;
pub type RadrootsSdkLocalSignerCapability = dyn RadrootsEventSigner + Send + Sync;
-pub const RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS: [u32; 5] = [
+pub const RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS: [u32; 7] = [
KIND_FARM,
KIND_LISTING,
- KIND_ORDER_REQUEST,
- KIND_ORDER_DECISION,
- KIND_ORDER_CANCELLATION,
+ KIND_TRADE_PROPOSAL,
+ KIND_TRADE_DECISION,
+ KIND_TRADE_REVISION_PROPOSAL,
+ KIND_TRADE_REVISION_DECISION,
+ KIND_TRADE_CANCELLATION,
];
pub const RADROOTS_SDK_MYC_NIP46_DEFAULT_REQUEST_TIMEOUT_MS: u64 = 30_000;
diff --git a/crates/sdk/src/trade_runtime.rs b/crates/sdk/src/trade_runtime.rs
@@ -5,7 +5,8 @@ use crate::{
RadrootsClient, RadrootsSdkError, RadrootsSdkRecoveryAction, RadrootsSdkTradeErrorKind,
SatisfactionPolicy, SdkIdempotencyKey, SdkMutationState, TargetPolicy, TradesClient,
private_store::{
- SdkPrivateTradeArtifactInput, SdkPrivateTradeArtifactKind, SdkPrivateTradeArtifactMetadata,
+ SDK_PRIVATE_STORE_SCHEMA_VERSION, SdkPrivateTradeArtifactInput,
+ SdkPrivateTradeArtifactKind, SdkPrivateTradeArtifactMetadata,
},
runtime::sdk_now_ms,
workflow_runtime::{
@@ -20,9 +21,12 @@ use radroots_authority::{RadrootsActorContext, RadrootsEventSigner};
use radroots_event::{
draft::RadrootsEventDraft,
ids::{RadrootsEventId, RadrootsTradeCandidateId, RadrootsTradeId, RadrootsTradeMutationId},
+ kinds::TRADE_MUTATION_EVENT_KINDS,
trade::{
- RadrootsTradeDecisionV1, RadrootsTradeMutationBodyV1, RadrootsTradeMutationEnvelopeV1,
- RadrootsTradePrivateTermsRefV1, trade_mutation_from_canonical_content,
+ RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES, RADROOTS_TRADE_MUTATION_CONTRACT_IDS,
+ RADROOTS_TRADE_SCHEMA_VERSION, RadrootsTradeDecisionV1, RadrootsTradeMutationBodyV1,
+ RadrootsTradeMutationEnvelopeV1, RadrootsTradePrivateTermsRefV1,
+ trade_mutation_from_canonical_content,
},
};
#[cfg(feature = "runtime")]
@@ -62,6 +66,17 @@ pub const TRADE_QUERY_DEFAULT_LIMIT: u32 = 50;
#[cfg(feature = "runtime")]
pub const TRADE_QUERY_MAX_LIMIT: u32 = 100;
#[cfg(feature = "runtime")]
+pub const TRADE_RUNTIME_CAPABILITY_API_VERSION: u16 = 1;
+#[cfg(feature = "runtime")]
+pub const TRADE_RUNTIME_PROTOCOL_PROFILE_ID: &str = "radroots.trade.protocol.v1";
+#[cfg(feature = "runtime")]
+pub const TRADE_RUNTIME_WIRE_PROFILE_ID: &str = "radroots.trade.nostr_regular_immutable_jcs.v1";
+#[cfg(feature = "runtime")]
+pub const TRADE_RUNTIME_STORAGE_PROFILE_ID: &str = "radroots.sdk.trade.sqlite.v1";
+#[cfg(feature = "runtime")]
+pub const TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID: &str =
+ "radroots.sdk.trade.private_artifacts.v1";
+#[cfg(feature = "runtime")]
const TRADE_MUTATION_QUERY_LIMIT: u32 = 1_000;
#[cfg(feature = "runtime")]
const TRADE_LIST_CURSOR_VERSION: u8 = 1;
@@ -244,6 +259,10 @@ impl<'client> TradeQueryService<'client> {
#[cfg(feature = "runtime")]
impl<'client> TradesClient<'client> {
+ pub fn capabilities(&self) -> TradeRuntimeCapabilityReport {
+ trade_runtime_capabilities()
+ }
+
pub fn commands(&self) -> TradeCommandService<'client> {
TradeCommandService::new(self.sdk)
}
@@ -666,6 +685,109 @@ pub struct TradePrivateArtifactDeleteReceipt {
}
#[cfg(feature = "runtime")]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
+#[non_exhaustive]
+pub struct TradeRuntimeCapabilityReport {
+ pub api_version: u16,
+ pub protocol: TradeProtocolCapabilityReport,
+ pub storage: TradeStorageCapabilityReport,
+ pub core_mvp: TradeCoreMvpCapabilityReport,
+ pub optional_integrations: TradeOptionalIntegrationCapabilityReport,
+}
+
+#[cfg(feature = "runtime")]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
+#[non_exhaustive]
+pub struct TradeProtocolCapabilityReport {
+ pub protocol_profile_id: &'static str,
+ pub wire_profile_id: &'static str,
+ pub schema_version: u16,
+ pub mutation_contract_ids: Vec<&'static str>,
+ pub mutation_event_kinds: Vec<u32>,
+ pub reducer_contract_id: &'static str,
+ pub reducer_version: u16,
+}
+
+#[cfg(feature = "runtime")]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
+#[non_exhaustive]
+pub struct TradeStorageCapabilityReport {
+ pub storage_profile_id: &'static str,
+ pub private_storage_profile_id: &'static str,
+ pub private_store_schema_version: i64,
+ pub max_private_artifact_bytes: usize,
+ pub private_artifact_kinds: Vec<TradePrivateArtifactKind>,
+}
+
+#[cfg(feature = "runtime")]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
+#[non_exhaustive]
+pub struct TradeCoreMvpCapabilityReport {
+ pub commands: bool,
+ pub queries: bool,
+ pub local_event_store: bool,
+ pub semantic_outbox: bool,
+ pub protected_private_artifacts: bool,
+ pub backup_restore: bool,
+ pub local_signer: bool,
+}
+
+#[cfg(feature = "runtime")]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
+#[non_exhaustive]
+pub struct TradeOptionalIntegrationCapabilityReport {
+ pub myc_nip46_signer: bool,
+ pub radrootsd_execution: bool,
+ pub rhi_attestation: bool,
+ pub tangle_transport: bool,
+ pub reticulum_transport: bool,
+}
+
+#[cfg(feature = "runtime")]
+fn trade_runtime_capabilities() -> TradeRuntimeCapabilityReport {
+ TradeRuntimeCapabilityReport {
+ api_version: TRADE_RUNTIME_CAPABILITY_API_VERSION,
+ protocol: TradeProtocolCapabilityReport {
+ protocol_profile_id: TRADE_RUNTIME_PROTOCOL_PROFILE_ID,
+ wire_profile_id: TRADE_RUNTIME_WIRE_PROFILE_ID,
+ schema_version: RADROOTS_TRADE_SCHEMA_VERSION,
+ mutation_contract_ids: RADROOTS_TRADE_MUTATION_CONTRACT_IDS.to_vec(),
+ mutation_event_kinds: TRADE_MUTATION_EVENT_KINDS.to_vec(),
+ reducer_contract_id: RADROOTS_TRADE_REDUCER_CONTRACT_ID,
+ reducer_version: RADROOTS_TRADE_REDUCER_VERSION,
+ },
+ storage: TradeStorageCapabilityReport {
+ storage_profile_id: TRADE_RUNTIME_STORAGE_PROFILE_ID,
+ private_storage_profile_id: TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID,
+ private_store_schema_version: SDK_PRIVATE_STORE_SCHEMA_VERSION,
+ max_private_artifact_bytes: RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES,
+ private_artifact_kinds: vec![
+ TradePrivateArtifactKind::BindingTerms,
+ TradePrivateArtifactKind::Message,
+ TradePrivateArtifactKind::ContactBundle,
+ TradePrivateArtifactKind::DeliveryInstruction,
+ ],
+ },
+ core_mvp: TradeCoreMvpCapabilityReport {
+ commands: true,
+ queries: true,
+ local_event_store: true,
+ semantic_outbox: true,
+ protected_private_artifacts: true,
+ backup_restore: true,
+ local_signer: cfg!(feature = "local-signer"),
+ },
+ optional_integrations: TradeOptionalIntegrationCapabilityReport {
+ myc_nip46_signer: cfg!(feature = "signer-adapters"),
+ radrootsd_execution: cfg!(feature = "radrootsd-execution"),
+ rhi_attestation: false,
+ tangle_transport: false,
+ reticulum_transport: false,
+ },
+ }
+}
+
+#[cfg(feature = "runtime")]
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct GetTradeRequest {
diff --git a/crates/sdk/tests/unit/error_tests.rs b/crates/sdk/tests/unit/error_tests.rs
@@ -1,11 +1,13 @@
use super::{
- RadrootsSdkError, RadrootsSdkGeoNamesErrorKind, RadrootsSdkTradeErrorKind, redacted_relay_url,
+ RadrootsSdkError, RadrootsSdkGeoNamesErrorKind, RadrootsSdkTradeErrorKind,
+ radroots_sdk_error_catalog, redacted_relay_url,
};
use crate::privacy::{PrivacyPreflightStatus, ProductSensitivityField};
use crate::transport::ReticulumBehavior;
use radroots_authority::RadrootsAuthorityError;
use radroots_event::contract::RadrootsActorRole;
use radroots_geocoder::{GeoNamesAssetFetcher, GeoNamesBlockingHttpFetcher, GeocoderError};
+use std::collections::BTreeSet;
#[test]
fn authority_error_conversion_redacts_pubkey_mismatches_and_falls_back() {
@@ -399,6 +401,73 @@ fn sdk_error_contract_methods_cover_representative_classes_and_details() {
}
#[test]
+fn sdk_error_catalog_exposes_stable_codes_and_metadata() {
+ let catalog = radroots_sdk_error_catalog();
+ let codes = catalog
+ .iter()
+ .map(|entry| entry.code)
+ .collect::<BTreeSet<_>>();
+
+ assert_eq!(codes.len(), catalog.len());
+ assert!(codes.contains("io"));
+ assert!(codes.contains("signer_auth_challenge_pending"));
+ assert!(codes.contains("product_sync_unsupported"));
+ assert!(codes.contains("reticulum_transport_deferred"));
+ assert!(codes.contains("unsupported_profile_schema"));
+ assert!(codes.contains("geonames_lookup"));
+
+ for trade_kind in [
+ RadrootsSdkTradeErrorKind::InvalidEnvelope,
+ RadrootsSdkTradeErrorKind::InvalidCommandBody,
+ RadrootsSdkTradeErrorKind::PrivateArtifactMissing,
+ RadrootsSdkTradeErrorKind::PrivateArtifactCommitmentMismatch,
+ RadrootsSdkTradeErrorKind::PrivateArtifactAcknowledgementMissing,
+ RadrootsSdkTradeErrorKind::TradeNotFound,
+ RadrootsSdkTradeErrorKind::QueryLimitInvalid,
+ RadrootsSdkTradeErrorKind::CursorInvalid,
+ ] {
+ assert!(codes.contains(trade_kind.code()));
+ }
+
+ for entry in catalog {
+ assert!(!entry.code.is_empty());
+ assert!(!entry.recovery_actions.is_empty());
+ }
+
+ let timeout = RadrootsSdkError::SignerRequestTimedOut {
+ mode: "myc_nip46".to_owned(),
+ };
+ let timeout_entry = catalog
+ .iter()
+ .find(|entry| entry.code == timeout.code())
+ .expect("timeout catalog entry");
+ assert_eq!(timeout_entry.class, timeout.class());
+ assert_eq!(timeout_entry.retryable, timeout.retryable());
+ let timeout_recovery_actions = timeout.recovery_actions();
+ assert_eq!(
+ timeout_entry.recovery_actions,
+ timeout_recovery_actions.as_slice()
+ );
+
+ let trade = RadrootsSdkError::Trade {
+ kind: RadrootsSdkTradeErrorKind::PrivateArtifactCommitmentMismatch,
+ operation: "trade.decide_candidate".to_owned(),
+ message: "private artifact commitment mismatch".to_owned(),
+ };
+ let trade_entry = catalog
+ .iter()
+ .find(|entry| entry.code == trade.code())
+ .expect("trade catalog entry");
+ assert_eq!(trade_entry.class, trade.class());
+ assert_eq!(trade_entry.retryable, trade.retryable());
+ let trade_recovery_actions = trade.recovery_actions();
+ assert_eq!(
+ trade_entry.recovery_actions,
+ trade_recovery_actions.as_slice()
+ );
+}
+
+#[test]
fn geonames_error_conversion_maps_source_errors_to_sdk_kinds() {
let path = std::path::PathBuf::from("geonames-test.db");
let download_error = GeoNamesBlockingHttpFetcher
diff --git a/crates/sdk/tests/unit/signer_provider_tests.rs b/crates/sdk/tests/unit/signer_provider_tests.rs
@@ -4,7 +4,7 @@ use nostr::{EventBuilder, JsonUtil, Kind, Tag};
use radroots_authority::RadrootsLocalEventSigner;
use radroots_event::contract::RadrootsActorRole;
use radroots_event::draft::RadrootsEventDraft;
-use radroots_event::kinds::{KIND_COOP, KIND_FARM};
+use radroots_event::kinds::{KIND_COOP, KIND_FARM, KIND_LISTING, TRADE_MUTATION_EVENT_KINDS};
use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrSecretKey};
use radroots_nostr_connect::prelude::{
RADROOTS_NOSTR_CONNECT_RPC_KIND, RadrootsNostrConnectClientTarget, RadrootsNostrConnectError,
@@ -516,15 +516,21 @@ async fn nip46_transport_adapter_delegates_publish_and_response_poll() {
fn myc_nip46_product_permissions_cover_sdk_write_event_kinds() {
let permissions = radroots_sdk_myc_nip46_product_permissions();
let rendered = radroots_sdk_myc_nip46_product_permission_strings();
+ let mut expected_kinds = vec![KIND_FARM, KIND_LISTING];
+ expected_kinds.extend_from_slice(&TRADE_MUTATION_EVENT_KINDS);
+ assert_eq!(permissions.as_slice().len(), expected_kinds.len());
assert_eq!(
- permissions.as_slice().len(),
- RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS.len()
+ RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS.as_slice(),
+ expected_kinds.as_slice()
);
assert_eq!(rendered.len(), permissions.as_slice().len());
for kind in RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS {
assert!(rendered.contains(&format!("sign_event:{kind}")));
}
+ for old_trade_write_kind in [3422, 3423, 3432] {
+ assert!(!rendered.contains(&format!("sign_event:{old_trade_write_kind}")));
+ }
assert!(!rendered.contains(&"sign_event:1".to_owned()));
}
diff --git a/crates/sdk/tests/unit/trade_runtime_tests.rs b/crates/sdk/tests/unit/trade_runtime_tests.rs
@@ -10,8 +10,10 @@ use radroots_event::{
RadrootsAddressableCoordinate, RadrootsDTag, RadrootsEventId, RadrootsInventoryBinId,
RadrootsPublicKey, RadrootsTradeId,
},
+ kinds::TRADE_MUTATION_EVENT_KINDS,
trade::{
- RADROOTS_TRADE_DECISION_CONTRACT_ID, RADROOTS_TRADE_PROPOSAL_CONTRACT_ID,
+ RADROOTS_TRADE_DECISION_CONTRACT_ID, RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES,
+ RADROOTS_TRADE_MUTATION_CONTRACT_IDS, RADROOTS_TRADE_PROPOSAL_CONTRACT_ID,
RADROOTS_TRADE_SCHEMA_VERSION, RadrootsFulfillmentProfileV1,
RadrootsSellerReservationAssertionV1, RadrootsSellerReservationLineV1,
RadrootsTradeCancellationProfileV1, RadrootsTradeCandidateLineV1,
@@ -21,7 +23,10 @@ use radroots_event::{
},
};
use radroots_nostr::prelude::{RadrootsNostrKeys, RadrootsNostrSecretKey};
-use radroots_trade::workflow::RadrootsTradePrivateTermsStateV1;
+use radroots_trade::workflow::{
+ RADROOTS_TRADE_REDUCER_CONTRACT_ID, RADROOTS_TRADE_REDUCER_VERSION,
+ RadrootsTradePrivateTermsStateV1,
+};
const BUYER_SECRET_KEY_HEX: &str =
"10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5";
@@ -50,6 +55,67 @@ fn local_signer(secret_key_hex: &str) -> (String, RadrootsLocalEventSigner) {
)
}
+#[tokio::test]
+async fn trade_capabilities_report_canonical_release_product_surface() {
+ let sdk = RadrootsClient::builder().build().await.expect("sdk");
+ let capabilities = sdk.trades().capabilities();
+
+ assert_eq!(
+ capabilities.api_version,
+ TRADE_RUNTIME_CAPABILITY_API_VERSION
+ );
+ assert_eq!(
+ capabilities.protocol.protocol_profile_id,
+ TRADE_RUNTIME_PROTOCOL_PROFILE_ID
+ );
+ assert_eq!(
+ capabilities.protocol.wire_profile_id,
+ TRADE_RUNTIME_WIRE_PROFILE_ID
+ );
+ assert_eq!(
+ capabilities.protocol.schema_version,
+ RADROOTS_TRADE_SCHEMA_VERSION
+ );
+ assert_eq!(
+ capabilities.protocol.mutation_contract_ids,
+ RADROOTS_TRADE_MUTATION_CONTRACT_IDS.to_vec()
+ );
+ assert_eq!(
+ capabilities.protocol.mutation_event_kinds,
+ TRADE_MUTATION_EVENT_KINDS.to_vec()
+ );
+ assert!(!capabilities.protocol.mutation_event_kinds.contains(&3422));
+ assert_eq!(
+ capabilities.protocol.reducer_contract_id,
+ RADROOTS_TRADE_REDUCER_CONTRACT_ID
+ );
+ assert_eq!(
+ capabilities.protocol.reducer_version,
+ RADROOTS_TRADE_REDUCER_VERSION
+ );
+ assert_eq!(
+ capabilities.storage.storage_profile_id,
+ TRADE_RUNTIME_STORAGE_PROFILE_ID
+ );
+ assert_eq!(
+ capabilities.storage.private_storage_profile_id,
+ TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID
+ );
+ assert_eq!(
+ capabilities.storage.max_private_artifact_bytes,
+ RADROOTS_TRADE_MAX_PRIVATE_ARTIFACT_BYTES
+ );
+ assert!(capabilities.core_mvp.commands);
+ assert!(capabilities.core_mvp.queries);
+ assert!(capabilities.core_mvp.local_event_store);
+ assert!(capabilities.core_mvp.semantic_outbox);
+ assert!(capabilities.core_mvp.protected_private_artifacts);
+ assert!(capabilities.core_mvp.backup_restore);
+ assert!(!capabilities.optional_integrations.rhi_attestation);
+ assert!(!capabilities.optional_integrations.tangle_transport);
+ assert!(!capabilities.optional_integrations.reticulum_transport);
+}
+
fn buyer_actor(buyer_pubkey: &str) -> RadrootsActorContext {
RadrootsActorContext::test(buyer_pubkey, [RadrootsActorRole::Buyer]).expect("buyer")
}
diff --git a/crates/trade_bindings/src/dto.rs b/crates/trade_bindings/src/dto.rs
@@ -189,9 +189,9 @@ pub struct RadrootsTradeListingProjection {
pub delivery_method: Option<RadrootsListingDeliveryMethodImport>,
pub location: Option<RadrootsListingPublicLocationImport>,
pub images: Option<Vec<RadrootsListingImageImport>>,
- pub order_count: u32,
- pub open_order_count: u32,
- pub terminal_order_count: u32,
+ pub trade_count: u32,
+ pub open_trade_count: u32,
+ pub terminal_trade_count: u32,
}
#[derive(dto_bindgen::Dto)]
@@ -222,10 +222,10 @@ pub enum RadrootsTradeListingSortField {
SellerPubkey,
#[serde(rename = "inventory_available")]
InventoryAvailable,
- #[serde(rename = "open_order_count")]
- OpenOrderCount,
- #[serde(rename = "total_order_count")]
- TotalOrderCount,
+ #[serde(rename = "open_trade_count")]
+ OpenTradeCount,
+ #[serde(rename = "total_trade_count")]
+ TotalTradeCount,
}
#[derive(dto_bindgen::Dto)]
@@ -244,9 +244,9 @@ pub struct RadrootsTradeMarketplaceListingSummary {
pub primary_bin_id: String,
pub primary_bin_label: Option<String>,
pub primary_bin_total: RadrootsTradeListingTotal,
- pub order_count: u32,
- pub open_order_count: u32,
- pub terminal_order_count: u32,
+ pub trade_count: u32,
+ pub open_trade_count: u32,
+ pub terminal_trade_count: u32,
}
#[derive(dto_bindgen::Dto)]
diff --git a/crates/trade_bindings/src/lib.rs b/crates/trade_bindings/src/lib.rs
@@ -78,14 +78,14 @@ pub const TRADE_LARGE_INTEGER_POLICIES: &[TradeLargeIntegerPolicyEntry] = &[
"RadrootsTradeListingBackofficeView",
"open_moderation_flag_count",
),
- json_number_safe_count("RadrootsTradeListingProjection", "order_count"),
- json_number_safe_count("RadrootsTradeListingProjection", "open_order_count"),
- json_number_safe_count("RadrootsTradeListingProjection", "terminal_order_count"),
- json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "order_count"),
- json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "open_order_count"),
+ json_number_safe_count("RadrootsTradeListingProjection", "trade_count"),
+ json_number_safe_count("RadrootsTradeListingProjection", "open_trade_count"),
+ json_number_safe_count("RadrootsTradeListingProjection", "terminal_trade_count"),
+ json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "trade_count"),
+ json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "open_trade_count"),
json_number_safe_count(
"RadrootsTradeMarketplaceListingSummary",
- "terminal_order_count",
+ "terminal_trade_count",
),
];
@@ -268,32 +268,32 @@ mod tests {
),
(
"RadrootsTradeListingProjection",
- "order_count",
+ "trade_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
(
"RadrootsTradeListingProjection",
- "open_order_count",
+ "open_trade_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
(
"RadrootsTradeListingProjection",
- "terminal_order_count",
+ "terminal_trade_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
(
"RadrootsTradeMarketplaceListingSummary",
- "order_count",
+ "trade_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
(
"RadrootsTradeMarketplaceListingSummary",
- "open_order_count",
+ "open_trade_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
(
"RadrootsTradeMarketplaceListingSummary",
- "terminal_order_count",
+ "terminal_trade_count",
super::TradeLargeIntegerPolicy::JsonNumberSafeCount
),
]
diff --git a/tools/sdk_xtask_import/src/dto_roots.rs b/tools/sdk_xtask_import/src/dto_roots.rs
@@ -149,6 +149,23 @@ const TRADE_EXTERNAL_OVERRIDES: &[DtoExternalOverride] = &[
const TRADE_REQUIRED_EXTERNAL_PACKAGE_IMPORTS: &[&str] =
&[CORE_BINDINGS_PACKAGE_NAME, EVENT_BINDINGS_PACKAGE_NAME];
+const RETIRED_ORDER_EVENT_DTO_ROOTS: &[&str] = &[
+ "RadrootsOrderCancellation",
+ "RadrootsOrderDecision",
+ "RadrootsOrderDecisionOutcome",
+ "RadrootsOrderEconomicActor",
+ "RadrootsOrderEconomicEffect",
+ "RadrootsOrderEconomicItem",
+ "RadrootsOrderEconomicLine",
+ "RadrootsOrderEconomicLineKind",
+ "RadrootsOrderEconomicTotals",
+ "RadrootsOrderEconomics",
+ "RadrootsOrderEventType",
+ "RadrootsOrderInventoryCommitment",
+ "RadrootsOrderItem",
+ "RadrootsOrderPricingBasis",
+ "RadrootsOrderRequest",
+];
pub fn package_root_set(package_key: &str) -> Option<&'static DtoPackageRootSet> {
DTO_PACKAGE_ROOTS
@@ -206,7 +223,10 @@ fn core_roots() -> Vec<RootDescriptor> {
}
fn event_roots() -> Vec<RootDescriptor> {
- radroots_event::dto::dto_roots().into_iter().collect()
+ radroots_event::dto::dto_roots()
+ .into_iter()
+ .filter(|root| !retired_order_event_dto_root(root))
+ .collect()
}
fn event_index_roots() -> Vec<RootDescriptor> {
@@ -217,6 +237,15 @@ fn trade_roots() -> Vec<RootDescriptor> {
radroots_trade_bindings::dto_roots()
}
+fn retired_order_event_dto_root(root: &RootDescriptor) -> bool {
+ let type_name = root
+ .rust_type_name
+ .rsplit("::")
+ .next()
+ .unwrap_or(root.rust_type_name);
+ RETIRED_ORDER_EVENT_DTO_ROOTS.contains(&type_name)
+}
+
fn core_import_options(
registry: &Registry,
mut options: DtoRegistryRenderOptions,
@@ -617,21 +646,6 @@ mod tests {
"RadrootsMessageFileDimensions",
"RadrootsMessageRecipient",
"RadrootsNip01EventWireDto",
- "RadrootsOrderCancellation",
- "RadrootsOrderDecision",
- "RadrootsOrderDecisionOutcome",
- "RadrootsOrderEconomicActor",
- "RadrootsOrderEconomicEffect",
- "RadrootsOrderEconomicItem",
- "RadrootsOrderEconomicLine",
- "RadrootsOrderEconomicLineKind",
- "RadrootsOrderEconomicTotals",
- "RadrootsOrderEconomics",
- "RadrootsOrderEventType",
- "RadrootsOrderInventoryCommitment",
- "RadrootsOrderItem",
- "RadrootsOrderPricingBasis",
- "RadrootsOrderRequest",
"RadrootsPlot",
"RadrootsPlotLocation",
"RadrootsPlotRef",
@@ -885,6 +899,7 @@ mod tests {
let actual = type_inventory(EVENT_BINDINGS_TYPES_TS);
assert_eq!(actual, EVENT_TYPE_INVENTORY);
+ assert!(!EVENT_BINDINGS_TYPES_TS.contains("RadrootsOrder"));
}
#[test]