app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 2020244abe15b5e225fe0b86063f20be88663b35
parent 50f2f4de1b20c59a0f3cd61144405b5b9bedf6b4
Author: triesap <tyson@radroots.org>
Date:   Sun, 14 Jun 2026 14:48:14 -0700

runtime: align trade reducer APIs

- wrap order lifecycle buckets in RadrootsOrderReductionInputs
- use public listing address parsing for seller authority checks
- refresh the lockfile for the current radroots_trade graph
- verify radroots_app_sqlite, radroots_app, and platform integration checks

Diffstat:
MCargo.lock | 9+++++++++
Mcrates/desktop/src/runtime.rs | 45+++++++++++++++++++++++----------------------
Mcrates/store/src/interop.rs | 22++++++++++++----------
3 files changed, 44 insertions(+), 32 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -5186,6 +5186,14 @@ dependencies = [ ] [[package]] +name = "radroots_authority" +version = "0.1.0-alpha.2" +dependencies = [ + "radroots_events", + "thiserror 1.0.69", +] + +[[package]] name = "radroots_core" version = "0.1.0-alpha.2" dependencies = [ @@ -5385,6 +5393,7 @@ version = "0.1.0-alpha.2" dependencies = [ "base64 0.22.1", "hex", + "radroots_authority", "radroots_core", "radroots_events", "radroots_events_codec", diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs @@ -113,10 +113,11 @@ use radroots_sdk::{ SdkPublishReceipt, SdkTransportMode, SdkTransportReceipt, SignerConfig, }; use radroots_sql_core::SqliteExecutor; +use radroots_trade::listing::parse_public_listing_address; use radroots_trade::order::{ RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderFulfillmentRecord, RadrootsOrderPaymentEventRecord, RadrootsOrderPaymentState, RadrootsOrderReceiptRecord, - RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord, + RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord, RadrootsOrderRevisionProposalRecord, RadrootsOrderSettlementRecord, RadrootsOrderStatus, reduce_order_events, }; @@ -2442,12 +2443,11 @@ impl DesktopAppRuntimeState { reason: "seller order decision seller account does not match order seller", }); } - let listing_address = - radroots_sdk::order::parse_listing_address(request.payload.listing_addr.as_str()) - .map_err(|_| AppSqliteError::InvalidProjection { - reason: "seller order decision listing address is invalid", - })?; - if listing_address.seller_pubkey != seller_pubkey { + let listing_address = parse_public_listing_address(request.payload.listing_addr.as_str()) + .map_err(|_| AppSqliteError::InvalidProjection { + reason: "seller order decision listing address is invalid", + })?; + if listing_address.seller_pubkey.as_str() != seller_pubkey.as_str() { return Err(AppSqliteError::InvalidProjection { reason: "seller order decision listing address is outside seller authority", }); @@ -2729,12 +2729,11 @@ impl DesktopAppRuntimeState { reason: "seller order revision seller account does not match order seller", }); } - let listing_address = - radroots_sdk::order::parse_listing_address(request.payload.listing_addr.as_str()) - .map_err(|_| AppSqliteError::InvalidProjection { - reason: "seller order revision listing address is invalid", - })?; - if listing_address.seller_pubkey != seller_pubkey { + let listing_address = parse_public_listing_address(request.payload.listing_addr.as_str()) + .map_err(|_| AppSqliteError::InvalidProjection { + reason: "seller order revision listing address is invalid", + })?; + if listing_address.seller_pubkey.as_str() != seller_pubkey.as_str() { return Err(AppSqliteError::InvalidProjection { reason: "seller order revision listing address is outside seller authority", }); @@ -5570,15 +5569,17 @@ impl DesktopAppRuntimeState { let projection = reduce_order_events( &request.payload.order_id, - buckets.requests.clone(), - buckets.decisions.clone(), - buckets.revision_proposals.clone(), - buckets.revision_decisions.clone(), - buckets.fulfillments.clone(), - buckets.cancellations.clone(), - buckets.receipts.clone(), - buckets.payments.clone(), - buckets.settlements.clone(), + RadrootsOrderReductionInputs { + requests: buckets.requests.clone(), + decisions: buckets.decisions.clone(), + revision_proposals: buckets.revision_proposals.clone(), + revision_decisions: buckets.revision_decisions.clone(), + fulfillments: buckets.fulfillments.clone(), + cancellations: buckets.cancellations.clone(), + receipts: buckets.receipts.clone(), + payments: buckets.payments.clone(), + settlements: buckets.settlements.clone(), + }, ); if !projection.issues.is_empty() || projection.status == RadrootsOrderStatus::Invalid { return Err(AppSqliteError::InvalidProjection { diff --git a/crates/store/src/interop.rs b/crates/store/src/interop.rs @@ -43,7 +43,7 @@ use radroots_sql_core::{SqlExecutor, SqliteExecutor}; use radroots_trade::order::{ RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderFulfillmentRecord, RadrootsOrderPaymentEventRecord, RadrootsOrderProjection, RadrootsOrderReceiptRecord, - RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord, + RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord, RadrootsOrderRevisionProposalRecord, RadrootsOrderSettlementRecord, reduce_order_events, }; use radroots_trade::validation_receipt::{ @@ -1197,15 +1197,17 @@ impl<'a> AppLocalInteropRepository<'a> { })?; let projection = reduce_order_events( &reducer_order_id, - buckets.requests, - buckets.decisions, - buckets.revision_proposals, - buckets.revision_decisions, - buckets.fulfillments, - buckets.cancellations, - buckets.receipts, - buckets.payments, - buckets.settlements, + RadrootsOrderReductionInputs { + requests: buckets.requests, + decisions: buckets.decisions, + revision_proposals: buckets.revision_proposals, + revision_decisions: buckets.revision_decisions, + fulfillments: buckets.fulfillments, + cancellations: buckets.cancellations, + receipts: buckets.receipts, + payments: buckets.payments, + settlements: buckets.settlements, + }, ); let request_payload = projection.request_event_id.as_deref().and_then(|event_id| { requests