Skip to content

yahia008/stellar-ticket-protocol

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stellar Ticket Protocol

Decentralized event ticketing on Stellar using Soroban smart contracts. Issues NFT-like tickets, prevents scalping via strict-receive payments, enforces resale price caps, and pays royalties to creators on secondary sales.

Architecture

stellar-ticket-protocol/
├── contracts/          # Soroban smart contracts (Rust)
│   ├── ticket_nft/     # NFT ownership, mint, transfer, approve
│   ├── ticket_factory/ # Event creation, supply/price config
│   ├── marketplace/    # Listings, resale cap enforcement, payment splits
│   └── royalty_engine/ # Royalty calculation and distribution
├── backend/            # Express REST API (TypeScript)
│   └── src/
│       ├── index.ts    # App entry point
│       ├── routes.ts   # API routes
│       ├── store.ts    # In-memory store (swap for Redis/DB in prod)
│       ├── anti-bot.ts # Rate limiting + wallet blacklist
│       └── types.ts    # Shared types
├── frontend/           # Next.js 14 web app (TypeScript + Tailwind)
│   └── src/
│       ├── app/        # App Router pages
│       ├── components/ # EventCard, WalletButton
│       └── context/    # WalletContext (Freighter integration)
└── sdk/                # @stellar-ticket/sdk — JS client library
    └── src/index.ts    # StellarTicketClient, tx builders, utils

How It Works

Primary sale: Buyer creates a trustline for the ticket asset, then submits a strict-receive payment. The contract mints the ticket and assigns ownership.

Secondary sale: Seller lists at a price ≤ original_price × resale_cap_bps / 10000. Buyer pays; the contract splits funds (seller payout + creator royalty) and transfers the NFT atomically.

Anti-scalping: Resale cap is enforced on-chain. Off-chain, the backend rate-limits wallet requests (10/min) and auto-blacklists wallets that sustain abuse.

Metaverse access: GET /api/verify/:address/:ticketId — returns ownership status for gating access to virtual events.

Prerequisites

  • Rust stable + wasm32-unknown-unknown target
  • Node.js 18+
rustup target add wasm32-unknown-unknown

Getting Started

Contracts

cd contracts

# Run tests
cargo test

# Build for deployment (requires stellar-cli)
cargo build --target wasm32-unknown-unknown --release

Backend

cd backend
npm install
npm run build   # compile TypeScript
npm test        # run Jest tests
npm run dev     # start dev server on :3001

Environment variables (optional):

PORT=3001

Frontend

cd frontend
npm install
npm run build   # production build
npm test        # run Jest + Testing Library tests
npm run dev     # start dev server on :3000

Set NEXT_PUBLIC_API_URL to point at the backend (defaults to http://localhost:3001/api).

SDK

cd sdk
npm install
npm run build   # outputs to dist/
npm test

Smart Contracts

Contract Responsibility
ticket_nft Mint tickets, track ownership, transfer with approval
ticket_factory Create events with supply, price, resale cap, royalty config
marketplace List/buy tickets; enforces resale cap; splits payment on buy
royalty_engine Calculate and distribute royalties to event creators

Key invariants enforced on-chain:

  • A ticket ID can only be minted once
  • Resale price ≤ original_price × resale_cap_bps / 10000
  • Royalty ≤ 30% (royalty_bps ≤ 3000)
  • Resale cap ≥ 100% (resale_cap_bps ≥ 10000)

API Reference

Method Path Description
POST /api/events Create an event
GET /api/events List all events
GET /api/events/:id Get event by ID
GET /api/wallets/:address/tickets Get tickets owned by address
POST /api/listings List a ticket for resale
GET /api/listings Get all active listings
GET /api/listings/:ticketId Get listing by ticket ID
DELETE /api/listings/:ticketId Cancel a listing
GET /api/verify/:address/:ticketId Verify ticket ownership

SDK Usage

import { StellarTicketClient, Asset, Keypair } from "@stellar-ticket/sdk";

const client = new StellarTicketClient({
  horizonUrl: "https://horizon-testnet.stellar.org",
  network: "testnet",
});

// Build a strict-receive buy transaction
const tx = await client.buildBuyTicketTx({
  buyerKeypair: Keypair.fromSecret("S..."),
  sellerAddress: "G...",
  ticketAsset: new Asset("TICKET001", "G...issuer"),
  maxSendAmount: "15",
  receiveAmount: "1",
});
await client.submitTx(tx);

// Verify ownership
const owns = await client.verifyOwnership({
  address: "G...",
  ticketAsset: new Asset("TICKET001", "G...issuer"),
});

// Pure utilities (no network call)
const { creator, seller } = StellarTicketClient.calculateRoyalty(10_000_000n, 500); // 5%
const valid = StellarTicketClient.validateResalePrice(12_000_000n, 10_000_000n, 15000); // 150% cap

Test Coverage

contracts/   10 tests  (cargo test)
backend/      9 tests  (jest)
frontend/     4 tests  (jest + @testing-library/react)
sdk/          7 tests  (jest)

Run everything:

# Contracts
(cd contracts && cargo test)

# Node packages
(cd backend && npm test)
(cd sdk && npm test)
(cd frontend && npm test)

Deployment

  1. Deploy contracts with stellar contract deploy (requires stellar-cli and a funded account on testnet/mainnet)
  2. Initialize the factory: stellar contract invoke --id <FACTORY_ID> -- initialize --admin <ADMIN_ADDRESS>
  3. Set NEXT_PUBLIC_API_URL in the frontend and deploy (Vercel, etc.)
  4. Run the backend behind a reverse proxy with TLS

Roadmap

  • Dynamic pricing (bonding curve)
  • Soulbound (non-transferable) tickets
  • Ticket staking for VIP perks
  • CAPTCHA + wallet signature pre-authorization
  • Horizon event indexer for real-time ownership sync
  • DAO-governed event parameters

License

MIT

About

Decentralized ticketing protocol on Stellar using Soroban. Issues NFT-like tickets, prevents scalping via strict-receive payments, enforces resale caps, and enables royalty payouts on secondary sales.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages