Kadrin Docs

Build cash-backed dares with Solana USDC escrow + live streaming

Next.js 14
TypeScript
Tailwind CSS
shadcn/ui
Supabase
Solana
Cloudflare

Kadrin enables cash-backed dares with live streaming. Built on Solana with USDC escrow and Cloudflare Stream integration. No ads, just pure competition.

💰 Real Money

USDC stakes locked in smart contracts

📹 Live Proof

Stream your dare completion live

âš¡ Instant Payout

Winners get paid automatically

1. Clone the repository

git clone https://github.com/kadrin/kadrin.git

2. Install dependencies

npm install

3. Set up environment variables

NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
NEXT_PUBLIC_SOLANA_RPC=https://api.mainnet-beta.solana.com

4. Run development server

npm run dev

Coding Rules

  1. 1.Single-shot answers: full feature per prompt, no chatter
  2. 2.Output pure code / shell cmds; inline comments only
  3. 3.Keep project dirs: /app, /components, /lib, /contracts
  4. 4.Strict TypeScript, strictNullChecks on
  5. 5.Use shadcn classes, no extra CSS
  6. 6.Add minimal vitest for each server util
  7. 7.Env vars NEXT_PUBLIC_*, never hard-code keys
  8. 8.Run next lint --fix
  9. 9.Anchor: derive PDA, confirm tx, return sig
  10. 10.Think fast, code like a god-tier engineer

Implementation Tasks

0 of 4 completed

Initialize Solana Vault

30 min
Medium
// Initialize Anchor vault for USDC escrow
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount};

#[program]
pub mod kadrin_vault {
    use super::*;
    
    pub fn initialize(ctx: Context<Initialize>, amount: u64) -> Result<()> {
        let vault = &mut ctx.accounts.vault;
        vault.owner = ctx.accounts.owner.key();
        vault.amount = amount;
        
        // Transfer USDC to escrow
        token::transfer(
            CpiContext::new(
                ctx.accounts.token_program.to_account_info(),
                token::Transfer {
                    from: ctx.accounts.user_token.to_account_info(),
                    to: ctx.accounts.vault_token.to_account_info(),
                    authority: ctx.accounts.owner.to_account_info(),
                },
            ),
            amount,
        )?;
        
        Ok(())
    }
}

Build Dare Creation Form

45 min
Easy
// Dare creation form with USDC stake
import { useState } from 'react';
import { useWallet } from '@solana/wallet-adapter-react';

export function DareForm() {
  const [title, setTitle] = useState('');
  const [amount, setAmount] = useState('');
  const { publicKey, signTransaction } = useWallet();
  
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    const response = await fetch('/api/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        title,
        amount: parseFloat(amount),
        wallet: publicKey?.toBase58(),
      }),
    });
    
    const { dareId, transaction } = await response.json();
    // Sign and send transaction
  };
  
  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
    </form>
  );
}

Setup Cloudflare Worker

20 min
Hard
// Cloudflare Worker for JWT token gating
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    // Verify JWT token
    const token = request.headers.get('Authorization')?.split(' ')[1];
    if (!token) {
      return new Response('Unauthorized', { status: 401 });
    }
    
    try {
      const payload = await verifyJWT(token, env.JWT_SECRET);
      
      // Check dare access
      const dareId = url.pathname.split('/')[2];
      const hasAccess = await checkDareAccess(payload.wallet, dareId, env);
      
      if (!hasAccess) {
        return new Response('Access denied', { status: 403 });
      }
      
      // Proxy to Cloudflare Stream
      return fetch(`https://videodelivery.net/${dareId}`, request);
    } catch (error) {
      return new Response('Invalid token', { status: 401 });
    }
  }
};

Test Vault Release

15 min
Easy
// Test vault release functionality
import { describe, it, expect } from 'vitest';
import { Connection, PublicKey } from '@solana/web3.js';
import { releaseVault } from '@/lib/solana';

describe('Vault Release', () => {
  it('should release funds to winner', async () => {
    const connection = new Connection('http://localhost:8899');
    const dareId = 'test-dare-123';
    const winnerWallet = new PublicKey('...');
    
    const signature = await releaseVault(
      connection,
      dareId,
      winnerWallet
    );
    
    expect(signature).toBeDefined();
    expect(signature.length).toBe(88);
    
    // Verify transaction
    const tx = await connection.getTransaction(signature);
    expect(tx?.meta?.err).toBeNull();
  });
});

Was this documentation helpful?

Your feedback helps us improve