Examples

Curated examples and reference implementations for building with the Zypp SDK.

Payments App

The examples/payments-app/ directory contains a full-stack P2P payment demo built with Expo:

examples/payments-app/
├── src/
│   ├── App.tsx           Main application entry
│   ├── screens/          Payment send/receive screens
│   ├── components/       UI components
│   └── hooks/            useIntent, useQueue wrappers
├── app.json
├── package.json
└── README.md

Running the Example

cd examples/payments-app
npx expo install
npx expo start

Key Code

import { createPaymentIntent, markProvisional, settle } from '@zypp-labs/expo-sdk';

// Send 1 USDC
const { intentId } = createPaymentIntent(
  1_000_000,                          // 1 USDC (6 decimals)
  'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',  // USDC mint
  recipientPubkey                     // recipient address
);

markProvisional(intentId);

// Settle when online
const result = settle(intentId, 'https://api.devnet.solana.com', 0);

Arcade Machine Template

The zypp-arcade starter template (rust-core/src/templates/arcade.rs) demonstrates a game arcade scenario — players buy credits and interact with a game machine.

Action Kinds and Trust Tiers

pub fn required_trust_tier(action_kind: &str) -> TrustTier {
    match action_kind {
        "spend_tokens" | "trade_item" => TrustTier::Signed,
        "move_avatar" | "ping" => TrustTier::Unsigned,
        _ => TrustTier::Unsigned,  // unknown actions handled by validation
    }
}

Arcade Flow

  1. Player deposits tokens → create Payment intent for credit purchase
  2. Player moves avatar → create Unsigned Action intent
  3. Player trades item → create Signed Action intent with cryptographic envelope

Processing Actions

pub fn process_action(intent: &Intent) -> ArcadeResult {
    let required = required_trust_tier(&kind);
    if intent.trust_tier as u8 < required as u8 {
        return ArcadeResult::TrustTierTooLow;
    }
    // Execute game action...
}

Event Ticketing Template

The zypp-ticket template (rust-core/src/templates/ticket.rs) provides event ticketing with dual-signature verification.

Verifying Issuer Signatures

pub fn redeem_ticket(
    intent: &Intent,
    issuer_public_key: Option<&[u8]>,
    try_redeem: &mut impl FnMut() -> bool,
) -> TicketResult {
    // Require Signed trust tier
    if intent.envelope.is_none() {
        return TicketResult::MissingEnvelope;
    }

    // Verify issuer signature cryptographically when key provided
    if let Some(pub_key) = issuer_public_key {
        let payload = get_ticket_payload(intent);
        if !sync::verify_signature(payload, issuer_sig, pub_key) {
            return TicketResult::InvalidIssuerSignature;
        }
    }

    // Atomic check-and-set redemption
    if try_redeem() {
        TicketResult::AlreadyRedeemed
    } else {
        TicketResult::Success
    }
}

CLI Tool

use zypp_labs_core::ZyppEngine;
use clap::Parser;

#[derive(Parser)]
struct Args {
    #[arg(short, long)]
    kind: String,
    #[arg(short, long)]
    payload: String,
    #[arg(short, long)]
    signed: bool,
}

fn main() {
    let args = Args::parse();
    let engine = ZyppEngine::new();
    let trust = if args.signed { TrustTier::Signed } else { TrustTier::Unsigned };
    let intent = engine.create_intent(&args.kind, &args.payload, trust);
    println!("Created intent: {}", intent.id);
}

Offline Queue Transfer

// Device A (sender)
const { packetB64 } = createTransferPacket(intentId);
// Display as QR code

// Device B (receiver)
const imported = decodeTransferPacket(scannedB64);
const { intentId } = createIntent(imported.kind, imported.payload);

Full Integration Test

From rust-core/tests/integration.rs, the test suite demonstrates:

#[test]
fn test_full_lifecycle() {
    // 1. Create intent
    // 2. Enqueue locally
    // 3. Mark provisional
    // 4. Finalize
    // 5. Verify state transitions
}

#[test]
fn test_offline_persistence() {
    // 1. Create and queue multiple intents
    // 2. Simulate offline period
    // 3. Verify queue survives without data loss
    // 4. Sync when online
}

#[test]
fn test_tamper_detection() {
    // 1. Create transfer packet
    // 2. Tamper with payload
    // 3. Verify decode fails with tamper error
}

Run all examples with:

cargo test --manifest-path rust-core/Cargo.toml --all -- --nocapture

Next Steps