LAZARUS · DOCS

Lazarus Protocol

A crypto continuity layer. Your wallet stays yours. When your on-chain heartbeat stops, a network of people you trust takes the right action. Transparently, on-chain, and with no ability to steal from you.

What is Lazarus

Every year, billions in crypto go unrecoverable. Lost seed phrases. Owners who die or disappear. Families locked out of the assets their partner spent a lifetime building. Existing "recovery" solutions force you to hand custody to someone else or give up self-custody entirely.

Lazarus is a different model: an insurance layer on top of the wallet you already use. It reads your public on-chain activity as a heartbeat. If that heartbeat stops for longer than your chosen baseline, a protocol of people you designated. A Council. Begins a transparent, contract-enforced process of escalation. You can always resurrect. Confirmers can never steal. Normal transactions are never intercepted.

IN ONE SENTENCE

Lazarus watches your wallet for silence, gives the people you trust a verifiable way to respond when something's wrong, and gives you the guaranteed ability to return and cancel everything.

The four invariants

These are enforced at the contract level. Not in a terms-of-service document. If any of these ever fails, Lazarus fails.

1 · Normal transactions are never intercepted Lazarus only reads public on-chain data. Your wallet is untouched. Your existing transactions route exactly as they always have.
2 · Confirmers earn nothing from petitions they vote on Enforced in executePetition(). A Confirmer who voted on a petition is excluded from receiving its funds. Byte-for-byte, at the contract level.
3 · Time alone never triggers a release Even a Protection Score of zero is not sufficient. A Custodian must file a petition, Confirmers must vote, and a 72-hour challenge window must elapse.
4 · The owner can always resurrect One recordActivity() call from the owner cancels every open petition and restores the Protection Score. There is no window where the owner is locked out.

How it works

  1. You register a contract. One Lazarus contract per wallet owner. You set your baseline days (7–180) and assign roles.
  2. An indexer watches your wallet. Any on-chain activity (incoming, outgoing, signatures) counts as a heartbeat and pings recordActivity().
  3. If your wallet goes silent beyond the baseline, your Protection Score drops. At 70 it enters a warning state. Below 70, a Custodian can file a petition.
  4. Confirmers verify and vote (blind commit-reveal). Two approvals are required, revealed only after the reveal window, readable only during and after the 72-hour challenge window.
  5. You can resurrect at any point. One signed tx cancels everything and restores your score.
  6. If you don't, funds release to the specified Custodian minus a 0.2% protocol fee. The Confirmer who voted is excluded from receiving any of it.

Roles

Three distinct roles. Each is intentionally narrow. No one can play two simultaneously. The contract enforces it.

Confirmer

Verifies a petition is legitimate via blind commit-reveal voting. Cannot receive funds from any petition they voted on. Two approvals needed to advance.

Custodian

Files petitions and receives funds on approval. Cannot vote. Cannot simultaneously hold the Confirmer role.

Watcher

Neutral observer with veto power. Two Watcher vetoes halt any petition permanently. Cannot receive funds.

Role separation is contract-level

In grantRole(), assigning a Confirmer role to someone who already holds Custodian (or vice versa) reverts with LAZ: role conflict. This is the core anti-collusion mechanism. The one who votes can never be the one who profits.

Invitations, not assignments

You don't directly assign roles. You invite. An invite creates an Invitation with InviteStatus.Pending; the invitee must accept with their own signature. This prevents accidentally "assigning" someone to a role they didn't consent to, and gives the role-holder an on-chain record of their commitment.

Protection Score

A number between 0 and 100 representing the health of your continuity posture. Returned by protectionScore() on the contract.

ScoreStateWhat's possible
100HealthyRecent activity. Nothing escalates.
70–99QuietBelow baseline. Monitoring.
40–69WarningCustodians can file petitions.
20–39SilentInstruction timelock reduces.
0–19Likely incapacitatedFull Incapacitation petitions allowed.
40 FLOOR INVARIANT

Time alone cannot drop your score below 40. Reaching scores below that requires confirmed external signals (escalation responses, role-network health) combined with silence. This is enforced in the contract's vitalityScore().

Petition lifecycle

Every fund release goes through this six-phase process. There are no shortcuts and no override paths.

  1. File. A Custodian calls filePetition(type, asset, amount, ipfs). Requires score ≤ 69 and at least two active Confirmers. Snapshots the Confirmer list so later role changes don't affect this petition.
  2. Commit phase. Each Confirmer submits a commitmentHash = keccak256(approve, salt) without revealing their vote. 48-hour window.
  3. Reveal phase. Confirmers reveal (approve, salt). The contract verifies the hash matches. Anyone who didn't commit cannot reveal. 48-hour window.
  4. Challenge window. 72 hours where the owner can cancel (resurrect) or Watchers can veto. Vote counts become public.
  5. Execute. Any non-voting Custodian can call executePetition(). Requires ≥2 approvals and expired challenge window. Funds release minus the 0.2% fee.
  6. Terminal. The petition enters one of: Executed, Cancelled, Vetoed, Rejected, or Expired.

Why commit-reveal?

Blind voting removes coordination pressure. A Confirmer doesn't know how others voted until after they've committed. This protects against social dynamics where one loud Confirmer's early "yes" cascades into a rubber-stamp. A real failure mode for naive voting systems.

Petition types & caps

TypeCap (% of balance)Score required
General Hardship15%≤ 69
Medical Emergency40%≤ 69
Legal Emergency35%≤ 69
Dependent Care30%≤ 69
Full Incapacitation100%≤ 19
Final Transition100%confirmed death

Plus a 25% aggregate cap across non-emergency releases in any rolling 90-day window.

Silence Windows

Going off-grid on purpose? A Silence Window tells the protocol to pause escalation. Your Protection Score reports a healthy 95 while the window is active, even if your wallet produces zero activity.

ModeTypical use
TravelTrip with limited connectivity. Custodians see an expected return date.
MedicalHospital stay. Custodians on standby but no auto-escalation.
Legal HoldLitigation / investigation. Everything paused, nothing escalates.
StealthDeliberately dark for operational reasons. Confirmers only.
Personal LeaveExtended quiet by choice.

Maximum window length: 1 year. The owner can clear the window at any time with clearSilenceWindow(). That doubles as a heartbeat.

Duress protocol

What if the attacker is the owner. Forced to sign? Lazarus includes a duress channel.

recordActivityUnderDuress() looks like a normal heartbeat from outside. Internally it flips the duressActive flag, which locks the owner out of unilateral petition cancellations. While duress is active:

  • The owner's cancelPetition() alone is rejected.
  • Clearing the duress flag requires two Watcher co-signatures, given out-of-band after they've verified the owner is safe.
  • External observers see nothing different. No public "under duress" signal that could escalate the situation.
WHY THIS MATTERS

A wrench-attack scenario (someone forces you to sign) would otherwise mean a single signed transaction drains your protocol. The duress channel means the attacker can't un-lock without coordinated co-signatures from people physically separated from the owner.

Security guarantees

  • Reentrancy-guarded on executePetition(). Releases are single-entry.
  • No unbounded loops in release paths. Confirmer list is snapshotted at petition filing; later changes don't alter execution cost.
  • Two-step ownership transfer. initiateOwnershipTransfer + acceptOwnership. No accidental single-sig ownership handover.
  • No-Release Freeze. A one-way switch that permanently disables all Custodian releases. For owners who want the monitoring without the recovery path. After engagement, nothing releases funds except the owner's own signature.
  • Death fee cap. $2,500 max via Chainlink oracle (fallback to flat rate if feed is stale). Prevents abusive escalation fees on large estates.
  • Ownership separation enforced. In grantRole(), Confirmer ↔ Custodian conflicts revert.
  • Expired petitions auto-state. Petitions that sit in any phase beyond their deadline become Expired, cannot execute retroactively.

Fees

The only thing worth saying publicly about Lazarus's economics: you should never feel a fee while you're alive and active. Monitoring is free, forever. The only fee a user ever pays fires once, on the day the protocol actually protects them.

What a user pays

EventFeeWhen
Monitoring$0Forever. No subscription, no setup, no monthly skim.
Emergency partial release0.40%Once, deducted from the released amount only.
Full incapacitation release0.40%Once, deducted from the released amount only.
Final transition (death-confirmed)0.20%, capped at $2,500Once. Cap protects large estates from disproportionate fees.

That's it. There is no other path through which a normal user pays Lazarus a cent. Not on swaps, not on transfers, not on idle balances, not on any normal wallet activity.

What Lazarus will never charge

  • Monthly subscriptions, "pro" tiers, or feature gates.
  • Setup or onboarding fees.
  • Fees on normal transactions. Your wallet's normal flow is never touched.
  • AUM management fees on idle balances.
  • Anything a user might notice as a recurring or visible charge.

How the protocol funds itself

Briefly: through structurally separate revenue lines that don't touch user wallets. Release fees flow into a protocol-owned treasury that earns its own income. Platforms that integrate Lazarus pay licensing fees. Institutional clients buy custom coverage contracts. Confirmers and Watchers earn flat per-event stipends drawn from the treasury, never from the user's released amount.

The litmus test we hold ourselves to: if a normal person setting up Lazarus for their family would notice a fee, a tier, an upsell, or a commercial surface in their experience. It's wrong. Surface to user = $0.

Multichain

Lazarus is chain-agnostic. Each user's contract is deployed to the chain of their choice. The wallet you already use. Currently configured:

ChainChain IDStatus
Base Sepolia84532Primary testnet
Base8453Mainnet-ready
Optimism Sepolia11155420Supported
Arbitrum Sepolia421614Supported
Ethereum Sepolia11155111Supported

The app's chain picker auto-detects your wallet's current network. Unsupported chains show as "coming soon". You can still explore the app in simulation mode.

Future expansion is a config addition, not a code rewrite: new chains are declared in js/contract.js's CHAINS map.

Contract reference

Core read methods:

function owner() view returns (address)
function protectionScore() view returns (uint256)
function daysSinceActivity() view returns (uint256)
function customBaselineDays() view returns (uint256)
function activeConfirmers() view returns (address[])
function activeCustodians() view returns (address[])
function activeWatchers() view returns (address[])
function petitionCount() view returns (uint256)
function petitions(uint256) view returns (Petition)
function noReleaseFreezeEngaged() view returns (bool)

Core write methods:

// Owner
function recordActivity()
function setBaselineDays(uint256)
function setSilenceWindow(SilenceReason, uint256, string)
function clearSilenceWindow()
function inviteRole(address, Role, string) returns (uint256)
function revokeRole(address)
function cancelPetition(uint256)
function engageNoReleaseFreeze()

// Custodian
function filePetition(PetitionType, address, uint256, string) returns (uint256)
function executePetition(uint256)

// Confirmer
function commitVote(uint256, bytes32)
function revealVote(uint256, bool, bytes32)

// Watcher
function watcherVeto(uint256)

// Anyone
function acceptInvite(uint256)
function declineInvite(uint256)

See contracts/Lazarus.sol for the full source (1,028 lines, 27 passing tests).

Glossary

BaselineThe number of days of wallet inactivity before your Protection Score starts dropping. User-configurable 7–180.
Challenge WindowThe 72-hour window after a petition's reveal phase where the owner can cancel or Watchers can veto.
Commit-RevealVoting scheme where votes are hashed and submitted privately (commit), then revealed after the deadline. Prevents vote cascading.
CouncilInformal name for the aggregate of Confirmers + Custodians + Watchers you've designated.
DuressA state where the owner is being coerced. Entered via recordActivityUnderDuress(), exited only with two Watcher co-signatures.
HeartbeatAny on-chain activity recorded on the contract's watched wallet. Keeps the score at 100.
Lazarus PoolThe protocol fee recipient. Set at deployment. Receives 0.2% of every release.
PetitionA Custodian-initiated request to release funds. Must complete the full lifecycle to execute.
Protection Score0–100 value representing the health of your continuity posture. Public, read-only.
ResurrectionThe owner's ability to cancel every open petition and restore the Protection Score with a single transaction.
Silence WindowAn owner-declared period of inactivity that pauses escalation (Travel / Medical / Legal / Stealth / Personal Leave).
Lazarus Protocol · Documentation · v0.1
Landing · Open app · GitHub