Build cash-backed dares with Solana USDC escrow + live streaming
Kadrin enables cash-backed dares with live streaming. Built on Solana with USDC escrow and Cloudflare Stream integration. No ads, just pure competition.
USDC stakes locked in smart contracts
Stream your dare completion live
Winners get paid automatically
git clone https://github.com/kadrin/kadrin.git
npm install
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
npm run dev
0 of 4 completed
// 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(())
}
}
// 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>
);
}
// 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 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();
});
});
Your feedback helps us improve