commit b08a9a6e98569ebcbcbd9975cb2c959c051fe5a9
parent e1d407387158a606a68ef30f7cdbe59e9cae7dd8
Author: triesap <tyson@radroots.org>
Date: Tue, 16 Jun 2026 14:20:29 -0700
sdk: add v1 product examples
Diffstat:
3 files changed, 212 insertions(+), 0 deletions(-)
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
@@ -95,6 +95,16 @@ serde_json = { workspace = true, optional = true, default-features = false, feat
sha2 = { workspace = true, optional = true }
uuid = { workspace = true, optional = true }
+[[example]]
+name = "sdk_v1_listing_prepare"
+path = "examples/sdk_v1_listing_prepare.rs"
+required-features = ["runtime"]
+
+[[example]]
+name = "sdk_v1_local_enqueue_and_mock_sync"
+path = "examples/sdk_v1_local_enqueue_and_mock_sync.rs"
+required-features = ["runtime", "local-signer"]
+
[dev-dependencies]
futures = { workspace = true }
nostr = { workspace = true }
diff --git a/crates/sdk/examples/sdk_v1_listing_prepare.rs b/crates/sdk/examples/sdk_v1_listing_prepare.rs
@@ -0,0 +1,84 @@
+use radroots_authority::RadrootsActorContext;
+use radroots_core::{
+ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreQuantity,
+ RadrootsCoreQuantityPrice, RadrootsCoreUnit,
+};
+use radroots_events::contract::RadrootsActorRole;
+use radroots_events::ids::{RadrootsDTag, RadrootsInventoryBinId};
+use radroots_sdk::protocol::farm::RadrootsFarmRef;
+use radroots_sdk::protocol::listing::{
+ RadrootsListing, RadrootsListingBin, RadrootsListingProduct,
+};
+use radroots_sdk::{ListingPreparePublishRequest, RadrootsSdk, RadrootsSdkTimestamp};
+
+const SELLER: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let sdk = RadrootsSdk::builder()
+ .fixed_clock(RadrootsSdkTimestamp::from_unix_seconds(1_700_000_000))
+ .build()
+ .await?;
+ let actor = RadrootsActorContext::test(SELLER, [RadrootsActorRole::Seller])?;
+ let request = ListingPreparePublishRequest::new(actor, sample_listing(SELLER));
+
+ let plan = sdk.listings().prepare_publish(request)?;
+
+ println!("public listing: {}", plan.public_listing_addr.as_str());
+ println!("draft listing: {}", plan.draft_listing_addr.as_str());
+ println!("expected event: {}", plan.expected_event_id.as_str());
+ Ok(())
+}
+
+fn sample_listing(seller: &str) -> RadrootsListing {
+ RadrootsListing {
+ d_tag: RadrootsDTag::parse("AAAAAAAAAAAAAAAAAAAAAQ").expect("d tag"),
+ published_at: None,
+ farm: RadrootsFarmRef {
+ pubkey: seller.to_owned(),
+ d_tag: "AAAAAAAAAAAAAAAAAAAAAA".to_owned(),
+ },
+ product: RadrootsListingProduct {
+ key: "coffee".to_owned(),
+ title: "Coffee".to_owned(),
+ category: "coffee".to_owned(),
+ summary: Some("Single origin coffee".to_owned()),
+ process: None,
+ lot: None,
+ location: None,
+ profile: None,
+ year: None,
+ },
+ primary_bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
+ bins: vec![RadrootsListingBin {
+ bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
+ quantity: RadrootsCoreQuantity::new(
+ RadrootsCoreDecimal::from(1000u32),
+ RadrootsCoreUnit::MassG,
+ ),
+ price_per_canonical_unit: RadrootsCoreQuantityPrice {
+ amount: RadrootsCoreMoney::new(
+ RadrootsCoreDecimal::from(20u32),
+ RadrootsCoreCurrency::USD,
+ ),
+ quantity: RadrootsCoreQuantity::new(
+ RadrootsCoreDecimal::from(1u32),
+ RadrootsCoreUnit::MassG,
+ ),
+ },
+ display_amount: None,
+ display_unit: None,
+ display_label: None,
+ display_price: None,
+ display_price_unit: None,
+ }],
+ resource_area: None,
+ plot: None,
+ discounts: None,
+ inventory_available: None,
+ availability: None,
+ delivery_method: None,
+ location: None,
+ images: None,
+ }
+}
diff --git a/crates/sdk/examples/sdk_v1_local_enqueue_and_mock_sync.rs b/crates/sdk/examples/sdk_v1_local_enqueue_and_mock_sync.rs
@@ -0,0 +1,118 @@
+use radroots_authority::{RadrootsActorContext, RadrootsLocalEventSigner};
+use radroots_core::{
+ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreQuantity,
+ RadrootsCoreQuantityPrice, RadrootsCoreUnit,
+};
+use radroots_events::contract::RadrootsActorRole;
+use radroots_events::ids::{RadrootsDTag, RadrootsInventoryBinId};
+use radroots_nostr::prelude::RadrootsNostrKeys;
+use radroots_relay_transport::RadrootsMockRelayPublishAdapter;
+use radroots_sdk::protocol::farm::RadrootsFarmRef;
+use radroots_sdk::protocol::listing::{
+ RadrootsListing, RadrootsListingBin, RadrootsListingProduct,
+};
+use radroots_sdk::{
+ ListingPreparePublishRequest, OrderStatusRequest, PushOutboxRequest, RadrootsSdk,
+ RadrootsSdkTimestamp, SdkIdempotencyKey, SdkRelayTargetPolicy, SdkRelayTargetSet,
+ SdkRelayUrlPolicy,
+};
+
+const LOCAL_RELAY: &str = "ws://localhost:7777";
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let keys = RadrootsNostrKeys::generate();
+ let seller = keys.public_key().to_hex();
+ let signer = RadrootsLocalEventSigner::new(keys)?;
+ let sdk = RadrootsSdk::builder()
+ .fixed_clock(RadrootsSdkTimestamp::from_unix_seconds(1_700_000_000))
+ .build()
+ .await?;
+ let actor = RadrootsActorContext::test(seller.as_str(), [RadrootsActorRole::Seller])?;
+ let targets = SdkRelayTargetSet::new([LOCAL_RELAY], SdkRelayUrlPolicy::Localhost)?;
+ let target_policy = SdkRelayTargetPolicy::explicit(targets);
+
+ let prepared = sdk
+ .listings()
+ .prepare_publish(ListingPreparePublishRequest::new(
+ actor.clone(),
+ sample_listing(seller.as_str()),
+ ))?;
+ let enqueue = sdk
+ .listings()
+ .enqueue_prepared_publish(
+ &actor,
+ prepared,
+ target_policy,
+ Some(SdkIdempotencyKey::new("sdk-v1-local-example")?),
+ &signer,
+ )
+ .await?;
+ let adapter = RadrootsMockRelayPublishAdapter::new();
+ let push = sdk
+ .sync()
+ .push_outbox_with_adapter(&adapter, PushOutboxRequest::new().with_limit(1))
+ .await?;
+ let order_status = sdk
+ .orders()
+ .status(OrderStatusRequest::parse("example-order-1")?)
+ .await?;
+
+ println!("queued listing event: {}", enqueue.signed_event_id.as_str());
+ println!("published events: {}", push.published_events);
+ println!("order found: {}", order_status.found);
+ Ok(())
+}
+
+fn sample_listing(seller: &str) -> RadrootsListing {
+ RadrootsListing {
+ d_tag: RadrootsDTag::parse("AAAAAAAAAAAAAAAAAAAAAQ").expect("d tag"),
+ published_at: None,
+ farm: RadrootsFarmRef {
+ pubkey: seller.to_owned(),
+ d_tag: "AAAAAAAAAAAAAAAAAAAAAA".to_owned(),
+ },
+ product: RadrootsListingProduct {
+ key: "coffee".to_owned(),
+ title: "Coffee".to_owned(),
+ category: "coffee".to_owned(),
+ summary: Some("Single origin coffee".to_owned()),
+ process: None,
+ lot: None,
+ location: None,
+ profile: None,
+ year: None,
+ },
+ primary_bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
+ bins: vec![RadrootsListingBin {
+ bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
+ quantity: RadrootsCoreQuantity::new(
+ RadrootsCoreDecimal::from(1000u32),
+ RadrootsCoreUnit::MassG,
+ ),
+ price_per_canonical_unit: RadrootsCoreQuantityPrice {
+ amount: RadrootsCoreMoney::new(
+ RadrootsCoreDecimal::from(20u32),
+ RadrootsCoreCurrency::USD,
+ ),
+ quantity: RadrootsCoreQuantity::new(
+ RadrootsCoreDecimal::from(1u32),
+ RadrootsCoreUnit::MassG,
+ ),
+ },
+ display_amount: None,
+ display_unit: None,
+ display_label: None,
+ display_price: None,
+ display_price_unit: None,
+ }],
+ resource_area: None,
+ plot: None,
+ discounts: None,
+ inventory_available: None,
+ availability: None,
+ delivery_method: None,
+ location: None,
+ images: None,
+ }
+}