Skip to content

AshFrancis/splicers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

68 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Splicers

A gene splicing NFT game built on Stellar with verifiable randomness.

Splicers is an on-chain NFT game where players splice genetic material to create unique creatures. The game uses BLS12-381 signature verification (CAP-0059) to ensure cryptographically verifiable randomness from the drand network.

Key Features:

  • 🧬 Gene Splicing Mechanics: Combine head, body, and leg genes to create unique creatures
  • 🎲 Verifiable Randomness: Uses drand's distributed randomness beacon with on-chain BLS12-381 verification
  • 🎨 Dynamic NFTs: Creatures rendered from layered PNG assets with gene-based variations
  • 🎟️ Cartridge System: Genome Cartridges with cosmetic skins generated via Soroban PRNG
  • πŸ”’ Cryptographic Security: Full CAP-0059 implementation with pairing checks, H2C, and subgroup verification

Built with:

  • ⚑️ Scaffold Stellar - Vite + React + TypeScript
  • πŸ¦€ Soroban smart contracts in Rust
  • πŸ” OpenZeppelin Stellar Contracts for NFT standards
  • πŸ“‘ Drand Quicknet (3-second rounds)

Requirements

Before getting started, make sure you’ve met the requirements listed in the Soroban documentation and that the following tools are installed :

Quick Start

Local Development

  1. Clone and install dependencies:
git clone https://github.com/AshFrancis/splicers.git
cd splicers
npm install
  1. Configure environment:
# Copy the example environment file
cp .env.example .env

# Edit .env to set:
# - STELLAR_SCAFFOLD_ENV=development (for local) or staging (for testnet)
# - Network configuration (already set for testnet by default)
  1. Start development server:
npm run dev

The scaffold will automatically:

  • Build the gene-splicer contract
  • Deploy to your configured network
  • Generate TypeScript bindings
  • Start the Vite dev server at http://localhost:5173
  1. Deploy Native XLM Contract (Local Development only):

If running locally, deploy the XLM token contract:

stellar contract asset deploy --source me --network local --asset native

This deploys the native XLM token at its deterministic address (CDMLFMKMMD7MWZP3FKUBZPVHTUEDLSX4BYGYKH4GCESXYHS3IHQ4EIG4), required for splice fees.

Testnet Deployment

The game is currently deployed on Stellar testnet. To deploy your own instance:

  1. Build the contract:
cargo build --release --target wasm32-unknown-unknown
  1. Get drand public key:
npx tsx scripts/getDrandPubkey.ts
# Copy the 192-byte hex output
  1. Deploy via Stellar CLI:
# Install WASM
stellar contract install \
  --wasm target/wasm32-unknown-unknown/release/gene_splicer.wasm \
  --network testnet

# Deploy with constructor args
stellar contract deploy \
  --wasm-hash <hash-from-install> \
  --network testnet \
  -- \
  --admin <your-address> \
  --xlm_token CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC \
  --cartridge_skin_count 10 \
  --dev_mode false \
  --drand_public_key <192-byte-hex-from-step-2>
  1. Update contract IDs (see section below)

Project Structure

splicers/
β”œβ”€β”€ contracts/
β”‚   └── gene-splicer/            # Main game contract (Rust/Soroban)
β”‚       β”œβ”€β”€ src/lib.rs           # Contract logic with BLS12-381 verification
β”‚       └── Cargo.toml
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ specs/                   # Game design specifications
β”‚   └── reference-implementations/ # Solidity & JS reference code
β”œβ”€β”€ packages/                    # Auto-generated TypeScript clients
β”‚   └── gene_splicer/           # Contract bindings (generated by scaffold)
β”œβ”€β”€ public/
β”‚   └── assets/creatures/        # Gene segment PNG assets (15 variants)
β”œβ”€β”€ scripts/                     # Utility scripts
β”‚   β”œβ”€β”€ getDrandPubkey.ts       # Extract drand public key
β”‚   β”œβ”€β”€ testBLS12381.sh         # End-to-end BLS verification test
β”‚   └── fetchAndDecompressDrand.ts
β”œβ”€β”€ src/                         # Frontend React application
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ GenomeSplicer.tsx   # Main game UI
β”‚   β”‚   └── CreatureRenderer.tsx # Dynamic creature rendering
β”‚   β”œβ”€β”€ contracts/
β”‚   β”‚   β”œβ”€β”€ gene_splicer.ts     # Contract client wrapper
β”‚   β”‚   └── util.ts             # Network utilities
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   └── entropyRelayer.ts   # BLS12-381 point decompression
β”‚   β”œβ”€β”€ hooks/                   # React hooks for wallet, balance, etc.
β”‚   β”œβ”€β”€ pages/                   # App routes
β”‚   └── App.tsx
β”œβ”€β”€ .github/workflows/
β”‚   └── deploy.yml              # GitHub Pages deployment
β”œβ”€β”€ environments.toml            # Network configurations
β”œβ”€β”€ package.json
└── .env                         # Local environment (gitignored)

Key Files:

  • contracts/gene-splicer/src/lib.rs - Smart contract with CAP-0059 BLS verification
  • src/services/entropyRelayer.ts - Decompresses drand signatures using @noble/curves
  • src/components/GenomeSplicer.tsx - Game UI for splicing and finalizing creatures
  • src/components/CreatureRenderer.tsx - Dynamic creature rendering from gene combinations

How It Works

Game Flow

  1. Splice Genome (splice_genome()):

    • Player pays 1 XLM fee
    • Receives Genome Cartridge NFT with cosmetic skin (generated via Soroban PRNG)
    • Contract stores the drand round number for future entropy
  2. Submit Entropy (submit_entropy()):

    • Off-chain relayer fetches drand quicknet entropy
    • Submits round, randomness, and BLS signature to contract
    • Contract performs full BLS12-381 verification (CAP-0059)
  3. Finalize Splice (finalize_splice()):

    • Permissionless function anyone can call
    • Uses verified drand entropy to select genes (head, body, legs)
    • Each gene has rarity: Legendary (10%), Rare (30%), Normal (60%)
    • Burns Genome Cartridge and mints final Creature NFT

BLS12-381 Verification (CAP-0059)

The contract implements cryptographically secure randomness using drand's distributed beacon:

Architecture:

  • Off-chain relayer (NON-SECURITY-CRITICAL): Fetches and decompresses BLS points
  • On-chain contract (SECURITY-CRITICAL): Verifies signatures with pairing checks

Verification Steps:

  1. Deserialize G1 signature (96 bytes uncompressed)
  2. Verify signature in G1 subgroup
  3. Construct drand message: prev_sig || round (big-endian)
  4. Hash-to-Curve (H2C) with DST: BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_
  5. Verify hashed point in G1 subgroup
  6. Deserialize drand public key (192 bytes uncompressed G2)
  7. Verify public key in G2 subgroup
  8. Pairing check: e(sig, G2_gen) == e(H(msg), pubkey)

Security Properties:

  • Signature authenticity proven via pairing equation
  • Message integrity from on-chain H2C
  • Replay protection via previous signature chaining
  • Randomness derived as SHA256(compressed_signature) - matches drand spec

Testing:

# Test full BLS verification with live drand data
bash scripts/testBLS12381.sh

⚠️ Important: Contract Deployment & ID Sync

When you deploy or redeploy contracts, you must keep the contract IDs in sync across all config files, otherwise your frontend will fail silently!

After deploying a contract:

  1. Check the new contract ID - After deployment, the contract ID is stored in:

    cat .config/stellar/contract-ids/gene_splicer.json
  2. Update ALL contract ID locations - Copy the contract ID to:

    • .env file (for local development):

      PUBLIC_GENE_SPLICER_CONTRACT_ID="CCL5G4HRTTBFASEBGJVF4OTLF2K3PWWUNLL3IWYZXI2CZAO4ZFJRHSPX"
    • .github/workflows/deploy.yml (for GitHub Pages deployment):

      env:
        PUBLIC_GENE_SPLICER_CONTRACT_ID: CCL5G4HRTTBFASEBGJVF4OTLF2K3PWWUNLL3IWYZXI2CZAO4ZFJRHSPX
  3. Restart dev server - The Vite dev server should auto-reload, but if not:

    # Stop npm run dev (Ctrl+C) and restart
    npm run dev

How to verify everything is synced:

# Contract ID in Stellar config
cat .config/stellar/contract-ids/gene_splicer.json

# Contract ID in .env
grep PUBLIC_GENE_SPLICER_CONTRACT_ID .env

# Contract ID in GitHub Actions workflow
grep PUBLIC_GENE_SPLICER_CONTRACT_ID .github/workflows/deploy.yml

# These should ALL match!

Why this matters: The frontend reads contract IDs from environment variables. If the .env file has an old contract ID but the blockchain has a new one, transactions will succeed in simulation but fail silently on the network, and you won't see any data!

About

Stellar NFT Game

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •