Build a Gacha Machine
Messaging
Message Definition: Same as DeCharge (
XephyDechargeMessage
), but typically only processesRequest
toWorking
andStatus
back toAvailable
.Mention Tag (Machine Pubkey): Identifies the GaCha machine (e.g.,
PublicKey::parse("gacha_machine_pubkey")
).Session Tag: Scopes events (e.g.,
"xephy-gacha-controller"
).Publishing and Subscription
Copy
let filter = Filter::new() .kind(EVENT_KIND) .since(Timestamp::now()) .custom_tag(SESSION_TAG, ["gacha_session"]) .custom_tag(MENTION_TAG, [gacha_machine_pubkey.to_hex()]); let sub_id = relay_client.subscribe(Timestamp::now(), [gacha_machine_pubkey]).await?;
Sender: User requesting a dispense.
Receiver: Gacha node controller.
Message Handling: Processes a single transaction and reverts state.
Building Controller
Node: Unlike DeCharge, Gacha’s simpler transaction (one payment, one action) doesn’t require a separate server. The node handles both state and payment in a single step using
pay
, making it lightweight.
Solana Interaction
Uses pay
for a one-time transaction:
Copy
// Before: Received Request event to start machine
if let Err(e) = xephy_balance_payment_sdk::pay(
&self.solana_rpc_url,
&self.solana_keypair_path,
parsed_payload.namespace_id,
&parsed_payload.user,
PAY_AMOUNT,
&parsed_payload.recover_info,
)
.await
{
tracing::error!("Failed to pay, error: {:?} skip event: {:?}", e, event);
return Ok(());
};
self.client
.send_event(mention, &XephyGachaMessage::Status {
status: *to_status,
reason: *reason,
initial_request: event.id,
payload: serde_json::to_string(&XephyGachaMessageStatusPayload {
namespace_id: parsed_payload.namespace_id,
user: parsed_payload.user.clone(),
nonce: parsed_payload.nonce,
recover_info: parsed_payload.recover_info.clone(),
})?,
})
.await?;
Last updated