commit ff7ff71237cdfadaec68cfd0d290e17bfcad7b7e
parent 8723f150629ee407dcd29dcb8174e972814b9b0f
Author: triesap <tyson@radroots.org>
Date: Sat, 9 May 2026 00:30:40 +0000
cli: route order submit through sdk
- enable radroots_sdk relay-client and signing features for order submit
- publish active order requests through the shared sdk relay path
- map sdk relay receipts back into existing order submit output
- cover relay-direct local-identity sdk client wiring in unit tests
Diffstat:
3 files changed, 98 insertions(+), 31 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -2090,6 +2090,7 @@ dependencies = [
"radroots_events",
"radroots_events_codec",
"radroots_identity",
+ "radroots_nostr",
"radroots_trade",
"reqwest",
"serde",
diff --git a/Cargo.toml b/Cargo.toml
@@ -37,7 +37,7 @@ radroots_replica_db = { path = "../lib/crates/replica_db" }
radroots_replica_db_schema = { path = "../lib/crates/replica_db_schema" }
radroots_replica_sync = { path = "../lib/crates/replica_sync" }
radroots_runtime_paths = { path = "../lib/crates/runtime_paths" }
-radroots_sdk = { path = "../lib/crates/sdk", features = ["radrootsd-client"] }
+radroots_sdk = { path = "../lib/crates/sdk", features = ["radrootsd-client", "relay-client", "signing"] }
radroots_secret_vault = { path = "../lib/crates/secret_vault", features = ["std", "os-keyring"] }
radroots_sql_core = { path = "../lib/crates/sql_core", features = ["native"] }
radroots_trade = { path = "../lib/crates/trade" }
diff --git a/src/runtime/order.rs b/src/runtime/order.rs
@@ -38,8 +38,7 @@ use radroots_events_codec::trade::{
active_trade_event_context_from_tags, active_trade_fulfillment_update_event_build,
active_trade_fulfillment_update_from_event, active_trade_order_cancel_event_build,
active_trade_order_cancel_from_event, active_trade_order_decision_event_build,
- active_trade_order_request_event_build, active_trade_order_request_from_event,
- active_trade_order_revision_decision_event_build,
+ active_trade_order_request_from_event, active_trade_order_revision_decision_event_build,
active_trade_order_revision_decision_from_event,
active_trade_order_revision_proposal_event_build,
active_trade_order_revision_proposal_from_event, active_trade_payment_recorded_event_build,
@@ -60,6 +59,10 @@ use radroots_replica_db_schema::nostr_event_state::{
use radroots_replica_db_schema::trade_product::{
ITradeProductFieldsFilter, ITradeProductFindMany, TradeProduct,
};
+use radroots_sdk::{
+ RadrootsSdkClient, RadrootsSdkConfig, SdkEnvironment, SdkPublishError, SdkPublishReceipt,
+ SdkRelayFailure, SdkTransportMode, SdkTransportReceipt, SignerConfig as SdkSignerConfig,
+};
use radroots_sql_core::SqliteExecutor;
use radroots_trade::order::{
RadrootsActiveOrderCancellationRecord, RadrootsActiveOrderDecisionRecord,
@@ -9713,36 +9716,66 @@ fn publish_order_request(
id: loaded.document.order.listing_event_id.clone(),
relays: None,
};
- let parts = active_trade_order_request_event_build(&listing_event, &payload)
- .map_err(|error| RuntimeError::Config(format!("encode order request event: {error}")))?;
- let event_kind = parts.kind;
- let receipt = publish_parts_with_identity(&signing.identity, &config.relay.urls, parts)
- .map_err(|error| RuntimeError::Network(error.to_string()))?;
+ let client = order_relay_publish_client(config)?;
+ let runtime = tokio::runtime::Builder::new_multi_thread()
+ .enable_all()
+ .build()
+ .map_err(|error| {
+ RuntimeError::Network(format!("build relay order submit runtime: {error}"))
+ })?;
+ let receipt = runtime
+ .block_on(client.trade().publish_order_request_with_identity(
+ &signing.identity,
+ &listing_event,
+ &payload,
+ ))
+ .map_err(map_sdk_order_submit_error)?;
- Ok(published_order_submit_view(
- config, loaded, args, event_kind, receipt,
- ))
+ published_order_submit_view(config, loaded, args, receipt)
+}
+
+fn order_relay_publish_client(config: &RuntimeConfig) -> Result<RadrootsSdkClient, RuntimeError> {
+ let mut sdk_config = RadrootsSdkConfig::for_environment(SdkEnvironment::Custom);
+ sdk_config.transport = SdkTransportMode::RelayDirect;
+ sdk_config.signer = SdkSignerConfig::LocalIdentity;
+ sdk_config.relay.urls = config.relay.urls.clone();
+ RadrootsSdkClient::from_config(sdk_config)
+ .map_err(|error| RuntimeError::Config(format!("configure relay order submit: {error}")))
+}
+
+fn map_sdk_order_submit_error(error: SdkPublishError) -> RuntimeError {
+ let message = format!("relay order submit failed: {error}");
+ match error {
+ SdkPublishError::Config(_)
+ | SdkPublishError::Encode(_)
+ | SdkPublishError::UnsupportedTransport { .. }
+ | SdkPublishError::UnsupportedSignerMode { .. } => RuntimeError::Config(message),
+ SdkPublishError::Relay(_)
+ | SdkPublishError::RelaySetup { .. }
+ | SdkPublishError::RelayNotAcknowledged { .. }
+ | SdkPublishError::Radrootsd(_) => RuntimeError::Network(message),
+ }
}
fn published_order_submit_view(
config: &RuntimeConfig,
loaded: &LoadedOrderDraft,
args: &OrderSubmitArgs,
- event_kind: u32,
- receipt: DirectRelayPublishReceipt,
-) -> OrderSubmitView {
- let DirectRelayPublishReceipt {
- event: _,
+ receipt: SdkPublishReceipt,
+) -> Result<OrderSubmitView, RuntimeError> {
+ let SdkPublishReceipt {
event_id,
- created_at: _,
- signature: _,
- target_relays,
- connected_relays,
- acknowledged_relays,
- failed_relays,
+ event_kind,
+ transport_receipt,
+ ..
} = receipt;
+ let SdkTransportReceipt::RelayDirect(relay) = transport_receipt else {
+ return Err(RuntimeError::Config(
+ "relay order submit returned a non-relay transport receipt".to_owned(),
+ ));
+ };
- OrderSubmitView {
+ Ok(OrderSubmitView {
state: "submitted".to_owned(),
source: ORDER_SUBMIT_SOURCE.to_owned(),
order_id: loaded.document.order.order_id.clone(),
@@ -9753,14 +9786,14 @@ fn published_order_submit_view(
buyer_account_id: loaded.document.buyer_account_id.clone(),
buyer_pubkey: non_empty_string(loaded.document.order.buyer_pubkey.clone()),
seller_pubkey: non_empty_string(loaded.document.order.seller_pubkey.clone()),
- event_id: Some(event_id),
- event_kind: Some(event_kind),
+ event_id: event_id.or(Some(relay.event_id)),
+ event_kind: event_kind.or(Some(relay.event_kind)),
dry_run: false,
deduplicated: false,
- target_relays,
- connected_relays,
- acknowledged_relays,
- failed_relays: relay_failures(failed_relays),
+ target_relays: relay.target_relays,
+ connected_relays: relay.connected_relays,
+ acknowledged_relays: relay.acknowledged_relays,
+ failed_relays: sdk_relay_failures(relay.failed_relays),
idempotency_key: args.idempotency_key.clone(),
signer_mode: Some(config.signer.backend.as_str().to_owned()),
signer_session_id: None,
@@ -9769,7 +9802,7 @@ fn published_order_submit_view(
job: None,
issues: Vec::new(),
actions: Vec::new(),
- }
+ })
}
fn order_binding_error_view(
@@ -10071,6 +10104,16 @@ fn relay_failures(failures: Vec<DirectRelayFailure>) -> Vec<RelayFailureView> {
.collect()
}
+fn sdk_relay_failures(failures: Vec<SdkRelayFailure>) -> Vec<RelayFailureView> {
+ failures
+ .into_iter()
+ .map(|failure| RelayFailureView {
+ relay: failure.relay_url,
+ reason: failure.error,
+ })
+ .collect()
+}
+
fn load_draft(path: &Path) -> Result<LoadedOrderDraft, String> {
let contents = fs::read_to_string(path)
.map_err(|error| format!("read order draft {}: {error}", path.display()))?;
@@ -10371,7 +10414,7 @@ mod tests {
order_history_from_receipt, order_payment_dry_run_view, order_payment_event_parts,
order_payment_payload_from_status, order_payment_preflight_view_from_status,
order_receipt_dry_run_view, order_receipt_event_parts, order_receipt_payload_from_status,
- order_receipt_preflight_view_from_status, order_request_filter,
+ order_receipt_preflight_view_from_status, order_relay_publish_client, order_request_filter,
order_revision_decision_event_parts, order_revision_decision_payload_from_proposal,
order_revision_decision_preflight_view_from_status, order_revision_event_parts,
order_revision_inventory_preflight_view, order_revision_payload_from_status,
@@ -10439,6 +10482,29 @@ mod tests {
}
#[test]
+ fn order_relay_publish_client_uses_configured_relay_and_local_identity() {
+ let dir = tempdir().expect("tempdir");
+ let mut config = sample_config(dir.path());
+ config.relay.urls = vec!["ws://127.0.0.1:9001".to_owned()];
+
+ let client = order_relay_publish_client(&config).expect("relay order publish client");
+
+ assert_eq!(
+ client.transport(),
+ radroots_sdk::SdkTransportMode::RelayDirect
+ );
+ assert_eq!(client.signer(), radroots_sdk::SignerConfig::LocalIdentity);
+ match client.resolved_transport_target() {
+ radroots_sdk::SdkResolvedTransportTarget::RelayDirect { relay_urls } => {
+ assert_eq!(relay_urls.as_slice(), ["ws://127.0.0.1:9001"]);
+ }
+ radroots_sdk::SdkResolvedTransportTarget::Radrootsd { .. } => {
+ panic!("order submit must use relay direct transport");
+ }
+ }
+ }
+
+ #[test]
fn order_economics_applies_listing_discounts_and_basket_adjustments() {
let listing = ResolvedOrderListing {
listing_addr: "30402:seller:AAAAAAAAAAAAAAAAAAAAAg".to_owned(),