sdk

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

commit b08a9a6e98569ebcbcbd9975cb2c959c051fe5a9
parent e1d407387158a606a68ef30f7cdbe59e9cae7dd8
Author: triesap <tyson@radroots.org>
Date:   Tue, 16 Jun 2026 14:20:29 -0700

sdk: add v1 product examples

Diffstat:
Mcrates/sdk/Cargo.toml | 10++++++++++
Acrates/sdk/examples/sdk_v1_listing_prepare.rs | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acrates/sdk/examples/sdk_v1_local_enqueue_and_mock_sync.rs | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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, + } +}