sdk

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

commit 7048004b20403f22c1c1f160da682b86320f91ff
parent 91ef09f8a9def11584c02efd94fcfaa90573e82d
Author: triesap <tyson@radroots.org>
Date:   Fri, 19 Jun 2026 15:32:05 -0700

sdk: add order workflow command metadata

- expose typed order workflow kind and metadata receipts
- attach workflow plans and enqueue receipts to order operations
- route enqueue operation kinds through the workflow model
- assert serialized workflow metadata in SDK runtime tests

Diffstat:
Mcrates/sdk/src/lib.rs | 5+++--
Mcrates/sdk/src/orders_runtime.rs | 197++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mcrates/sdk/tests/orders_runtime.rs | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mcrates/sdk/tests/source_boundary.rs | 3+++
4 files changed, 270 insertions(+), 11 deletions(-)

diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs @@ -77,8 +77,9 @@ pub use crate::orders_runtime::{ OrderRevisionProposalEnqueueRequest, OrderRevisionProposalPlan, OrderRevisionProposalPrepareRequest, OrderRevisionProposalReceipt, OrderSettlementStateKind, OrderStatusKind, OrderStatusReceipt, OrderStatusRequest, OrderSubmitEnqueueRequest, - OrderSubmitPlan, OrderSubmitPrepareRequest, OrderSubmitReceipt, SdkOrderStatusIssue, - SdkOrderStatusIssueKind, SdkOrderStatusSource, + OrderSubmitPlan, OrderSubmitPrepareRequest, OrderSubmitReceipt, OrderWorkflowEnqueueReceipt, + OrderWorkflowKind, OrderWorkflowPlan, SdkOrderStatusIssue, SdkOrderStatusIssueKind, + SdkOrderStatusSource, }; #[cfg(feature = "runtime")] pub use crate::product_clients::{FarmsClient, ListingsClient, OrdersClient, SyncClient}; diff --git a/crates/sdk/src/orders_runtime.rs b/crates/sdk/src/orders_runtime.rs @@ -81,6 +81,71 @@ const ORDER_FULFILLMENT_UPDATE_CONTRACT_ID: &str = "radroots.order.fulfillment_u const ORDER_RECEIPT_CONTRACT_ID: &str = "radroots.order.receipt.v1"; #[cfg(feature = "runtime")] +#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum OrderWorkflowKind { + Submit, + Decision, + RevisionProposal, + RevisionDecision, + Cancellation, + FulfillmentUpdate, + ReceiptRecord, +} + +#[cfg(feature = "runtime")] +impl OrderWorkflowKind { + pub fn operation_kind(self) -> &'static str { + match self { + Self::Submit => ORDER_SUBMIT_OPERATION_KIND, + Self::Decision => ORDER_DECISION_OPERATION_KIND, + Self::RevisionProposal => ORDER_REVISION_PROPOSAL_OPERATION_KIND, + Self::RevisionDecision => ORDER_REVISION_DECISION_OPERATION_KIND, + Self::Cancellation => ORDER_CANCELLATION_OPERATION_KIND, + Self::FulfillmentUpdate => ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, + Self::ReceiptRecord => ORDER_RECEIPT_RECORD_OPERATION_KIND, + } + } + + pub fn contract_id(self) -> &'static str { + match self { + Self::Submit => ORDER_REQUEST_CONTRACT_ID, + Self::Decision => ORDER_DECISION_CONTRACT_ID, + Self::RevisionProposal => ORDER_REVISION_PROPOSAL_CONTRACT_ID, + Self::RevisionDecision => ORDER_REVISION_DECISION_CONTRACT_ID, + Self::Cancellation => ORDER_CANCELLATION_CONTRACT_ID, + Self::FulfillmentUpdate => ORDER_FULFILLMENT_UPDATE_CONTRACT_ID, + Self::ReceiptRecord => ORDER_RECEIPT_CONTRACT_ID, + } + } +} + +#[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] +pub struct OrderWorkflowPlan { + pub kind: OrderWorkflowKind, + pub operation_kind: &'static str, + pub contract_id: &'static str, + pub expected_event_id: RadrootsEventId, + pub created_at: RadrootsSdkTimestamp, +} + +#[cfg(feature = "runtime")] +#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] +pub struct OrderWorkflowEnqueueReceipt { + pub kind: OrderWorkflowKind, + pub operation_kind: &'static str, + pub expected_event_id: RadrootsEventId, + pub signed_event_id: RadrootsEventId, + pub local_event_seq: i64, + pub outbox_operation_id: i64, + pub outbox_event_id: i64, + pub state: SdkMutationState, + pub idempotency_digest_prefix: Option<String>, +} + +#[cfg(feature = "runtime")] #[derive(Clone, Debug)] #[non_exhaustive] pub struct OrderSubmitPrepareRequest { @@ -208,6 +273,7 @@ impl OrderSubmitEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderSubmitPlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub listing_event_id: RadrootsEventId, @@ -219,6 +285,7 @@ pub struct OrderSubmitPlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderSubmitReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub listing_event_id: RadrootsEventId, @@ -454,6 +521,7 @@ impl OrderDecisionEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderDecisionPlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -467,6 +535,7 @@ pub struct OrderDecisionPlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderDecisionReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -617,6 +686,7 @@ impl OrderRevisionProposalEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderRevisionProposalPlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -631,6 +701,7 @@ pub struct OrderRevisionProposalPlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderRevisionProposalReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -782,6 +853,7 @@ impl OrderRevisionDecisionEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderRevisionDecisionPlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -796,6 +868,7 @@ pub struct OrderRevisionDecisionPlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderRevisionDecisionReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -947,6 +1020,7 @@ impl OrderCancellationEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderCancellationPlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -961,6 +1035,7 @@ pub struct OrderCancellationPlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderCancellationReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -1112,6 +1187,7 @@ impl OrderFulfillmentUpdateEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderFulfillmentUpdatePlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -1126,6 +1202,7 @@ pub struct OrderFulfillmentUpdatePlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderFulfillmentUpdateReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -1277,6 +1354,7 @@ impl OrderReceiptRecordEnqueueRequest { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderReceiptRecordPlan { + pub workflow: OrderWorkflowPlan, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -1291,6 +1369,7 @@ pub struct OrderReceiptRecordPlan { #[cfg(feature = "runtime")] #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] pub struct OrderReceiptRecordReceipt { + pub workflow: OrderWorkflowEnqueueReceipt, pub order_id: RadrootsOrderId, pub listing_addr: RadrootsListingAddress, pub buyer_pubkey: RadrootsPublicKey, @@ -1709,7 +1788,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_SUBMIT_OPERATION_KIND, + operation_kind: OrderWorkflowKind::Submit.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -1719,6 +1798,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderSubmitReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::Submit, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, listing_event_id: plan.listing_event_id, @@ -1792,7 +1876,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_DECISION_OPERATION_KIND, + operation_kind: OrderWorkflowKind::Decision.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -1802,6 +1886,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderDecisionReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::Decision, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, buyer_pubkey: plan.buyer_pubkey, @@ -1886,7 +1975,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_REVISION_PROPOSAL_OPERATION_KIND, + operation_kind: OrderWorkflowKind::RevisionProposal.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -1896,6 +1985,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderRevisionProposalReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::RevisionProposal, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, buyer_pubkey: plan.buyer_pubkey, @@ -1981,7 +2075,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_REVISION_DECISION_OPERATION_KIND, + operation_kind: OrderWorkflowKind::RevisionDecision.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -1991,6 +2085,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderRevisionDecisionReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::RevisionDecision, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, buyer_pubkey: plan.buyer_pubkey, @@ -2070,7 +2169,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_CANCELLATION_OPERATION_KIND, + operation_kind: OrderWorkflowKind::Cancellation.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -2080,6 +2179,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderCancellationReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::Cancellation, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, buyer_pubkey: plan.buyer_pubkey, @@ -2165,7 +2269,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_FULFILLMENT_UPDATE_OPERATION_KIND, + operation_kind: OrderWorkflowKind::FulfillmentUpdate.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -2175,6 +2279,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderFulfillmentUpdateReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::FulfillmentUpdate, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, buyer_pubkey: plan.buyer_pubkey, @@ -2254,7 +2363,7 @@ impl<'sdk> OrdersClient<'sdk> { let enqueue = enqueue_signed_workflow( self.sdk, SdkWorkflowEnqueueRequest { - operation_kind: ORDER_RECEIPT_RECORD_OPERATION_KIND, + operation_kind: OrderWorkflowKind::ReceiptRecord.operation_kind(), actor, frozen_draft: &plan.frozen_draft, target_relays, @@ -2264,6 +2373,11 @@ impl<'sdk> OrdersClient<'sdk> { ) .await?; Ok(OrderReceiptRecordReceipt { + workflow: order_workflow_enqueue_receipt( + OrderWorkflowKind::ReceiptRecord, + plan.expected_event_id.clone(), + &enqueue, + ), order_id: plan.order_id, listing_addr: plan.listing_addr, buyer_pubkey: plan.buyer_pubkey, @@ -2542,6 +2656,11 @@ fn order_submit_plan( message: format!("order submit draft produced invalid event id: {error}"), })?; Ok(OrderSubmitPlan { + workflow: order_workflow_plan( + OrderWorkflowKind::Submit, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, listing_event_id, @@ -2591,6 +2710,11 @@ fn order_decision_plan( message: format!("order decision draft produced invalid event id: {error}"), })?; Ok(OrderDecisionPlan { + workflow: order_workflow_plan( + OrderWorkflowKind::Decision, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, buyer_pubkey, @@ -2644,6 +2768,11 @@ fn order_revision_proposal_plan( "order revision proposal", )?; Ok(OrderRevisionProposalPlan { + workflow: order_workflow_plan( + OrderWorkflowKind::RevisionProposal, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, buyer_pubkey, @@ -2698,6 +2827,11 @@ fn order_revision_decision_plan( "order revision decision", )?; Ok(OrderRevisionDecisionPlan { + workflow: order_workflow_plan( + OrderWorkflowKind::RevisionDecision, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, buyer_pubkey, @@ -2745,6 +2879,11 @@ fn order_cancellation_plan( "order cancellation", )?; Ok(OrderCancellationPlan { + workflow: order_workflow_plan( + OrderWorkflowKind::Cancellation, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, buyer_pubkey, @@ -2792,6 +2931,11 @@ fn order_fulfillment_update_plan( "order fulfillment update", )?; Ok(OrderFulfillmentUpdatePlan { + workflow: order_workflow_plan( + OrderWorkflowKind::FulfillmentUpdate, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, buyer_pubkey, @@ -2838,6 +2982,11 @@ fn order_receipt_record_plan( "order receipt record", )?; Ok(OrderReceiptRecordPlan { + workflow: order_workflow_plan( + OrderWorkflowKind::ReceiptRecord, + expected_event_id.clone(), + created_at, + ), order_id, listing_addr, buyer_pubkey, @@ -2851,6 +3000,40 @@ fn order_receipt_record_plan( } #[cfg(feature = "runtime")] +fn order_workflow_plan( + kind: OrderWorkflowKind, + expected_event_id: RadrootsEventId, + created_at: RadrootsSdkTimestamp, +) -> OrderWorkflowPlan { + OrderWorkflowPlan { + kind, + operation_kind: kind.operation_kind(), + contract_id: kind.contract_id(), + expected_event_id, + created_at, + } +} + +#[cfg(feature = "runtime")] +fn order_workflow_enqueue_receipt( + kind: OrderWorkflowKind, + expected_event_id: RadrootsEventId, + enqueue: &crate::workflow_runtime::SdkWorkflowEnqueueReceipt, +) -> OrderWorkflowEnqueueReceipt { + OrderWorkflowEnqueueReceipt { + kind, + operation_kind: kind.operation_kind(), + expected_event_id, + signed_event_id: enqueue.signed_event_id.clone(), + local_event_seq: enqueue.local_event_seq, + outbox_operation_id: enqueue.outbox_operation_id, + outbox_event_id: enqueue.outbox_event_id, + state: enqueue.state.into(), + idempotency_digest_prefix: Some(enqueue.idempotency_digest_prefix.clone()), + } +} + +#[cfg(feature = "runtime")] fn freeze_order_workflow_draft( parts: WireEventParts, contract_id: &str, diff --git a/crates/sdk/tests/orders_runtime.rs b/crates/sdk/tests/orders_runtime.rs @@ -44,8 +44,8 @@ use radroots_sdk::{ OrderPaymentStateKind, OrderReceiptRecordEnqueueRequest, OrderRequestEvidenceIngestRequest, OrderRevisionDecisionEnqueueRequest, OrderRevisionProposalEnqueueRequest, OrderSettlementStateKind, OrderStatusKind, OrderStatusRequest, OrderSubmitEnqueueRequest, - OrderSubmitPrepareRequest, PushOutboxEventState, PushOutboxRelayOutcomeKind, PushOutboxRequest, - RadrootsSdk, RadrootsSdkError, RadrootsSdkPartialLocalMutationFailure, + OrderSubmitPrepareRequest, OrderWorkflowKind, PushOutboxEventState, PushOutboxRelayOutcomeKind, + PushOutboxRequest, RadrootsSdk, RadrootsSdkError, RadrootsSdkPartialLocalMutationFailure, RadrootsSdkRecoveryAction, RadrootsSdkTimestamp, SdkMutationState, SdkOrderStatusIssue, SdkOrderStatusIssueKind, SdkOrderStatusSource, SdkRelayTargetPolicy, SdkRelayTargetSet, SdkRelayUrlPolicy, @@ -389,6 +389,17 @@ async fn order_submit_enqueue_stores_event_queues_outbox_and_status_sees_request order.clone(), )) .expect("prepared"); + assert_eq!(prepared.workflow.kind, OrderWorkflowKind::Submit); + assert_eq!( + prepared.workflow.operation_kind, + ORDER_SUBMIT_OPERATION_KIND + ); + assert_eq!(prepared.workflow.contract_id, "radroots.order.request.v1"); + assert_eq!( + prepared.workflow.expected_event_id, + prepared.expected_event_id + ); + assert_eq!(prepared.workflow.created_at, prepared.created_at); let request = OrderSubmitEnqueueRequest::new( buyer_actor(), listing_event_ptr(), @@ -409,6 +420,24 @@ async fn order_submit_enqueue_stores_event_queues_outbox_and_status_sees_request assert_eq!(receipt.order_id, prepared.order_id); assert_eq!(receipt.listing_addr, prepared.listing_addr); assert_eq!(receipt.listing_event_id, prepared.listing_event_id); + assert_eq!(receipt.workflow.kind, OrderWorkflowKind::Submit); + assert_eq!(receipt.workflow.operation_kind, ORDER_SUBMIT_OPERATION_KIND); + assert_eq!( + receipt.workflow.expected_event_id, + prepared.expected_event_id + ); + assert_eq!(receipt.workflow.signed_event_id, receipt.signed_event_id); + assert_eq!(receipt.workflow.local_event_seq, receipt.local_event_seq); + assert_eq!( + receipt.workflow.outbox_operation_id, + receipt.outbox_operation_id + ); + assert_eq!(receipt.workflow.outbox_event_id, receipt.outbox_event_id); + assert_eq!(receipt.workflow.state, receipt.state); + assert_eq!( + receipt.workflow.idempotency_digest_prefix, + receipt.idempotency_digest_prefix + ); assert_eq!(receipt.expected_event_id, prepared.expected_event_id); assert_eq!(receipt.signed_event_id, receipt.expected_event_id); assert_eq!(receipt.local_event_seq, 1); @@ -763,6 +792,17 @@ async fn order_submit_runtime_dtos_serialize_deterministically() { assert_eq!( receipt_json, serde_json::json!({ + "workflow": { + "kind": "submit", + "operation_kind": ORDER_SUBMIT_OPERATION_KIND, + "expected_event_id": receipt.workflow.expected_event_id.as_str(), + "signed_event_id": receipt.workflow.signed_event_id.as_str(), + "local_event_seq": 1, + "outbox_operation_id": 1, + "outbox_event_id": 1, + "state": "stored_and_queued", + "idempotency_digest_prefix": receipt.workflow.idempotency_digest_prefix.as_deref() + }, "order_id": receipt.order_id.as_str(), "listing_addr": receipt.listing_addr.as_str(), "listing_event_id": receipt.listing_event_id.as_str(), @@ -1371,11 +1411,43 @@ async fn order_decision_runtime_dtos_serialize_deterministically() { .enqueue_decision(enqueue_request, &FixtureSigner::new(SELLER_SECRET_KEY_HEX)) .await .expect("enqueue"); + assert_eq!(receipt.workflow.kind, OrderWorkflowKind::Decision); + assert_eq!( + receipt.workflow.operation_kind, + ORDER_DECISION_OPERATION_KIND + ); + assert_eq!( + receipt.workflow.expected_event_id, + receipt.expected_event_id + ); + assert_eq!(receipt.workflow.signed_event_id, receipt.signed_event_id); + assert_eq!(receipt.workflow.local_event_seq, receipt.local_event_seq); + assert_eq!( + receipt.workflow.outbox_operation_id, + receipt.outbox_operation_id + ); + assert_eq!(receipt.workflow.outbox_event_id, receipt.outbox_event_id); + assert_eq!(receipt.workflow.state, receipt.state); + assert_eq!( + receipt.workflow.idempotency_digest_prefix, + receipt.idempotency_digest_prefix + ); let receipt_json = serde_json::to_value(&receipt).expect("receipt json"); assert_eq!( receipt_json, serde_json::json!({ + "workflow": { + "kind": "decision", + "operation_kind": ORDER_DECISION_OPERATION_KIND, + "expected_event_id": receipt.workflow.expected_event_id.as_str(), + "signed_event_id": receipt.workflow.signed_event_id.as_str(), + "local_event_seq": 2, + "outbox_operation_id": 1, + "outbox_event_id": 1, + "state": "stored_and_queued", + "idempotency_digest_prefix": receipt.workflow.idempotency_digest_prefix.as_deref() + }, "order_id": receipt.order_id.as_str(), "listing_addr": receipt.listing_addr.as_str(), "buyer_pubkey": BUYER_PUBLIC_KEY_HEX, diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs @@ -87,6 +87,9 @@ const REQUIRED_ORDER_RUNTIME_EXPORTS: &[&str] = &[ "OrderSubmitPlan", "OrderSubmitPrepareRequest", "OrderSubmitReceipt", + "OrderWorkflowEnqueueReceipt", + "OrderWorkflowKind", + "OrderWorkflowPlan", "SdkOrderStatusIssue", "SdkOrderStatusIssueKind", "SdkOrderStatusSource",