LifeProof is a non-custodial “proof of life” protocol on Solana: you lock tokens in a program-controlled vault, set a nominee and a check-in interval, and extend your deadline by signing proof_of_life on time. If you stop checking in, after a grace period anyone (or an automated keeper) can call claim_vault and the program sends everything to the nominee — not to the caller.
On mainnet builds, idle liquidity can be deposited into Kamino Finance lending reserves so the vault earns yield as kTokens until claim or close. On devnet (default build), tokens stay in the vault’s associated token account with no Kamino CPI.
This repository is a full stack: Anchor program, Codama-generated TypeScript client, Next.js dApp, keeper bot, and GitHub Actions scheduling.
- Architecture at a glance
- On-chain program (Anchor)
- Codama: IDL → TypeScript client
- Frontend: Next.js, wallet adapter, and the Codama bridge
- Keeper bot and automation
- Testing
- Repository layout
- Build variants and Kamino
- Accounts and PDAs
- Deployments
- Further reading
┌─────────────────────────────────────────────────────────────────────────┐
│ Solana cluster │
│ ┌──────────────────┐ CPI / SPL ┌─────────────────────────────┐ │
│ │ proof_pol │ ◄──────────────► │ SPL Token, ATA, (Kamino*) │ │
│ │ (Anchor 0.32) │ │ * mainnet feature only │ │
│ └────────┬─────────┘ └─────────────────────────────┘ │
└───────────┼────────────────────────────────────────────────────────────┘
│
│ JSON IDL (anchor build)
▼
┌───────────────────────┐ Codama renderers ┌────────────────────────┐
│ target/idl/ │ ────────────────────────► │ client/generated/js │
│ proof_pol.json │ nodes-from-anchor │ (+ frontend lib copy) │
└───────────────────────┘ └───────────┬────────────┘
│
┌──────────────────────────────────────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐
│ Next.js dApp │ wallet-adapter + web3.js tx │ ProofPolClient │ │ keeper.ts │
│ (React 19) │ ◄── codama instructions ───────│ (bridge layer) │ │ Anchor IDL │
└─────────────────┘ └─────────────────┘ └──────────────┘
Single source of truth for instructions and account layouts: the Anchor IDL emitted by anchor build. Codama turns that IDL into typed JavaScript builders and decoders. The frontend wraps those builders into TransactionInstruction objects that @solana/wallet-adapter can sign. The keeper uses the same program semantics via the Anchor IDL and @coral-xyz/anchor for a different integration style (no Codama in the keeper script today).
| Item | Detail |
|---|---|
| Framework | Anchor 0.32.1 (anchor-lang, anchor-spl with token, associated_token, init-if-needed) |
| Language | Rust (edition 2021), compiled to BPF / SBPF for Solana |
| Entry | programs/proof_pol/src/lib.rs — registers instructions and modules |
| Features | mainnet — optional Cargo feature; when enabled, Kamino deposit/redeem CPI paths compile in. Default = devnet-style vault ATA only |
| Instruction | Role |
|---|---|
initialize_vault |
Creates / funds the vault PDA, sets nominee, interval, mint; may CPI Kamino on mainnet |
proof_of_life |
Owner extends deadline by one interval while vault is active and not claimable |
claim_vault |
After deadline + CLAIM_GRACE_PERIOD, sends funds to nominee and closes vault-related accounts |
close_vault |
Owner closes while in good standing; returns funds to owner |
Custom errors live in programs/proof_pol/src/error.rs. Constants (grace period, Kamino pubkeys for mainnet) live in programs/proof_pol/src/constants.rs.
Kamino’s on-chain interfaces often pull older solana-program trees than Anchor 0.32. This repo uses raw instructions built in kamino_cpi.rs: fixed 8-byte Anchor discriminators, AccountMeta / invoke_signed, and explicit account ordering. That avoids version-pinned Kamino Rust crates in the same dependency graph as the program.
Codama (codama-idl/codama) is an IDL toolkit: it parses your program interface into an intermediate node tree, then visitors emit clients in multiple languages.
| Package | Role |
|---|---|
codama |
Core CLI / library entrypoints for pipelines |
@codama/nodes-from-anchor |
rootNodeFromAnchorWithoutDefaultVisitor — converts Anchor JSON IDL → Codama node tree (skips Anchor’s default account visitor so your explicit accounts stay explicit) |
@codama/renderers |
renderJavaScriptVisitor (and optional Umi / Rust visitors, commented in generator) — emits files to a target directory |
@codama/visitors-core |
visit — walks the tree and runs the renderer |
File: client/generate-client.ts
- Imports
../target/idl/proof_pol.json(must exist afteranchor build). - Casts it to
AnchorIdland builds:
const node = rootNodeFromAnchorWithoutDefaultVisitor(anchorIdl). - Invokes
visit(node, await renderJavaScriptVisitor(outputDir)). - Output today:
client/generated/js/src/— JavaScript/TypeScript modules for programs, instructions, accounts, errors, shared types.
Script: yarn generate:client (see root package.json).
Typical layout under client/generated/js/src/:
programs/— program address constant, program link helpersinstructions/— one file per instruction (initializeVault,proofOfLife,claimVault,closeVault) with typed account metas and instruction data encodersaccounts/— decoders / discriminators forCommitmentVault,OwnerProfile, etc.errors/— typed error codes where the IDL exposes themshared/— shared types and helpers
The Next.js app ships an equivalent Codama-style tree under frontend/src/lib/proof-pol/ (header comment: autogenerated; do not hand-edit — regenerate and copy or wire generation into your workflow). The dApp imports getInitializeVaultInstructionAsync, getClaimVaultInstructionAsync, decoders, PROOF_POL_PROGRAM_ADDRESS, etc., from that tree.
- IDL is law: Any account list or discriminator change in Rust is reflected after rebuild + regen, reducing drift between chain and client.
- Typed builders: Instruction helpers know account roles (signer / writable) from the IDL.
- Solana Kit alignment: Generated code targets
@solana/kittypes (Address,TransactionSigner, etc.). The app still uses@solana/web3.jsforConnection,Transaction, and wallet-adapter compatibility, so a thin adapter layer converts Codama instructions → legacyTransactionInstruction(see below).
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI | React 19, Tailwind CSS v4 (@import "tailwindcss" in globals.css) |
| Solana RPC / txs | @solana/web3.js |
| Wallet UX | @solana/wallet-adapter-react, @solana/wallet-adapter-react-ui, @solana/wallet-adapter-wallets |
| Instruction types | @solana/kit (address, TransactionSigner) + Codama-generated modules under src/lib/proof-pol/ |
File: frontend/src/lib/proof-pol/client.ts — ProofPolClient
- Calls async builders like
getInitializeVaultInstructionAsync/getClaimVaultInstructionAsyncwith concretePublicKeys and bigint amounts. - Converts each Codama instruction into a
@solana/web3.jsTransactionInstructionvia a localcodamaToWeb3Instructionmapper (maps Codama accountrole→isSigner/isWritablefor legacy runtime). - Sends through
wallet.sendTransactionafter recent blockhash + optional ATA pre-instructions (e.g. WSOL wrap flow on create page). fetchAllActiveVaultsusesconnection.getProgramAccountswithmemcmpfilters on vault discriminator andisActivebyte offset — efficient “all active vaults” reads for the Help Others (/keeper) page.
Domain constants (mints, Kamino reserve addresses for UI-side account ordering when needed) live in frontend/src/lib/constants.ts.
| Piece | Technology |
|---|---|
| Runtime | Node.js, TypeScript, ts-node |
| Solana | @coral-xyz/anchor, @solana/web3.js, @solana/spl-token |
| Interface | require("../target/idl/proof_pol.json") — uses Anchor’s IDL + program class to build claim_vault |
File: keeper/keeper.ts
- Loads a keypair from process environment (used in CI and locally).
- Scans vault PDAs for the owner pattern your protocol uses, decodes deadlines, compares to
nowwith the sameCLAIM_GRACE_PERIODsemantics as on-chain (172_800seconds). --onceorCI=true: single scan and exit (GitHub Actions). Otherwise optional long-interval loop for a server.
Automation: .github/workflows/keeper.yml — scheduled cron: "0 0 */2 * *" (every two days UTC) plus workflow_dispatch for manual runs. The workflow uses actions/checkout@v5 and actions/setup-node@v5 with Node 22, then npm ci --omit=dev: production dependencies only (no anchor-bankrun / solana-bankrun / test tools). Root .npmrc sets legacy-peer-deps=true so local npm install still resolves anchor-bankrun (peer Anchor ^0.30 vs project 0.32) for anchor test. If no vaults are past deadline + grace, the keeper finishes with no claims and the job is still green — that is normal.
| Tool | Use |
|---|---|
| Anchor | anchor test (see Anchor.toml [scripts] — runs ts-mocha on files under tests/) |
| Mocha + Chai | Assertion style in TypeScript tests |
| solana-bankrun / anchor-bankrun | Fast local ledger tests without a full solana-test-validator loop where configured |
Tests cover flows such as initialize, proof of life, claim, and close (see tests/*.ts).
proof_pol/
├── Anchor.toml # Cluster, program id, test script
├── Cargo.toml # Workspace root (if present) / meta
├── package.json # Codama + anchor + test deps; yarn generate:client
├── client/
│ ├── generate-client.ts # Codama: IDL → client/generated/js
│ └── generated/js/src/ # Generated JS (source for syncing to frontend)
├── programs/proof_pol/ # On-chain program
│ └── src/
│ ├── lib.rs
│ ├── constants.rs
│ ├── error.rs
│ ├── kamino_cpi.rs # Raw Kamino ix builders (mainnet feature)
│ ├── instructions/
│ └── state/
├── target/idl/proof_pol.json # Produced by anchor build — Codama input
├── tests/ # ts-mocha integration tests
├── frontend/ # Next.js dApp
│ └── src/
│ ├── app/ # Routes: /, /dashboard, /create, /keeper, /upcoming
│ ├── components/
│ ├── hooks/
│ ├── lib/proof-pol/ # Codama-generated client + ProofPolClient bridge
│ └── providers/
├── keeper/
│ └── keeper.ts # Permissionless claim bot
└── .github/workflows/
└── keeper.yml # Scheduled keeper
| Build | Command idea | Behavior |
|---|---|---|
| Default (devnet) | anchor build |
No mainnet feature — vault holds tokens in vault ATA; no Kamino CPI in binary |
| Mainnet-capable | anchor build -- --features mainnet |
Compiles Kamino deposit (initialize) and redeem (claim/close) paths |
Always verify reserve accounts, market, mints, and instruction ordering against the current Kamino deployment before production; raw CPI is powerful but must match live interfaces.
| Account | Seeds | Role |
|---|---|---|
| OwnerProfile | [b"owner_profile", owner] |
Tracks per-owner vault_id counter for the next vault index |
| CommitmentVault | [b"vault", owner, vault_id.to_le_bytes()] |
One PDA per (owner, vault id); stores nominee, mint, stake, deadline, isActive, Kamino-related fields on mainnet |
| vault_ata | ATA(owner = vault PDA, mint) | Custodies SPL (or staging liquidity around Kamino redeem on mainnet) |
| nominee_ata | ATA(nominee, mint) | Destination on claim; may be created idempotently by payer |
Exact struct layouts and bumps are defined in the Anchor program; the IDL and Codama account decoders match those layouts.
| Network | Program ID |
|---|---|
| Devnet | DHHHbFFGWX2y4HkgdePB61bUZxdJQw8VmfGvgR4cxeof |
| Mainnet | Deploy and record when ready |
This section is intentionally high level. Priorities change with audits, partners, and how much value sits in vaults.
| Direction | Notes |
|---|---|
| Mainnet | Deploy the mainnet feature build only after Kamino account sets and CPI ordering are re-verified on live programs; use dedicated RPC and multisig (or timelock) for upgrade authority. |
| Safety and ops | Focused program review or audit before meaningful TVL; keeper monitoring, alerts, and runbooks; document account layout upgrades so clusters do not mix incompatible vault sizes. |
| Product | Clearer onboarding and risk copy; optional indexer or cache for dashboards at scale; mobile-friendly flows. |
| Automation | Harden keeper (retries, metrics); optional companion browser tooling that orchestrates txs while signing stays in the user’s wallet—policy remains on-chain. |
- Multi‑vault per owner — one profile, many mints / strategies via
vault_id(e.g. USDC vault, SOL vault). - Vault templates (“strategies”) — presets for interval, grace, yield on/off, and copy tuned for use cases (family, team treasury, founder-style accountability metaphors).
- Split or ranked nominees — fixed % to multiple wallets, or primary + backup with explicit rules.
- Nominee payout preferences — optional payout address vs on-chain nominee; nominee-signed updates where safe.
- Basket vaults — one commitment PDA holding multiple SPL ATAs with one coordinated claim path.
- Time-locks & recovery windows — extra delay after a missed deadline before the nominee can execute; optional owner “panic extend” with caps.
- Read-only delegation — watchers / accountants see status without signing power.
- Strategy router beyond Kamino — pluggable yield adapters (Marginfi, Drift, Jupiter Lend, Solend) selectable per vault at initialization. The same raw-CPI pattern used for Kamino generalizes to a thin adapter layer, so vaults stop being a "Kamino wrapper" and become a non-custodial, yield-bearing commitment primitive with the user picking the venue.
- Auto-compound vs. live yield stream — at vault creation the owner picks how earned yield behaves: compound back into principal (default), stream to the nominee in real time (a recurring allowance that automatically converts to full inheritance on a missed proof), or route to a third address (charity, DAO treasury, co-signer). The "stream while alive, lump on death" mode turns LifeProof into both inheritance and programmable allowance infrastructure with one PDA.
- Yield-only claim — let a designated address (e.g. a child, a contributor) claim accrued yield on a schedule without ever touching principal, so the owner can use a vault as a self-custodial trust fund.
- Strategy migration — owners can move a live vault between strategies (e.g. Kamino → Marginfi) without breaking the proof-of-life schedule, so changing venues never resets the inheritance clock.
- Decentralized / credibly neutral automation — incentive layer for claim executors (tips, ordering rules, or integration with Clockwork, cron-style networks, or keeper marketplaces) so execution is not only a single hosted bot.
- On-chain “job” registry — vaults surface next
claimable_at; anyone (or specialized bots) competes to execute. - Push notifications / webhooks — off-chain indexer → email, Telegram, mobile push (no custody of user keys).
- Calendar & ICS export — “next proof due” in normal productivity tools.
- Formal spec + threat model — written for auditors and power users.
- Bug bounty / audit pipeline — staged before high TVL mainnet.
- Upgrade policy — multisig, timelock, user-visible changelog.
- Insurance or risk partners — exploratory, if the category matures.
- Indexer / subgraph-style API — fast dashboards and “upcoming claims” at scale.
- Mobile-first PWA — proof-of-life from a phone without building a full wallet.
- Simulator — “if I miss N check-ins, nominee receives funds at time T” before the user commits funds. in
- Codama: github.com/codama-idl/codama
- Anchor: anchor-lang.com
- Solana wallet adapter: github.com/anza-xyz/wallet-adapter
- Kamino: kamino.finance — verify program IDs and reserve metadata for your target cluster
LifeProof: programmable inheritance and accountability, with the interface generated from the same IDL that defines the chain’s behavior.