Tikka is a decentralized raffle platform built on Stellar using Soroban smart contracts. Users can create raffles, sell tickets priced in Stellar assets, and distribute prizes securely on-chain.
- Internal draws use Soroban
env.prng()with a multi-source seed:timestamp + sequence + raffle_id + tickets_sold - Deterministic replay for identical raffle and ledger inputs
- Intended for low-stakes raffles; high-stakes draws should use oracle randomness
- Ticket Purchases: Any Stellar asset contract
- Prizes: Same asset used for ticket purchases
- Flexible Pricing: Set ticket prices and prize amount per raffle
- Prizes are held in the smart contract until finalization
- Winners claim prizes after the raffle ends
- Total tickets sold per raffle
- Winner tracking and claim status
Creator → Create Raffle → Set Parameters
- Raffle creators specify:
- Description and end time
- Maximum ticket count
- Ticket price and payment asset
- Whether multiple tickets per person are allowed
- Prize amount (in the same payment asset)
Creator → Deposit Prize → Contract Escrow
- Prizes are transferred to the smart contract
- Contract holds the prize until raffle finalization
Participants → Buy Tickets → Contract Validation → Ticket Issuance
- Users purchase tickets with the raffle asset
- Contract validates payment and issues tickets
- One ticket equals one entry in the raffle
Raffle Ends → Finalize → Select Winner
- Winner is selected from sold tickets
- Internal mode uses Soroban PRNG seeded with multiple ledger and raffle fields
- External/oracle mode remains available for stronger trust assumptions
Winner Selected → Claim Prize
- Winners claim their prizes
flowchart TD
Creator[Creator]
Buyer[TicketBuyer]
Token[StellarAssetContract]
Raffle[RaffleContract]
Creator -->|"create_raffle()"| Raffle
Creator -->|"deposit_prize()"| Token
Token -->|"transfer(prize)"| Raffle
Buyer -->|"buy_ticket()"| Token
Token -->|"transfer(ticket_price)"| Raffle
Raffle -->|"finalize_raffle()"| Raffle
Raffle -->|"select_winner(prng_seeded_entropy)"| Raffle
Buyer -->|"claim_prize()"| Raffle
Raffle -->|"transfer(prize)"| Token
Token -->|"transfer(prize)"| Buyer
- Soroban (Rust): Smart contract implementation
- Stellar: Network and asset contracts
pub fn create_raffle(... ) -> u64;
pub fn deposit_prize(... );
pub fn buy_ticket(... ) -> u32;
pub fn finalize_raffle(... ) -> Address;
pub fn claim_prize(... );
pub fn get_raffle(... ) -> Raffle;
pub fn get_tickets(... ) -> Vec<Address>;pub struct Raffle {
pub id: u64,
pub creator: Address,
pub description: String,
pub end_time: u64,
pub max_tickets: u32,
pub allow_multiple: bool,
pub ticket_price: i128,
pub payment_token: Address,
pub prize_amount: i128,
pub tickets_sold: u32,
pub is_active: bool,
pub prize_deposited: bool,
pub prize_claimed: bool,
pub winner: Option<Address>,
}- Only one winner per raffle
- Prize and ticket payments use the same Stellar asset
- Internal PRNG is suitable for low-stakes raffles (e.g., sub-500 XLM prizes)
- For high-stakes raffles, prefer the external oracle/VRF randomness path
Every raffle requires a metadata_hash: BytesN<32> — a SHA-256 hash of the off-chain metadata JSON stored on IPFS. This hash is committed on-chain at creation and is immutable, so organizers cannot alter the description, image, or rules after tickets are sold.
{
"name": "My Raffle",
"description": "Full rules and description here",
"image": "ipfs://Qm...",
"rules": "..."
}Linux / macOS
# 1. Create your metadata file
cat > metadata.json << 'EOF'
{"name":"My Raffle","description":"...","image":"ipfs://Qm...","rules":"..."}
EOF
# 2. Hash it (outputs hex)
sha256sum metadata.json
# or on macOS:
shasum -a 256 metadata.jsonNode.js
const crypto = require("crypto");
const fs = require("fs");
const hash = crypto
.createHash("sha256")
.update(fs.readFileSync("metadata.json"))
.digest("hex");
console.log(hash); // 64-char hex string → 32 bytesPython
import hashlib, json
meta = {"name": "My Raffle", "description": "...", "image": "ipfs://Qm...", "rules": "..."}
# Use compact, sorted JSON for reproducibility
raw = json.dumps(meta, separators=(',', ':'), sort_keys=True).encode()
print(hashlib.sha256(raw).hexdigest())# Stellar CLI example — pass as a hex-encoded bytes argument
stellar contract invoke ... -- \
--metadata_hash "$(sha256sum metadata.json | cut -d' ' -f1)"Important: Use a canonical JSON serialization (compact, keys sorted) so the hash is reproducible by anyone who downloads the metadata from IPFS.
- Contract Address:
CCTCPMI66REXIJQPVOPNTNUZBCMSRM7TZLMIPQROZIID44XNP2P2MKFZ
- Rust toolchain
- Stellar CLI (optional for deployment)
cargo test -p hello-worldcargo build -p hello-worldFor local setup, build, and test workflows, see DEVELOPMENT.md.
See CONTRIBUTING.md for contribution guidelines and PR expectations.
- Stellar Soroban: https://developers.stellar.org/docs/build/smart-contracts/overview
- Soroban Examples: https://github.com/stellar/soroban-examples
This project is licensed under the MIT License - see the LICENSE file for details.
- Documentation: Check our guides
- Issues: Report bugs and feature requests
- Community: Join our Discord for discussions
Built with ❤️ on Stellar