Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/natureloved/DeadMan-Vault/llms.txt

Use this file to discover all available pages before exploring further.

Deadman Vault enforces a simple contract: as long as you keep checking in, your funds stay locked and only you control them. The moment you stop — regardless of why — an automated keeper detects the silence, waits out a grace period, and then distributes your USDCx to your configured beneficiaries according to the exact splits and vesting schedules you defined at setup. No court orders, no probate, no custodian with discretionary power over your assets. The full lifecycle — from first deposit to final payout — is described below.

Architecture

The protocol layers a Next.js application and Supabase database on top of FlowVault’s on-chain token routing, with a Vercel Cron Job acting as the automated keeper:
┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Browser   │────▶│  Next.js App │────▶│  FlowVault  │
│  (Wallet)   │     │  (API/Pages) │     │   SDK       │
└─────────────┘     └──────┬───────┘     └─────────────┘

                    ┌──────▼───────┐
                    │   Supabase   │
                    │  (Postgres)  │
                    └─────────────┘
The keeper is a server-held Stacks keypair, one per vault, generated at vault creation and encrypted at rest. Because flowvault-v2 keys all vault state off tx-sender, only the address that called deposit can call withdraw — which means the keeper must act on the owner’s behalf once the vault flatlines. This is a custodial design limited to testnet. See the Security Model for the production-grade alternative.

Step-by-Step Walkthrough

1

Create a Vault

The owner connects their Leather or Xverse wallet and fills in the vault creation form:
  • Vault name and optional message to beneficiaries
  • Heartbeat interval — how many days between required check-ins (options: 7 days, 14 days, 1 month, 2 months, 3 months, 6 months, 1 year, 2 years)
  • Beneficiaries — one or more Stacks addresses, each with a name, optional email, an allocation_percent (must sum to exactly 100%), and an optional vesting_days cliff
  • Deposit amount — the USDCx balance to lock in the vault
On submission, the API calls initVault(), which validates that allocations total 100%, generates a dedicated keeper keypair for this vault, saves an encrypted copy of the keeper private key to Supabase, and returns the vault’s unique keeper address. Vault status is set to "funding".The owner then signs a plain USDCx token transfer from their wallet to the keeper address. This is the only transaction the owner ever signs — all subsequent FlowVault interactions are performed by the keeper on their behalf.
2

Vault Activation

Once the owner’s USDCx transfer is broadcast, they submit the transaction ID to the API, which calls finalizeVaultFunding(). The keeper:
  1. Queries the current Stacks block height
  2. Computes deadlineBlock = currentBlock + heartbeatIntervalDays × 144
  3. Calls FlowVault.setRoutingRules() with lockAmount = totalDeposited and lockUntilBlock = deadlineBlock
  4. Calls FlowVault.deposit() to lock the full balance on-chain
Vault status advances to "active" and the deadline block is stored in Supabase.
Lock-stacking is FlowVault’s mechanism for extending an existing lock. When a new deposit is made with an updated lockUntilBlock, FlowVault extends the deadline on the entire locked balance — not just the new deposit amount. This is how heartbeat check-ins extend the countdown without unlocking previous funds.
3

Heartbeat Check-Ins

To prove they are still in control, the owner must check in before each heartbeatDeadlineBlock. A check-in works exactly like the initial deposit, but for the minimum amount:
  1. The owner signs a USDCx transfer of 0.01 USDCx to the vault’s keeper address
  2. They submit the transaction ID to the API, which calls performHeartbeat()
  3. The keeper computes a new deadlineBlock = currentBlock + heartbeatIntervalDays × 144 and calls setRoutingRules() + deposit() with lockAmount = 0.01 USDCx
  4. FlowVault’s lock-stacking extends the lockUntilBlock for the entire locked balance to the new deadline
Each successful heartbeat is recorded in the heartbeats table with block_height, tx_id, and deposited_amount.
The heartbeat interval is configurable at vault creation. A 30-day interval means you have roughly one calendar month between required check-ins. Choose an interval that matches your availability — not too short to be burdensome, not too long to leave beneficiaries waiting unnecessarily.
4

Warning Phase

The keeper cron runs periodically and checks every active vault’s heartbeat_deadline_block against the current block height. When the remaining blocks drop to 432 blocks (≈ 3 days) before the deadline, the keeper:
  • Sets vault status to "warning"
  • Sends a warning email to the owner’s configured address via Resend
This gives the owner a 3-day window to submit a check-in before entering the grace period. If the owner checks in during this phase, the vault returns to "active" status and the countdown resets.
5

Grace Period

If the heartbeat_deadline_block passes without a check-in, the keeper cron detects the overdue vault and begins the grace period:
  • Vault status changes to "grace_period"
  • An urgent email is sent to the owner
  • Optional notification emails are sent to beneficiaries (if emails were configured)
The grace period lasts 288 blocks (≈ 48 hours). This buffer exists to protect against transient issues — network outages, wallet unavailability, travel — that could cause an accidental miss. The owner can still submit a heartbeat during the grace period to abort the payout.
6

Trigger

When the grace period expires (current block ≥ heartbeatDeadlineBlock + 288), the keeper cron marks the vault as triggered:
  • Vault status changes to "triggered"
  • Beneficiaries with email addresses receive a claim notification
  • vesting_release_at timestamps are computed for each beneficiary: triggerTimestamp + vestingDays × 86400 seconds
Beneficiaries with vesting_days = 0 are immediately eligible. Beneficiaries with a vesting cliff must wait until their individual vesting_release_at timestamp passes before receiving funds.
7

Automatic Settlement

On each keeper cron run after the vault is triggered, the settlement routine:
  1. Calls FlowVault.withdraw() through the keeper to retrieve the unlocked balance
  2. Iterates through every beneficiary record for the vault
  3. For each beneficiary where claimed = false and vesting_release_at ≤ now: sends a USDCx transfer equal to totalBalance × (allocation_percent / 100)
  4. Marks claimed = true and records claimed_tx_id in the beneficiaries table
Vault status advances to "claimed" once all beneficiaries have been paid.
Settlement is fully automatic — beneficiaries do not need to take any action. The keeper cron re-runs on every cycle, so beneficiaries with future vesting cliffs will be paid automatically once their cliff date passes, without any manual intervention.
8

Vesting Cliffs

Beneficiaries configured with vesting_days > 0 receive their allocation only after their computed vesting_release_at timestamp passes. For example, a beneficiary with vesting_days = 365 will not receive funds until one year after the vault was triggered.On each keeper cron cycle, the settlement routine checks every unclaimed beneficiary. If vesting_release_at has passed since the last sweep, the transfer is sent automatically. This means:
  • No action required from beneficiaries — the cron handles retry
  • Staggered releases — different beneficiaries can have different vesting periods on the same vault
  • Vesting is enforced at the application layer by the keeper, not on-chain, consistent with the current testnet custodial architecture
9

Claim Page

If the keeper cron has not yet run since the vault was triggered, beneficiaries can manually initiate settlement by visiting the /claim/[vaultId] page and clicking “Check & Release Funds”. This calls the same settlement routine as the cron job and immediately distributes any eligible balances.This ensures beneficiaries are never dependent on cron timing — they always have an on-demand fallback to trigger payout themselves.

Timing Constants Reference

These constants (from src/lib/constants.ts) govern all block-based timing calculations in the protocol:
ConstantValueMeaning
BLOCKS_PER_DAY144Approximate Stacks blocks mined per day (one block every ~10 minutes)
GRACE_PERIOD_BLOCKS288Grace period length — 2 days after a missed deadline before payout triggers
WARNING_BLOCKS432Warning threshold — 3 days before deadline, warning email is sent
HEARTBEAT_AMOUNT"0.01"Minimum USDCx required per heartbeat check-in transfer
All deadlines are expressed as block heights, not wall-clock timestamps. Because Stacks block times are approximately (not exactly) 10 minutes, real-world elapsed time may vary slightly. The 144 blocks/day constant is a best-effort approximation — plan your heartbeat interval with some margin.

Build docs developers (and LLMs) love