Skip to content

thecurioussailor/tiplink-clone

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BonFire - MPC-Secured Solana Web Wallet

A non-custodial Solana web wallet that uses Multi-Party Computation (MPC) with threshold signatures (TSS) for secure key management. Users can send SOL and swap tokens without any single server ever holding a complete private key.

Built for Superdev Solana Fellowship.


What It Does

  • MPC Wallet Creation - On signup, each user is assigned a wallet derived from distributed key shares across 3 MPC nodes. No single node holds the full private key.
  • Send SOL - Transfer SOL to any Solana address. Transactions are signed collaboratively by MPC nodes using the MuSig2 protocol.
  • Swap Tokens - Swap between SOL, USDC, USDT, and other SPL tokens via the Jupiter DEX aggregator with slippage protection and dynamic priority fees.
  • Balance Tracking - A background indexer continuously polls Solana to keep user balances and transaction history in sync, with USD prices fetched from CoinGecko.

Architecture

┌──────────────┐       ┌──────────────┐       ┌──────────────────────┐
│   Frontend   │──────▶│   Backend    │──────▶│   MPC Node 1 (3001)  │
│  (Next.js)   │       │ (Actix-web)  │──────▶│   MPC Node 2 (3002)  │
│  Port 3000   │       │  Port 8080   │──────▶│   MPC Node 3 (3003)  │
└──────────────┘       └──────┬───────┘       └──────────────────────┘
                              │
                    ┌─────────┼─────────┐
                    ▼         ▼         ▼
              ┌──────────┐ ┌─────┐ ┌──────────┐
              │PostgreSQL│ │Solana│ │ Jupiter  │
              │  (2 DBs) │ │ RPC │ │   API    │
              └──────────┘ └─────┘ └──────────┘
                    ▲
                    │
              ┌──────────┐
              │ Indexer   │
              │ (cron)    │
              └──────────┘

4 services run independently:

Service Language Purpose
Backend Rust (Actix-web) REST API - auth, send, swap, balance queries
MPC Node Rust (Actix-web) Holds key shares, produces partial signatures
Indexer Rust (Tokio) Polls Solana RPC, syncs balances & transactions to DB
Frontend TypeScript (Next.js 15) User-facing dashboard

How MPC Signing Works

This project uses the multi-party-eddsa library implementing the MuSig2 protocol for Ed25519 (Solana's signature scheme).

Key Generation:

  1. Admin triggers key generation across all 3 MPC nodes
  2. Each node generates its own Solana keypair and stores it
  3. Backend aggregates the public keys into a single Solana address using MuSig2 key aggregation
  4. The aggregated public key becomes the user's wallet address

Transaction Signing (2-round protocol):

  1. Round 1 - Backend sends a signing request to each MPC node. Each node generates partial nonces and returns them.
  2. Round 2 - Backend distributes all nonces to each node along with the unsigned transaction. Each node produces a partial signature.
  3. Aggregation - Backend aggregates partial signatures into a valid Ed25519 signature and submits the signed transaction to Solana.

Private keys never leave their respective MPC nodes. The backend only ever sees partial signatures.


Tech Stack

Backend & Services:

  • Rust, Actix-web 4, Tokio
  • SQLx + PostgreSQL
  • multi-party-eddsa / curv-kzen (MPC/TSS)
  • solana-sdk 3.0, solana-client 3.0
  • jsonwebtoken (JWT auth), bcrypt (password hashing)

Frontend:

  • Next.js 15, React 19, TypeScript
  • Tailwind CSS 4
  • Zustand (state management)

External APIs:

  • Jupiter v6 (DEX aggregation for swaps)
  • CoinGecko (token prices)
  • Solana RPC (devnet / mainnet)

Project Structure

tiplink-clone/
├── backend/          # Main API server (port 8080)
│   └── src/
│       ├── main.rs           # Server setup & routes
│       ├── routes/
│       │   ├── user.rs       # Signup, signin, user info
│       │   ├── solana.rs     # Send, swap, quote
│       │   ├── balance.rs    # SOL & token balances
│       │   ├── aggregated_key.rs
│       │   ├── asset.rs      # Token registry CRUD
│       │   └── mpc_node.rs   # MPC node management
│       ├── tss.rs            # Signature aggregation & broadcast
│       └── jwt.rs            # JWT middleware
├── mpc/              # MPC signing node (port 3001+)
│   └── src/
│       ├── main.rs           # MPC server setup
│       └── routes/
│           ├── keypair.rs    # Key generation & lookup
│           └── sign.rs       # Step-one / step-two signing
├── indexer/          # Balance & transaction indexer
│   └── src/main.rs           # Polling loop
├── store/            # Shared DB models (main database)
├── mpc-store/        # MPC DB models (keypair storage)
├── frontend/         # Next.js application
│   ├── app/
│   │   ├── (auth)/           # Signin / signup pages
│   │   ├── dashboard/        # Main wallet UI
│   │   └── page.tsx          # Landing page
│   ├── components/
│   │   ├── SendComponent.tsx
│   │   └── SwapComponent.tsx
│   └── store/                # Zustand stores
└── Cargo.toml        # Rust workspace

API Endpoints

Public

Method Endpoint Description
POST /api/v1/signup Register a new user (auto-assigns MPC wallet)
POST /api/v1/signin Login, returns JWT

Authenticated (Bearer token)

Method Endpoint Description
GET /api/v1/user Current user info
POST /api/v1/send Send SOL to an address
POST /api/v1/quote Get a swap quote from Jupiter
POST /api/v1/swap Execute a swap using a stored quote
GET /api/v1/balance/sol SOL balance
GET /api/v1/balance/token/{mint} SPL token balance
GET /api/v1/balance/all All balances with asset info
GET /api/v1/assets List supported tokens

Admin

Method Endpoint Description
POST /api/v1/admin/mpc-node Register an MPC node
POST /api/v1/admin/generate-aggregated-keys Generate aggregated keys from MPC nodes
POST /api/v1/admin/asset Add a supported token

Getting Started

Prerequisites

  • Rust (1.75+)
  • Node.js (18+)
  • PostgreSQL (12+)
  • Two PostgreSQL databases: one for the main app, one for MPC keypairs

1. Clone & Setup Environment

git clone https://github.com/thecurioussailor/tiplink-clone.git
cd tiplink-clone

Create .env files from the examples:

cp backend/.env.example backend/.env
cp mpc/.env.example mpc/.env
cp indexer/.env.example indexer/.env
cp store/.env.example store/.env
cp mpc-store/.env.example mpc-store/.env

2. Configure Environment Variables

backend/.env

DATABASE_URL=postgresql://user:password@localhost/bonfire
MPC_API_KEY=your-mpc-api-key
JWT_SECRET=your-jwt-secret
SOLANA_RPC_URL=https://api.devnet.solana.com

mpc/.env

DATABASE_URL=postgresql://user:password@localhost/bonfire_mpc
MPC_PORT=3001
MPC_API_KEY=your-mpc-api-key

indexer/.env

DATABASE_URL=postgresql://user:password@localhost/bonfire
RPC_URL=https://api.devnet.solana.com
INTERVAL_MS=60000
JWT_SECRET=your-jwt-secret

3. Run Database Migrations

Migrations run automatically on startup via SQLx.

4. Start Services

# Terminal 1 - Backend
cd backend && cargo run

# Terminal 2 - MPC Node (run multiple with different ports for production)
cd mpc && cargo run

# Terminal 3 - Indexer
cd indexer && cargo run

# Terminal 4 - Frontend
cd frontend && npm install && npm run dev

5. Initial Setup (Admin)

  1. Create an admin user (set is_admin = true in the database)
  2. Register MPC nodes via POST /api/v1/admin/mpc-node
  3. Generate aggregated keys via POST /api/v1/admin/generate-aggregated-keys
  4. Add supported assets (SOL, USDC, etc.) via POST /api/v1/admin/asset

Now users can sign up and each will be assigned a wallet automatically.


Database Schema

Two PostgreSQL databases:

Main DB - users, aggregated_keys, assets, balances, transactions, quotes, mpc_nodes

MPC DB - key_pairs (stores individual node keypairs)

Key relationships:

  • Each user is assigned one aggregated_key (their wallet)
  • Each aggregated_key maps to keypair IDs across all MPC nodes (node_keypairs JSONB)
  • Balances are tracked per user per asset, updated by the indexer
  • Transactions store on-chain history linked to users

Security Model

  • Private keys are split across 3 MPC nodes - no single point of compromise
  • All transaction signing happens server-side through the MPC protocol
  • Passwords are hashed with bcrypt
  • API authentication uses JWT with 24-hour expiry
  • MPC nodes authenticate via API key headers
  • Quote ownership is verified before swap execution

License

MIT

Releases

No releases published

Packages

 
 
 

Contributors