Build a XeCharge Machine
Messaging
Message Definition: Messages are defined as
XephyDechargeMessage
(inmessage.rs
), with two variants:Request
: Initiates a state change (e.g., user requests the machine to start).Status
: Confirms a state update (e.g., machine is now Working).
Copy
pub enum XephyDechargeMessage { Request { to_status: XephyDechargeStatus, reason: XephyDechargeStatusReason, initial_request: EventId, payload: String, }, Status { status: XephyDechargeStatus, reason: XephyDechargeStatusReason, initial_request: EventId, payload: String, }, }
Mention Tag (Machine Pubkey): The
p
tag identifies the target machine using its Nostr public key. For example,PublicKey::parse("machine_pubkey")
specifies which device receives the message.Session Tag: The
s
tag scopes events to a specific session (e.g., "xephy-decharge-controller
"), ensuring messages are isolated to the current context.Publishing and Subscription: The
RelayClient
publishes messages to a Nostr relay and subscribes to events using filters:Copy
let filter = Filter::new() .kind(EVENT_KIND) // Custom kind 1573 .since(started_at) .custom_tag(SESSION_TAG, ["xephy-decharge-controller"]) .custom_tag(MENTION_TAG, [machine_pubkey.to_hex()]); let sub_id = relay_client.subscribe(started_at, [machine_pubkey]).await?;
Filter: Retrieves events since
started_at
, scoped to the session and machine pubkey.Sender: Typically a user or admin via the dApp or CLI.
Receiver: The DeCharge node controller handling the machine.
Message Handling: The MessageHandler processes events, updating machine states and coordinating with Solana.
Building Controller
Node: Listens for user
Request
events, verifies eligibility withcheck_eligible
, and updates machine state (e.g.,Available
toWorking
). It notifies the server viaStatus
events.Server: Monitors
Status
events, locks funds withlock
when the machine starts, and settles the final amount withsettle
when it stops. This split ensures state management and payment processing are separate but coordinated.
Solana Interaction
Controller: Initiates state change and verifies eligibility
Copy
// Before: Received Request event to start machine
if xephy_balance_payment_sdk::check_eligible(
&self.solana_rpc_url,
parsed_payload.namespace_id,
&parsed_payload.user,
parsed_payload.nonce,
PREPAID_AMOUNT,
&parsed_payload.recover_info,
).await? {
// After: Send Status event to set machine to Working
self.client.send_event(mention, &XephyDechargeMessage::Status { ... }).await?;
}
Server: Locks and settles funds
Copy
// When machine starts (Working status) // Before: Received Status event indicating machine is Working if let Err(e) = xephy_balance_payment_sdk::lock( &self.solana_rpc_url, &self.solana_keypair_path, parsed_payload.namespace_id, &parsed_payload.user, PREPAID_AMOUNT, &parsed_payload.recover_info, ).await { // After: Send Request event to revert to Available if lock fails self.client.send_event(mention, &XephyDechargeMessage::Request { to_status: XephyDechargeStatus::Available, ... }).await?; } // When machine stops (Available status after 60s) // Before: Received Status event indicating machine is Available if let Err(e) = xephy_balance_payment_sdk::settle( &self.solana_rpc_url, &self.solana_keypair_path, &parsed_payload.user, parsed_payload.nonce, TRANSFER_AMOUNT, ).await { tracing::error!("Settle failed: {:?}", e); } // After: No event sent; balance is settled
Last updated