Skip to content

t-rhex/dead-mans-switch

Repository files navigation

Dead Man's Switch

Your crypto shouldn't die with you.

Open-source crypto inheritance platform built on OWS + Base + Chainlink

Quick StartHow It WorksMock vs RealDeploymentSmart ContractContributing


Dead Man's Switch automatically distributes your crypto assets to the people you choose if you ever become unreachable. Set up your will, check in periodically, and know that your loved ones are protected.

Quick Start

git clone https://github.com/yourusername/dead-mans-switch.git
cd dead-mans-switch
./setup.sh
npm run dev:all

Open http://localhost:3001. That's it.

What happens:

  1. setup.sh installs all dependencies, copies .env.example files, and sets up the SQLite database
  2. npm run dev:all starts the API (port 3000) and frontend (port 3001) in mock mode
  3. You land on the welcome page → create an account → set up your first will

Prerequisites

  • Node.js 20+
  • npm

How It Works

For the owner (you):

  1. Create your will — name your beneficiaries (who gets what %) and guardians (who confirms if you're gone)
  2. Fund your vault — send USDC to your wallet address on Base chain
  3. Check in regularly — click a button or click a link in your email every 30 days (configurable)
  4. That's it — as long as you check in, nothing happens

If you stop checking in:

Day 0:   You miss a check-in
         → Grace period starts (7 days default)
         → You get email alerts + push notifications
         → You can still check in to cancel

Day 7:   Grace expires
         → Your guardians are notified
         → They vote on whether you're truly unreachable

Day 7+:  2 of 3 guardians vote "proceed"
         → Final pending window starts (48 hours)
         → You can STILL cancel

Day 9+:  Pending window expires
         → Funds are distributed to your beneficiaries
         → Immediate beneficiaries get their full share
         → Drip beneficiaries get a rate-limited vault

For beneficiaries:

  1. They receive an invite link via email
  2. They click it, enter their wallet address (or ENS name like sarah.eth)
  3. You approve their address
  4. If the plan executes, funds are sent automatically
  5. They can check their status anytime on the claim page

For guardians:

  1. They receive an invite to accept the guardian role
  2. They acknowledge the responsibility
  3. If you become unreachable, they vote on whether to proceed
  4. They can vote "proceed", "unsure", or "cancel"

Mock vs Real

The app has two modes controlled by MOCK_TRANSFERS:

Mock Mode (default for development)

npm run dev:all    # or MOCK_TRANSFERS=true npm run dev

What mock mode does:

  • Wallet balance always shows $10.00 (no real chain query)
  • USDC transfers are simulated — no real tokens move, fake tx hashes are generated
  • Emails are logged to console (not actually sent)
  • Push notifications are logged (not actually sent)
  • OWS wallets are created for real (local encrypted vault at ~/.ows/)
  • The state machine, guardian voting, drip vault — everything else works for real

Use mock mode for: development, demos, testing the full flow without real money.

Real Mode (production)

MOCK_TRANSFERS=false npm run dev    # or just: npm run dev

What changes in real mode:

  • Wallet balance is queried from Base chain via RPC
  • USDC transfers are signed by OWS and broadcast to Base — real tokens move
  • You need real USDC on Base in your wallet
  • You need ETH on Base for gas fees
  • Emails are sent via Resend or SMTP — see Email Setup Guide

Switching from mock to real:

  1. Set MOCK_TRANSFERS=false in apps/api/.env
  2. Set BASE_RPC_URL=https://mainnet.base.org (mainnet) or keep the default (Base Sepolia testnet)
  3. Fund your wallet with USDC + ETH on the chosen chain
  4. Set up email — see Email Setup Guide
  5. Restart the server

Recommended path: Start on Base Sepolia testnet (free test USDC from faucets), then switch to mainnet when ready.

Features

Core

  • 5-gate safety pipeline — check-in → grace → guardian vote → pending → execution
  • Programmable drip payouts — release funds gradually over time
  • Guardian quorum — 2-of-3 (configurable) must agree before any distribution
  • Emergency freeze — halt everything instantly with one click
  • Personal messages — leave words for your loved ones, shown after execution

Authentication & Security

  • Passkey (WebAuthn) — sign in with Touch ID / Face ID, no passwords
  • Email/password — traditional auth as fallback
  • Hardware wallet support — connect Ledger/Trezor via WalletConnect
  • Safe multi-sig — use Gnosis Safe as the policy owner for maximum security
  • Field encryption — emails and personal messages encrypted at rest (AES-256-GCM)
  • Rate limiting — per-endpoint limits to prevent abuse
  • Invite token expiry — 72-hour expiration on invite links

Blockchain

  • Smart contract escrow — funds held on-chain, not by the app
  • On-chain guardian voting — guardians vote directly on the contract
  • Chainlink Automation — decentralized keepers trigger execution (no server dependency)
  • Multi-token — distribute USDC, ETH, WBTC, or any ERC-20
  • NFT inheritance — transfer ERC-721 NFTs to beneficiaries
  • Gasless claiming — pull mode lets relayers pay gas for beneficiaries
  • ENS resolution — enter sarah.eth instead of 0x...

UX

  • Beneficiary invite flow — they provide their own wallet, you approve
  • Guardian acceptance — formal role acknowledgment before voting access
  • One-click email check-in — click a link in the reminder email
  • Push notifications — browser notifications for check-in reminders
  • Activity timeline — full event history on the dashboard
  • Mobile responsive — hamburger menu, stacking layouts
  • Light/dark mode
  • GDPR data export + account deletion
  • Terms of Service page

Tech Stack

Layer Technology
Backend Hono + Node.js + SQLite (Drizzle ORM)
Frontend Next.js 16 + shadcn/ui + Tailwind CSS
Auth Better Auth (passkey + email + SIWE)
Wallet OWS SDK + wagmi + ConnectKit
Smart Contract Solidity + Hardhat + OpenZeppelin + Chainlink
Chain Base (USDC) via viem
Email Resend / Nodemailer SMTP / console fallback

Scripts

Command Description
npm run dev:all Start API (mock) + frontend
npm run dev Start backend only (real mode)
npm run dev:mock Start backend only (mock mode)
npm run dev:web Start frontend only
npm test Run 30 backend tests
npm run contracts:test Run 82 smart contract tests
npm run build Build frontend (22 routes)
npm run seed Seed demo data (wallets + policy + beneficiaries + guardians)
npm run reset Clear all data
npm run backup Backup SQLite database
make dev Shortcut for npm run dev:all
make test Run all tests (backend + contracts)

Configuration

API (apps/api/.env)

Variable Default Description
PORT 3000 Backend port
MOCK_TRANSFERS true true = simulated transfers, false = real USDC on Base
BETTER_AUTH_URL http://localhost:3000 Where the API is accessible (for auth callbacks)
RPID localhost Passkey domain (e.g., yourdomain.com in production)
ORIGIN http://localhost:3001 Frontend URL (for CORS + cookies)
ENCRYPTION_KEY dev fallback Change in production. Encrypts emails and messages.
EXECUTOR_SECRET demo-secret Change in production. Protects the executor endpoint.
RESEND_API_KEY Resend.com API key for sending emails
SMTP_HOST SMTP server (alternative to Resend)
BASE_RPC_URL Base Sepolia Base chain RPC (https://mainnet.base.org for production)
LOG_LEVEL info debug / info / warn / error

Web (apps/web/.env.local)

Variable Default Description
NEXT_PUBLIC_SKIP_AUTH false true bypasses auth (for demos only)
NEXT_PUBLIC_CONTRACT_ADDRESS Deployed escrow contract address
NEXT_PUBLIC_WC_PROJECT_ID WalletConnect Cloud project ID

See apps/api/.env.example and apps/web/.env.example for the complete list.

Architecture

apps/
├── api/                      # Hono backend
│   ├── src/server.ts         # Entry point + cron loop
│   ├── src/auth/             # Better Auth (passkey + email + SIWE)
│   ├── src/cron/             # 5-gate state machine
│   ├── src/db/               # Drizzle schema + SQLite
│   ├── src/lib/              # Email, encryption, events, rate limiting, logging
│   ├── src/ows/              # OWS wallet + USDC transfer helpers
│   └── src/routes/           # API endpoints (~30 routes)
└── web/                      # Next.js frontend (22 routes)
    ├── (dashboard)/          # Authenticated: overview, check-in, guardians, drip, invites, settings
    ├── welcome/              # Public landing page
    ├── login/                # Auth (passkey + email)
    ├── claim/                # Beneficiary claim page (public)
    ├── accept-invite/        # Beneficiary invite acceptance (public)
    ├── accept-guardian/       # Guardian role acceptance (public)
    ├── deposit/              # Hardware wallet USDC deposit
    ├── onchain-checkin/      # On-chain check-in via Ledger
    └── security/             # Custody model settings

packages/
└── contracts/                # Solidity smart contracts
    ├── DeadMansSwitch.sol    # Escrow + guardian voting + Chainlink + multi-token + NFT
    └── 82 tests

Smart Contract

The escrow contract enforces fund protection on-chain. Even if the backend server goes down, the critical path works:

Action Server alive Server dead
Owner check-in Dashboard button or email link Call checkIn() directly from Ledger
Guardian voting Web UI Call vote() directly on the contract
Distribution trigger Backend executor Chainlink keeper calls performUpkeep()
Beneficiary claiming Web claim page Call claim() on the contract

Contract Features

  • USDC escrow with check-in timer enforcement
  • On-chain guardian voting with configurable quorum
  • Chainlink Automation — decentralized execution trigger
  • Multi-ERC20 distribution (USDC, WBTC, DAI, etc.)
  • Native ETH distribution
  • ERC-721 NFT inheritance (single + batch)
  • Pull mode — gasless claiming for beneficiaries
  • Emergency withdraw — owner can pull all funds at any time
  • Freeze/unfreeze — halt distribution instantly

Deploy

cd packages/contracts
DEPLOYER_PRIVATE_KEY=0x... EXECUTOR_ADDRESS=0x... npx hardhat run scripts/deploy.ts --network baseSepolia

Then set NEXT_PUBLIC_CONTRACT_ADDRESS in your .env.

Deployment

Local Development

./setup.sh       # One-time setup
npm run dev:all  # Start everything (mock mode)

Docker Compose

cp .env.docker.example .env   # Edit ENCRYPTION_KEY, EXECUTOR_SECRET
docker compose up -d           # Start API + Web
docker compose exec api npx tsx scripts/seed-demo.ts  # Optional: seed data

Production with Caddy (auto HTTPS)

cp .env.docker.example .env
# Edit: DOMAIN, ENCRYPTION_KEY, EXECUTOR_SECRET, MOCK_TRANSFERS=false

DOMAIN=deadswitch.yourdomain.com docker compose -f docker-compose.production.yml up -d

Caddy auto-provisions HTTPS via Let's Encrypt. DNS must point to your server. Ports 80 + 443 must be open.

Internet → Caddy (:443, auto HTTPS)
             ├── / → Next.js frontend
             └── /api/* → Hono backend
           + daily SQLite backups

Contributing

See CONTRIBUTING.md for development setup, code style, and PR guidelines.

Tests

  • 30 backend tests (Vitest) — auth, state machine, drip vault, validation
  • 82 smart contract tests (Hardhat/Chai) — escrow, guardian voting, Chainlink, multi-token, NFT, freeze, emergency withdraw
make test  # or: npm test && npm run contracts:test

License

MIT

About

Your crypto shouldn't die with you. Open-source crypto inheritance platform built on OWS + Base + Chainlink.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors