# Introduction

A decentralized framework for digital legacy planning: give your crypto a survivable plan, without trusting a centralized custodian.

Crypto security has matured. Smart contracts get audited, wallets get hardware-hardened, users get more discerning. Legacy planning for crypto has not kept up. Most "solutions" still rely on centralized custodians, legal instruments designed for fiat assets, or a scrap of paper shoved in a safe that nobody remembers where.

**10102 Computing Legacy** is a small, auditable set of Ethereum smart contracts (plus a thin app on top) that lets you define the rules for how your on-chain assets pass on, and executes them automatically when those rules are met. No custody. No subscription required for the core flows. No middleman the plan depends on.

The protocol has been live on Ethereum mainnet since **October 2024** and independently audited twice ([RockSolid Security, report January 2025](https://github.com/10102-io/computing-sc/blob/main/Security_Review_Computing_Will.pdf); [CDSecurity, report October 2025](https://github.com/CDSecurity/audits)). Development started in June 2024; the original contracts repository is [archived and public](https://github.com/10102-labs/computing-sc-og), preserved when the project moved to the `10102-io` GitHub organization in January 2026.

## What it does

* **Transfer legacy**: split specific assets across named Ethereum addresses when you've been inactive for a configurable window. Created from your connected EOA wallet (MetaMask, Ledger, Trezor, Rainbow, Coinbase Wallet, WalletConnect-compatible mobile wallets).
* **Multisig legacy**: hand over control of an existing Safe to your beneficiaries by adding them as co-signers when the inactivity window elapses. The Safe itself, and everything it holds or governs, *is* the legacy.
* **Timelock**: a time-based security layer for your own funds: lock assets until a specific date (protecting against coercion, wrench attacks, or your own impulses). Three flavors: Timelock, Soft Timelock, Beneficiary Timelock. For sealed gifts with a claim link, see Heirloom.
* **Premium layer**: optional contingent beneficiaries (fallback layers), authorized watchers (read-only oversight accounts), and email reminders. All additive; the core flows work without them.

## The design principle: your plan survives us

Every feature in this app is operable directly from the Ethereum contracts: without our UI, without our servers, without our company. That's not an afterthought; it's the point.

* **Contracts are verified on Etherscan**. Anyone can call them from any Ethereum interface.
* **Code and audits are public**. See [github.com/10102-io/computing-sc](https://github.com/10102-io/computing-sc) and [github.com/10102-labs/audits](https://github.com/10102-labs/audits).
* **The Legacy Claim Card is printable**. Every legacy produces a one-pager documenting the contract address, legacy ID, and activation instructions, enough for a beneficiary to claim via Etherscan even decades from now. See [Legacy Claim Card](/user-guide/legacy/legacy-claim-card).
* **Upgrades are timelocked and publicly visible**. The `DefaultProxyAdmin` for all upgradeable contracts is owned by an on-chain upgrade timelock: no implementation can change without first sitting in a public 48-hour queue that anyone can watch. See [Upgrade Policy](/architecture/upgrade-policy).

If our website goes down tomorrow, your legacy still works. That's the entire bet.

## Built on Ethereum, with the ecosystem

* **Ethereum**: the settlement layer. Mainnet + Sepolia for testing.
* **Safe**: wallet infrastructure for all multisig-based flows (Safe Guard + Safe Module patterns).
* **The Graph**: subgraphs index legacy contracts, token balances, and activity, so the UI stays fast without trusting any single RPC.
* **Mailjet**: transactional email delivery for the off-chain reminder worker. Email scheduling, encryption, and delivery live entirely off-chain; activation itself never depends on it.

## Wallet support

Any wallet that speaks a standard Ethereum connector works: **MetaMask**, **WalletConnect** (covering most mobile wallets), **Coinbase Wallet** (extension, mobile, and passkey-based smart wallets), **Ledger** + **Trezor** (direct or via Ledger Live / Trezor Suite), **Rainbow**, and others. ENS names render everywhere addresses do.

## Mainnet and Sepolia

You can switch networks inside the app. **Sepolia** is the public testnet: identical flow, free test ETH, activation windows configurable in minutes instead of days so you can exercise the whole cycle in a short session. **Mainnet** is production: real assets, real value, real consequences.

## Where to go next

* New users → start with the [User Guide](/user-guide), in particular [Concepts](/user-guide/concepts) for the vocabulary.
* Technical readers → [Architecture](/architecture) explains the contracts, the subgraph layer, and the email infrastructure.
* Engineers / contributors → [Design & Engineering Notes](/dev) covers the "why" behind the harder design decisions.
* Agents and integrators → [Agents & Builders](/agents-and-builders); recommending 10102 to an audience or client book → [Partner Program](/partners).
* Introducing 10102 to a partner or a desk → [About](/about), one page with status, links and contact.


# About

One page on 10102 Computing Legacy: what it is, what is live, how it is built, how it earns, and how to reach us.

**10102 Computing Legacy** is a set of audited Ethereum smart contracts, with a thin web app on top, that lets people decide how their on-chain assets pass on and lock funds until a date they choose. Assets stay in the owner's own wallet until the rules they set are met. There is no custody, and every feature works directly from the contracts if the app or the company disappears.

Development started in June 2024. Live on Ethereum mainnet since October 2024, under the `10102-io` GitHub organization since January 2026.

## Status

|          |                                                                                                                                                                                                           |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Network  | Ethereum mainnet (production) and Sepolia (public testnet, same flows)                                                                                                                                    |
| Custody  | None. Funds stay in the user's wallet or Safe until activation or unlock                                                                                                                                  |
| Audits   | RockSolid Security (January 2025), CDSecurity (October 2025). [Reports](https://github.com/10102-labs/audits)                                                                                             |
| Code     | Contracts are open source and verified on Etherscan. [Source](https://github.com/10102-io/computing-sc), [deployed addresses](https://github.com/10102-io/computing-sc/blob/main/contract-addresses.json) |
| Upgrades | Every contract upgrade waits in a public 48-hour on-chain queue. [Upgrade Policy](/architecture/upgrade-policy)                                                                                           |
| Fees     | Core flows are free; users pay network gas only                                                                                                                                                           |

## What is live

* **Legacy**: assets split across named addresses, or a Safe handed to co-signers, when the owner has been inactive for a window they set. Optional backup beneficiaries, read-only watchers, email reminders and automatic renewal.
* **Timelock**: ETH or tokens locked until a date, for the owner or for someone else. Includes a soft lock with a short unlock delay.
* **Heirloom**: a sealed gift the recipient opens on a chosen date, delivered by a link and a printable paper key. Claiming costs the recipient nothing; the network fee is covered.
* **Guardian**: an in-app assistant, with private inference through Venice, that explains the product and sets up flows on request.
* **For agents and builders**: a public MCP server and free read endpoints. See [Agents & Builders](/agents-and-builders).

## How it earns

Premium, paid on-chain in ETH, USDC or USDT: $99 per year or $399 once. And a small fee when assets are delivered (0.25% today), fixed into each contract when it is created and shown before you confirm; never to set one up or keep it. Partners who introduce clients or an audience earn a share of the Premium purchases they bring, reconciled against public transactions. See the [Partner Program](/partners).

## How it is built

Ethereum for settlement, [Safe](https://safe.global) for all multisig flows, [The Graph](https://thegraph.com) for indexing, [Venice](https://venice.ai) for Guardian's inference, Mailjet for reminder emails. Reminders and emails run off-chain and are optional; activation never depends on them.

## Roadmap and limits

What we are working on, evaluating and deferring is public: [Roadmap](/dev/backlog). The design notes state the limits out loud, for example how inactivity is detected and what the worst case looks like: [Design & Engineering Notes](/dev).

## Links and contact

* App: [app.10102.io](https://app.10102.io). Add `?network=testnet` to try it on Sepolia.
* Docs: [docs.10102.io](https://docs.10102.io). Site: [10102.io](https://10102.io).
* Partnerships and general questions: <info@10102.io>
* Security disclosures: <security@10102.io>


# User Guide

How to use 10102 Computing Legacy, from connecting your wallet to creating legacies, timelocks, and managing them over time.

This guide covers every user-facing flow in the app. Pages are ordered roughly the way a new user would encounter them. Start at the top if this is your first visit, or jump to whatever section matches what you're trying to do.

Unfamiliar with the vocabulary? Skim [Concepts](/user-guide/concepts) first.

## Sections

### Getting started

* [Authentication](/user-guide/authentication): connecting and disconnecting a wallet.
* [Concepts](/user-guide/concepts): short glossary of the terms used throughout this guide.
* [Quick Actions](/user-guide/quick-actions): shortcuts from the home page that pre-fill common setups.

### Legacy

* [Legacy](/user-guide/legacy): overview of Transfer vs. Multisig legacies.
* [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract).
* [Legacy Contract Details](/user-guide/legacy/legacy-contract-details).
* [Edit or Delete a Legacy Contract](/user-guide/legacy/edit-or-delete-a-legacy-contract).
* [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds): the beneficiary's side.
* [Legacy Claim Card](/user-guide/legacy/legacy-claim-card): the printable safety net.

### Premium features

* [Premium Features](/user-guide/premium-features): subscription model and what it unlocks.
* [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries).
* [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers).
* [Configure Email Reminders](/user-guide/premium-features/configure-email-reminders).

### Timelock

* [Timelock](/user-guide/timelock): overview of Timelock, Soft Timelock, Beneficiary Timelock.
* [Heirloom (sealed gifts)](/user-guide/heirloom): seal ETH or USDC as a gift that opens on a chosen date.
* [Using Timelock](/user-guide/timelock/using-timelock): create, unlock, and claim for all three flavors.

## A note on philosophy

10102 is deliberately built so that your plan survives us. Every feature in this guide can be operated directly from the Ethereum contracts, without our UI. That's why [Legacy Claim Card](/user-guide/legacy/legacy-claim-card) exists, and why [Architecture](/architecture) is published alongside the user guide. If something about our UI is confusing or our servers are down, the plan doesn't stop working. That's the point.


# Authentication

Connect and disconnect wallets. We support every common Ethereum wallet via standard connectors: WalletConnect, Ledger, Trezor, MetaMask, and more.

10102 Computing Legacy never takes custody of your funds and never asks you to create a 10102-specific account. Your wallet *is* your identity. Connecting a wallet is a read-only signature handshake; signing in does not move anything.

## Supported wallets

Any wallet that speaks one of the standard Ethereum connector protocols works. That includes, but isn't limited to:

* **MetaMask**: browser extension or mobile app.
* **WalletConnect**: protocol covering most mobile wallets (Rainbow, Trust Wallet, 1inch Wallet, imToken, …).
* **Coinbase Wallet**: extension, mobile, and smart wallets (passkeys).
* **Hardware wallets**: Ledger and Trezor, either directly over USB or through their respective bridge apps (Ledger Live, Trezor Suite).
* **Rainbow**: extension and mobile.

If your wallet exposes a standard provider, it'll show up in the Connect modal automatically. The app treats every connector identically once connected; there's no special case for any brand.

## Connect

1. Click **Connect Wallet** at the top right of the app.
2. Choose your wallet from the modal.
3. Complete the connection flow in your wallet's UI:
   * Extensions open a popup asking for approval.
   * Mobile wallets show a QR code; scan it in the wallet app.
   * Hardware wallets may require you to unlock the device and open the Ethereum app.
4. Back in 10102, you'll see your wallet address (and any ENS name it resolves to) at the top right.

{% hint style="info" %}
**Don't have a wallet installed?** The Connect modal links out to each wallet's official install page. We never redirect through third-party download sites, only to the wallet vendors themselves.
{% endhint %}

## Switch wallets

Click your wallet address in the top right, then **Disconnect**. Reconnect with a different wallet via the standard flow.

Some wallets (MetaMask, most extensions) also let you switch accounts inside the wallet itself without disconnecting; the app picks up the change automatically.

## Disconnect

Click your wallet address in the top right, then **Disconnect**. You'll be returned to the Connect screen. No data is persisted client-side across a disconnect, other than standard browser storage (theme, UI preferences).

## Networks

* **Mainnet** (Ethereum mainnet) is the canonical deployment.
* **Sepolia** testnet is available for kicking the tires without real funds. It's useful for trying a flow end-to-end (creation, activation, claim) with throwaway ETH.

Switch networks in your wallet; the app follows. There is full feature parity between mainnet and Sepolia: everything you can do on one, you can do on the other.

If the default Ethereum node providers are slow for you, or you'd rather the app read chain state through your own endpoint, see [Bring your own RPC](/user-guide/bring-your-own-rpc).

## Signing vs. sending

Two different things happen with your wallet while you use the app:

* **Signing a message**: a pure cryptographic signature; doesn't send a transaction, doesn't cost gas, doesn't touch the blockchain. Used rarely, mostly for opt-in features that need to prove you control an address.
* **Sending a transaction**: a real Ethereum transaction that costs gas and changes on-chain state. Used for creating/editing/deleting legacies and timelocks, approvals, activations, and claims.

Your wallet clearly distinguishes the two in its prompts. If you're ever uncertain about a wallet prompt, the details page of whatever you're working on will describe the transaction you're expected to sign next; compare it against what your wallet shows.

## See also

* [Concepts](/user-guide/concepts)
* [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract)


# Concepts

Short definitions of the vocabulary that shows up throughout 10102 Computing Legacy. Skim this first; come back when a term doesn't click.

## Legacy type

How your assets pass to your beneficiaries. Two shapes:

* **Transfer legacy**: distributes specific assets to specific addresses when activated, proportional to allocations you set. Created from your connected EOA wallet.
* **Multisig legacy**: hands over your existing Safe by adding your beneficiaries as co-signers on activation. The Safe itself (and everything it holds, stakes, or governs) is the legacy.

## Activation trigger

The condition that makes a legacy claimable. Today there's one trigger: **inactivity**, the time since your last activity the legacy can see (what counts differs by wallet type; see [Heartbeat](#heartbeat)). Measured in days. When the window elapses, any beneficiary can activate.

## Heartbeat

Any action that proves you're still around and resets the activation timer. What counts depends on your wallet type:

* **Safe legacies**: every Safe transaction counts automatically (the Safe Guard records it), so normal usage keeps the legacy fresh.
* **EOA legacies**: interactions with your legacy count (edits, deposits, withdrawals, or the dedicated heartbeat action on the details page). Generic wallet activity elsewhere (a send, a swap) does **not** reset the timer by itself, unless you enable [Auto-renew](#auto-renew-eoa-legacies).

If you don't have another qualifying action to make, the details page has a dedicated heartbeat action that resets the timer in a single transaction.

## Auto-renew (EOA legacies)

An optional Premium feature, off by default, that you enable per legacy. When on, an attestor service watches your wallet's public on-chain activity (its transaction count) and renews your inactivity timer for you when you've been active near the deadline: no email, no click, no gas from you. Every safety bound is enforced on-chain: renewals only work near the deadline, stop 365 days after your last real check-in, and can never make a legacy claimable earlier. See [Automatic Renewal](/user-guide/premium-features/automatic-renewal) for the guide, and [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew) for the full trust model.

## Creator vs. signer (Safe legacies)

When a Safe creates a legacy, it's the Safe (not an individual) that owns it on-chain. But **the single wallet that submitted the creation transaction** is tagged as the **creator**. On-chain settings (beneficiaries, trigger, allocations) can be changed by any Safe signer at the Safe's threshold. **Off-chain settings** (email reminders, watchers) can only be changed by the creator. This asymmetry is documented inline on the relevant pages.

## Storage token

A substitute for ETH inside the legacy or timelock, because native ETH can't be approved like an ERC-20. When you want to include ETH, you swap it through a built-in route into a supported storage token (WETH, a liquid staking token, etc.) and approve that token instead. You always see the available list in the app.

## CREATE2

The deterministic contract-deployment opcode. We use it so your legacy contract's final address is known *before you sign the deploy transaction*. You can verify it in the app, and beneficiaries can find the contract even if our UI is unavailable. See also [Legacy Claim Card](/user-guide/legacy/legacy-claim-card).

## Safe threshold

The minimum number of Safe signers required to execute a transaction (e.g. 2 of 3). Every on-chain change to a Safe-backed legacy is a Safe transaction and respects your Safe's threshold. You can finalize signatures inside our app or on [app.safe.global](https://app.safe.global); either works.

## Finalizing

When a Safe transaction has collected enough signatures but hasn't executed yet, we call its state *needs finalizing*. Any signer can finalize by paying gas and broadcasting the transaction. Until it's finalized, the change isn't live.

## Watchers

Read-only accounts a Premium user can authorize to view selected legacies under **My Watchlist**. Used for estate lawyers, family oversight, or personal dashboards across wallets. Watchers have one of two visibility levels; see [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers).

## Contingent beneficiaries

Optional Premium layers. If the primary beneficiaries don't claim within a configurable window after activation, a second-line beneficiary becomes eligible. Same thing for a third-line after a further window. Designed to prevent assets from getting stuck when someone loses keys or is unreachable.

## Legacy Claim Card

A printable one-page summary with the minimum information your beneficiaries need to claim via any Ethereum interface, not just our UI. Contains the legacy ID and contract address; intentionally *excludes* the owner's address for privacy. See [Legacy Claim Card](/user-guide/legacy/legacy-claim-card).

## Timelock

A self-directed time-based lock on your own assets. Three flavors:

* **Timelock**: locked until a date; then you reclaim.
* **Soft timelock**: locked indefinitely; a waiting period starts when *you* initiate an unlock.
* **Beneficiary timelock**: locked until a date; then a specified recipient claims. Heirloom wraps this type into a designed gift experience with a claim link and free claiming.

See [Timelock](/user-guide/timelock).

## Premium subscription

Optional, time-bound access model (like ENS registrations). Pay upfront in ETH, USDC, or USDT to unlock contingent beneficiaries, watchers, and email reminders for a chosen period. Free users retain full access to legacy creation, editing, and claims.


# Quick Actions

Opinionated shortcuts on the home page that pre-fill a legacy or timelock for a specific goal. All of them drop into the standard flows, so you can tweak anything before signing.

Quick Actions are prominent buttons on the home page labelled by *what you want to accomplish*, not by product feature. Each one routes you into the relevant creation flow with sensible defaults so you don't have to compose the settings yourself.

Use them as training wheels, or as actual product: they're not a cut-down flow, just a pre-configured one. Everything is editable before you sign the transaction.

{% hint style="info" %}
Quick Actions only pre-fill settings. They don't change what gets deployed on-chain. The result is indistinguishable from a hand-configured legacy or timelock of the same type.
{% endhint %}

## Available actions

### Pass my assets to a loved one

Pre-fills a **Transfer legacy** with your connected wallet as the owner and a single beneficiary at 100% allocation. Takes you to the configure screen to add the beneficiary's address and pick which assets to include.

Use when: you want a straightforward one-person legacy without thinking about allocations.

### Split my assets among several people

Pre-fills a **Transfer legacy** with allocation inputs for multiple beneficiaries. You enter the addresses and percentages.

Use when: you know this will be a multi-beneficiary setup and you'd rather start from a split-ready screen.

### Schedule a future gift (to a loved one)

Opens [Heirloom](/user-guide/heirloom): seal ETH or USDC as a gift that opens on a chosen date, with occasion designs, printable sheets, and free claiming for the recipient. (Deep links and agent tools that reference this action land on the Heirloom page.)

Use when: you want scheduled delivery to a loved one on a specific date, like a child's milestone, a wedding, or planned giving.

### Protect all my funds (for a waiting period)

Pre-fills a **Soft Timelock**: locks your chosen assets indefinitely; when *you* want them back, you initiate an unlock and a configurable waiting period begins. The window is measured in days.

Use when: you want anti-coercion protection, so compromised keys or a wrench attack can't immediately drain the locked balance.

### Designate future signers for my Safe

Pre-fills a **Multisig legacy** configuration. Because this flow needs to know *which* Safe you're targeting, you're first taken to the Safe verification step; once a Safe address is confirmed, the rest of the configure screen is pre-filled to highlight the signer-designation use case.

Use when: your Safe is your long-term vault and you want other people (family, a trusted proxy) to become co-signers if you go quiet.

## Gotchas

* **Quick Action ≠ skipping asset permissions.** Including assets still works exactly like the standard create: you pick tokens in the configure screen and the permission rides the single create transaction. See [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract) for what your wallet will show.
* **The Multisig quick action requires a Safe.** Don't click it from an EOA-only context; you'll get routed to the Safe check. If you don't have a Safe, create one at [app.safe.global](https://app.safe.global) first.
* **Nothing is irreversible before signing.** You can swap types (e.g. change Transfer to Multisig), change beneficiaries, change allocations. Quick Actions are defaults, not locks.

## See also

* [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract): the full creation flow that Quick Actions drop into.
* [Using Timelock](/user-guide/timelock/using-timelock): details on the three timelock flavors.
* [Concepts](/user-guide/concepts): vocabulary reference.


# Bring your own RPC

Route the app's Ethereum reads through your own RPC endpoint instead of the default providers. Useful when the defaults are throttled, when you want privacy from third-party node operators, or when yo

Every action in 10102 Computing Legacy that reads on-chain state (checking a legacy's status, listing beneficiaries, verifying ownership, etc.) goes through an Ethereum JSON-RPC endpoint. By default the app rotates through a list of providers we configure, so a single provider being slow or rate-limited doesn't take the app down.

If you have your own node, a paid Alchemy/Infura/drpc key, or simply prefer not to depend on the providers we ship, you can point the app at your endpoint instead.

## How it works

The app supports the draft [dAppSpec](https://ethereum-magicians.org/t/new-erc-best-practices-for-dapps-dappspec/24407) query-parameter convention:

```
?ds-rpc-<chainId>=<url-encoded-rpc-url>
```

When present, the endpoint you supply is used for that chain **with higher priority than anything we configure**. Any provider throttling on our side is bypassed entirely.

The override is also remembered across reloads (saved to your browser's local storage for this origin), so you only have to paste the URL once.

## Examples

### Mainnet

Append to any page URL:

```
?ds-rpc-1=https%3A%2F%2Feth-mainnet.g.alchemy.com%2Fv2%2FYOUR_KEY
```

or, with a self-hosted node:

```
?ds-rpc-1=https%3A%2F%2Frpc.mynode.example%2F
```

### Sepolia (testnet)

```
?ds-rpc-11155111=https%3A%2F%2Fsepolia.infura.io%2Fv3%2FYOUR_KEY
```

### Multiple chains at once

You can override both chains in the same URL:

```
?ds-rpc-1=https%3A%2F%2Fmainnet.example%2F&ds-rpc-11155111=https%3A%2F%2Fsepolia.example%2F
```

## Clearing a saved override

Either:

* Navigate to any page with an **empty** override value, which resets the saved endpoint:

  ```
  ?ds-rpc-1=
  ```
* Or clear your browser's site data for the app domain. Both remove the persisted override; the app will fall back to the default providers on the next load.

## Automatic eviction on repeated failure

If the override endpoint fails several requests in a row at the network level (DNS failure, timeout, connection refused, HTTP error), the app evicts it automatically and falls back to the defaults for the rest of the session. You'll see a one-line warning in the console like:

```
[rpc] chain 1: user-override evicted after 5 consecutive failures (was: https://…). Falling back to the default providers.
```

Eviction is triggered strictly by **transport-level** failures. A working node that responds with a valid JSON-RPC error (for example, the node saying "that method is not supported") does **not** count toward eviction, because that means the node itself is healthy. Any successful request resets the counter, so an endpoint that's generally fine but occasionally slow won't get evicted by coincidence.

Once evicted, the app won't auto-reinstate the same endpoint. You can reconfigure one by supplying a fresh `?ds-rpc-<chainId>=` query parameter.

## Verifying the override is active

Open the browser's developer console (usually **F12** → Console tab). When an override is in effect, you'll see a line like:

```
[rpc] chain 1: using user-override from ?ds-rpc-1= (stored for this origin)
```

After reloads (without the query parameter), the same log appears but mentions it's using the persisted value:

```
[rpc] chain 1: using persisted user-override (clear with ?ds-rpc-1=)
```

## Things to know

{% hint style="info" %}
**What this changes and what it doesn't.** The override affects **read** calls the app makes to inspect chain state. It does **not** change how your wallet connects to the network or where your wallet signs/submits transactions; that is controlled entirely by your wallet's own RPC settings. If you want your transactions to also go through your own node, set that inside your wallet (e.g. MetaMask → Settings → Networks).
{% endhint %}

{% hint style="warning" %}
**Trust the endpoint you point at.** An RPC provider can, in principle, serve inaccurate reads or link requests to your IP address. Use endpoints operated by parties you're comfortable relying on. The app only accepts `http://` and `https://` URLs; other schemes (like `javascript:` or `data:`) are rejected so the override can't be used to run code.
{% endhint %}

{% hint style="warning" %}
**If your endpoint embeds an API key, restrict it at the provider.** RPC keys you paste into the query parameter end up in the browser request (and transiently in your history, screenshots, and any link you share). This is the same exposure model every web dapp has; the fix isn't to hide the key but to lock it down at the provider. Alchemy, Infura, QuickNode all support per-key "allowed origins" restrictions; enable that so even a leaked key is useless from any domain other than yours, and ideally disable `eth_sendRawTransaction` on read-only keys. Because the app persists your override after the first paste, you only need to put the URL in the query string once, which limits the exposure window.
{% endhint %}

{% hint style="info" %}
**The override is per-browser, per-origin.** Clearing your browser data, switching browsers, or using a private-browsing window all reset the persisted override to the defaults.
{% endhint %}

## See also

* [Authentication](/user-guide/authentication): how wallets connect and submit transactions.
* [Concepts](/user-guide/concepts): what the app does with chain state it reads.


# Legacy

Legacy contracts hold the rules for how, when, and to whom your assets pass. Two shapes, Transfer and Multisig, for different legacy styles.

A **legacy contract** is a small, purpose-built Ethereum contract that sits between you and your beneficiaries. It doesn't take custody of your assets; it just holds the rules (who, how much, and under what condition) and executes them when the condition is met.

There are two shapes to choose from.

## Transfer Legacy

Designed for **asset-level transfer**: "when I've been inactive for X days, beneficiary A gets 40% of these tokens, B gets 60%".

* Works with an **EOA** (MetaMask, Ledger, Trezor, Rainbow, Coinbase Wallet…) or a **Safe**.
* Beneficiaries don't need to work together or sign anything jointly. Any one of them can activate once the window has elapsed, and distribution happens according to the pre-set allocations.
* You retain custody until activation. The contract only has the ERC-20 allowances you've explicitly approved.
* Up to 10 primary beneficiaries, each with a percentage allocation summing to 100%.
* Premium users can add up to two additional contingent layers; see [Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries).

When to pick it: you want precise control over what passes to whom, and you don't need your beneficiaries to collectively continue running a Safe.

## Multisig Legacy

Designed for **wallet-level transfer**: your **Safe** *is* the legacy, and your beneficiaries become its co-signers on activation.

* Requires an existing Safe. Create one at [app.safe.global](https://app.safe.global) first if you don't have one.
* On activation, beneficiaries are added as signers to your Safe. They then control the entire Safe, including anything it holds, stakes, governs, or is credited with (reputation, airdrop eligibility, governance positions, off-chain privileges tied to the address, etc.).
* The activation threshold for the new signers is configurable (e.g. 2-of-3 beneficiaries required to act on the Safe).
* Every on-chain change follows your Safe's existing signature threshold. You're not bypassing your Safe's security model, you're building *on top of* it.
* Allocations aren't applicable here; the Safe passes as a unit.

When to pick it: your Safe is your long-term vault, you want beneficiaries to take over the whole thing (positions and all), not just cherry-picked assets.

## Transfer vs. Multisig at a glance

|                                       | Transfer                               | Multisig                     |
| ------------------------------------- | -------------------------------------- | ---------------------------- |
| Wallet type                           | EOA                                    | Safe only                    |
| What passes                           | Specified ERC-20s + storage tokens     | The entire Safe wallet       |
| Granularity                           | Per-asset, per-beneficiary percentages | The wallet is one unit       |
| Requires beneficiaries to coordinate? | No, any one activates                  | Yes, once they're co-signers |
| Custody before activation             | Owner's wallet                         | Owner's Safe                 |

## What's next

* [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract): the full creation flow.
* [Legacy Contract Details](/user-guide/legacy/legacy-contract-details): reading and operating a legacy after it's live.
* [Edit or Delete a Legacy Contract](/user-guide/legacy/edit-or-delete-a-legacy-contract): changing the rules or tearing it down.
* [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds): the beneficiary's side.
* [Legacy Claim Card](/user-guide/legacy/legacy-claim-card): the printable safety net.


# Create a Legacy Contract

Set up a legacy contract so your assets can pass to your beneficiaries on your terms, without a middleman.

A legacy contract holds the rules for how, when, and to whom your assets pass. This page walks through creating one end-to-end.

{% hint style="info" %}
**New to the terminology?** See [Concepts](/user-guide/concepts) for short definitions of *legacy type*, *storage token*, *activation trigger*, and *claim card*.
{% endhint %}

## Pick a type

You have two choices at `Create a legacy`:

* **Transfer legacy**: splits your assets between named Ethereum addresses when activated. Created from your connected EOA wallet (MetaMask, Ledger, Trezor, …).
* **Multisig legacy**: hands over control of your existing **Safe** to your beneficiaries by adding them as co-signers once activated.

Still unsure? Start with Transfer legacy; it's the most common case and doesn't require a Safe. You can always create a Multisig legacy later.

{% hint style="success" %}
If you started from a **Quick action** on the home page, we've pre-filled the type and some settings for you. The rest of this page still applies. See [Quick Actions](/user-guide/quick-actions) for the full list.
{% endhint %}

## Create a Transfer legacy

Creating a Transfer legacy is **one transaction**. You configure everything on one screen, confirm once in your wallet, and the contract is live with its asset permissions already in place. Your wallet keeps full custody the whole time; nothing moves until activation.

### Configure

Fill in:

* **Name**: a private label. It's saved on your device only; it is never written to the blockchain, and neither are beneficiary names.
* **Beneficiaries**: up to 10 addresses. If you list only one, we auto-allocate 100%.
* **Allocations**: percentages must sum to 100%.
* **Activation trigger**: inactivity period (time since your last interaction with the legacy) before beneficiaries can claim. Days, not months.
* **Assets to include**: the ERC-20 tokens your beneficiaries will be able to claim. You pick them here, in the same form; there is no separate approval step afterwards.

Tick the terms checkbox. Your acceptance is recorded by the create transaction itself; there's no separate "sign this message" prompt.

{{screenshot: configure-legacy-eoa-step1}}

### Confirm

Click **Deploy**. Two things happen in your wallet:

1. If you included tokens, you sign one **gas-free permission message** covering all of them at once. The permission goes through [Permit2](https://github.com/Uniswap/permit2), the token-permission standard used across the Ethereum ecosystem, and names a single spender: our published, Etherscan-verified vault contract, the same address for every 10102 user. You can check it against the address in [How Legacy Creation Works](/architecture/create-flow-v2).
2. You confirm **one transaction**. It deploys your legacy contract and registers the token permissions together. The contract address is deterministic (`CREATE2`), so the address shown on screen is the address you get.

That's it: the details page opens and your legacy is live.

{% hint style="info" %}
**A possible one-time extra.** If your wallet has never used a particular token with Permit2 before (in any app), that token needs a one-time `approve(Permit2)` transaction first. The app detects this and prompts you. It's once per token per wallet, and it's shared with every other Permit2-based app you use.
{% endhint %}

{% hint style="info" %}
**What does the permission actually allow?** Nothing, until activation. Tokens stay in your wallet and remain fully spendable by you. If the legacy activates, beneficiaries receive their configured percentages of whatever is in your wallet at that time. You can revoke the permission at any point by deleting the legacy or directly in your wallet's Permit2 settings.
{% endhint %}

### Adding ETH

ETH can't be permissioned directly because it isn't an ERC-20. Use the **add ETH** action on the details page to swap it to a **supported storage token** (WETH or a liquid staking token) through a built-in swap route; the permission for the resulting token is set up as part of the same flow.

### Print a Legacy Claim Card (optional but recommended)

The app generates a one-page printable card with the minimum information your beneficiaries need to claim, even if our UI is ever unavailable. See [Legacy Claim Card](/user-guide/legacy/legacy-claim-card).

## Safe-based legacies (Multisig / Safe Transfer)

Safe-based flows work differently from the EOA flow above: creation goes through your Safe's own transaction process, so your Safe's co-signers approve it at your normal threshold.

### Create a Multisig legacy

Multisig legacy *is* your Safe: beneficiaries become co-signers on activation, taking over the wallet and any positions it holds elsewhere (staking, governance, NFTs, etc.).

1. Click **Create a legacy**, choose **Multisig legacy**.
2. Enter your Safe address. We verify it.
3. Configure:
   * Contract name, beneficiaries (addresses), activation trigger.
   * No asset allocation here; beneficiaries take over the Safe itself.
4. Your Safe signers approve the creation transaction (installs our Safe module and guard).

{{screenshot: configure-multisig-check-safe}}

{% hint style="warning" %}
The Safe must still be in active use, because Multisig legacy relies on your Safe's last outgoing transaction as a liveness signal. If you don't transact from the Safe at least once per activation window, beneficiaries can activate. Use the heartbeat action on the details page to reset the timer if you don't have another transaction to send.
{% endhint %}

## Premium: Additional contingent beneficiaries

If you subscribe to Premium, you can configure up to two additional contingent layers: fallbacks if a primary beneficiary can't claim (lost keys, deceased, etc.). See [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries).

## Common questions

**Does the contract hold custody of my assets?** No, for Transfer legacy. Your tokens never leave your wallet before activation. The create transaction only grants a claim permission, and only your own legacy contract can ever use it.

**What happens if I move my included tokens?** Nothing breaks. The permission is a promise, not a lock: beneficiaries can only claim what's actually in your wallet on activation. Spend, stake, or move your tokens as usual.

**Can I add ETH directly to the legacy?** Not for Transfer legacies; ETH must be swapped to a storage token first. This is by design: the legacy contract works through ERC-20 token permissions, which ETH doesn't have.

**Can I include more tokens later?** Yes: use the include action on the details page. Adding a token after creation is a small on-chain transaction.

**Where are the names stored?** The legacy's name and your beneficiaries' names live on your device, not on the blockchain. On-chain there are only addresses, percentages, and the trigger; see [How Legacy Creation Works](/architecture/create-flow-v2).

**Can I change the beneficiaries later?** Yes; see [Edit or Delete a Legacy Contract](/user-guide/legacy/edit-or-delete-a-legacy-contract).

## What's next

* [Legacy Contract Details](/user-guide/legacy/legacy-contract-details): what the details view shows, and how to interpret it.
* [Edit or Delete a Legacy Contract](/user-guide/legacy/edit-or-delete-a-legacy-contract): updating allocations, revoking permissions, or tearing everything down.
* [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries): Premium fallback layers.
* [How Legacy Creation Works](/architecture/create-flow-v2): the architecture behind the one-transaction create, for the curious.


# Legacy Contract Details

The details page is where you operate a legacy day-to-day: check status, add or remove assets, reset the activation timer, or tear it down.

After creating a legacy, clicking it from the home page opens its details view. This is also where beneficiaries land when they open a legacy left to them.

## Sections of the details page

### Header

* **Name** and **Legacy ID**: the on-chain identifier, useful for claiming via Etherscan and for cross-referencing with emails.
* **Contract address**: where allocations, approvals, and native token deposits live.
* **Status**: see [Status values](#status-values) below.
* **Creator** (Safe legacies only): the wallet that originally submitted the creation transaction. Relevant because notification settings (watchers, reminders) are creator-only; see the callout on the affected settings pages.

### Activity and trigger

* **Last activity**: the most recent activity the legacy knows about. For Safe legacies that's the Safe's last transaction (every Safe transaction counts). For EOA legacies it's your last interaction with the legacy itself; see [The owner's view](#on-an-eoa-legacy) below.
* **Activation trigger**: the inactivity threshold you configured. The details page shows how much of the window has elapsed.
* **Heartbeat action**: resets the trigger timer in a single transaction when you don't have another qualifying action to make naturally. On a Safe legacy, any Safe transaction already counts; on an EOA legacy, only interactions with the legacy count (unless you enable [auto-renew](/user-guide/concepts#auto-renew-eoa-legacies)), so the dedicated action is the standard way to check in.

### Assets (Transfer legacies)

Shows the ERC-20s approved to the legacy contract, their current allowances, and the per-beneficiary distribution that would happen on activation.

* Only tokens with a non-zero approved amount are shown, keeping the view focused on what actually moves on activation. To see the full list of held tokens with zero allowance, enter edit mode.
* ETH is not shown in the assets table: ETH can't be approved as an ERC-20, so it's represented by whatever storage token (WETH, a liquid staking token, …) you swapped into. The home page shows your wallet's current ETH balance separately, independent of the legacy.

### Beneficiaries

The configured addresses, their allocations (for Transfer legacies), and, for Safe legacies, the role they'll take on activation.

### Danger zone

* **Edit contract**: adjust beneficiaries, allocations, trigger window, or asset approvals.
* **Delete contract**: tear the legacy down and return any native tokens; see [Edit or Delete](/user-guide/legacy/edit-or-delete-a-legacy-contract).

## Status values

| Status                           | Meaning                                                                                                             | Typical next step                                                                            |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| **Needs finalizing** (Safe only) | A Safe transaction has been submitted but not enough signers have finalized it                                      | Collect the remaining signatures in our app or on [app.safe.global](https://app.safe.global) |
| **Live**                         | The legacy is active; allocations are in effect; the activation trigger is counting down                            | Include assets, manage watchers, etc.                                                        |
| **Activated**                    | A beneficiary has successfully activated the legacy and distribution has started (Transfer) or completed (Multisig) | For Transfer with >100 transactions, keep claiming until done                                |

{% hint style="info" %}
**"Needs finalizing" threshold is inclusive.** When the number of signers who've approved equals or exceeds the Safe's threshold, the transaction is ready to finalize. (This was recently aligned with Safe's own semantics, so having *more* signatures than strictly needed no longer blocks finalization.)
{% endhint %}

## The owner's view

### On a Safe legacy

* You'll see a banner if the legacy needs finalizing. Your Safe co-signers can add signatures there, or at [app.safe.global](https://app.safe.global). Finalizing is a gas-paying transaction that any Safe signer can submit once the threshold is met.
* The heartbeat action is available to any Safe signer; the Safe's own transactions already reset the timer.
* Notification settings (watchers, reminders) are managed by the creator of the legacy, which may or may not be you. If it isn't, you'll see a "Notification settings managed by 0x…abcd" badge pointing to the creator. See [Creator vs. signer](/user-guide/concepts#creator-vs-signer-safe-legacies).

### On an EOA legacy

* No finalizing step: on-chain changes happen as soon as you sign. Simpler flow, less coordination.
* Interactions with the legacy count as heartbeats: edits, deposits, withdrawals, or the dedicated heartbeat action. Generic wallet activity elsewhere does **not** reset the timer by itself.
* If you'd rather have your wallet's general on-chain activity keep the timer fresh, enable **auto-renew** (Premium, opt-in, per legacy): an attestor service observes your wallet's public transaction count and renews for you near the deadline, within strict on-chain bounds. See [Automatic Renewal](/user-guide/premium-features/automatic-renewal).

## The beneficiary's view (Legacies for Me)

Beneficiaries see a legacy left to them on the home page under **Legacies for Me**, starting with status **Not activated**. The details page shows:

* **When they can activate**: based on the owner's last recorded activity and the activation trigger.
* **What they'd receive**: their allocation and the current list of approved assets (Transfer) or the Safe they'll take over (Multisig).
* **Activation button**: enabled once the window has elapsed. Any designated beneficiary can trigger it; distribution happens to *all* beneficiaries according to the allocations, not just the one who activated.

See [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds) for the beneficiary flow.

## Watcher and contingent-beneficiary views

* A **watcher** sees the legacy under **My Watchlist** with either full or limited visibility, depending on what the owner configured. See [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers).
* A **contingent beneficiary** sees the legacy under **My Watchlist** until their line activates, then it moves to **Legacies for Me**.

## See also

* [Edit or Delete a Legacy Contract](/user-guide/legacy/edit-or-delete-a-legacy-contract)
* [Legacy Claim Card](/user-guide/legacy/legacy-claim-card)
* [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds)


# Edit or Delete a Legacy Contract

Change allocations, add or remove beneficiaries, adjust the activation trigger, or tear a legacy down entirely. EOA changes are instant; Safe changes go through your normal Safe threshold.

Once a legacy is **Live**, the owner (or, for Safe legacies, any Safe signer) can edit or delete it at any time before it's activated.

## Editing

### What you can change

* **Name**: private label.
* **Beneficiaries**: add, remove, or replace up to 10 primary addresses.
* **Allocations**: any percentages, as long as they sum to 100%. Single-beneficiary legacies auto-allocate 100%.
* **Activation trigger**: the inactivity window (days).
* **Note to beneficiaries**: an on-chain message they'll see in the beneficiary view.
* **Approvals**: include new ERC-20s, adjust existing allowances, or remove tokens from the inclusion set.
* **Safe threshold for beneficiaries** (Multisig legacies only): how many beneficiaries must sign as the new Safe's threshold after activation.
* **Contingent layers** (Premium): add, remove, or resize the second- and third-line activation windows.

### EOA legacy

A single transaction from your wallet applies the change. No coordination needed.

{% hint style="info" %}
**Which edits reset the activation timer?** Approving, adjusting, or removing allowances and changing the note **do not** reset the timer. All other edits (beneficiaries, allocations, trigger window) do. If you want to explicitly reset without another edit, use the heartbeat action instead.
{% endhint %}

### Safe legacy

Any Safe signer can submit the edit; your Safe co-signers then finalize at the Safe's threshold. The edit shows as *Needs finalizing to update* until the threshold is met. You can finalize in our app or on [app.safe.global](https://app.safe.global).

## Deleting

Deletion is available to owners (EOA) or any Safe signer (Safe), and returns the legacy to a clean state:

* **Native tokens** held by the contract (rare: Transfer legacies rarely hold native tokens directly; this mostly applies to legacy contracts that pre-date the storage-token flow) are returned to the owner's wallet.
* **Token permissions** are dealt with according to how the legacy was created:
  * Legacies created with the current one-transaction flow use Permit2 permissions. The delete transaction itself releases them; afterwards nothing can use the permissions you signed at create. No extra prompts needed.
  * Older legacies created with direct per-token approvals get an `approve(legacy, 0)` per token; the UI runs through each one after the delete.

### EOA delete

1. Click **Delete contract** on the details page.
2. Confirm in the popup.
3. Sign one transaction to tear down the legacy. For older legacies with direct approvals, the UI then walks through revoking each one.

{% hint style="info" %}
**If the revoke loop reports a warning.** This only applies to older, direct-approval legacies: you'll only see "some token permissions couldn't be cleared" if an actual `approve(0)` transaction failed for a specific token. A legacy with no live approvals is deleted cleanly with no warning. If it happens, you can revoke the remaining permissions for the contract address from your wallet.
{% endhint %}

{% hint style="success" %}
**Post-delete refresh.** The home page and the "create legacy" eligibility check re-read directly from the chain after a delete, so you can create a new legacy immediately without refreshing the page.
{% endhint %}

### Safe delete

1. Click **Delete contract** on the details page.
2. Confirm in the popup; this submits the first signature.
3. Safe co-signers finalize at the threshold; status shows *Needs finalizing to delete* until done.
4. Once finalized, assets return to the Safe and approvals are revoked.

## What stays the same after edits

Notification settings (**watchers and email reminders**) are tied to the wallet that created the legacy, not to the legacy itself. Editing or replacing beneficiaries doesn't change who controls notifications. For Safe legacies where the creator is a specific Safe signer, only that signer can change notification settings; see [Creator vs. signer](/user-guide/concepts#creator-vs-signer-safe-legacies).

If the creator needs to effectively hand off notification settings to another Safe signer, the current workaround is: delete the legacy and recreate it, with the new signer submitting the creation transaction.

## See also

* [Legacy Contract Details](/user-guide/legacy/legacy-contract-details)
* [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds)
* [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers)


# Activate a Legacy Contract and Claim Funds

Activate a legacy left to you and claim funds. Works through the 10102 app, the Safe platform (for Safe legacies), or directly from any Ethereum interface using the printed Legacy Claim Card.

When a legacy's activation window has elapsed, any of its designated beneficiaries can activate it. This page covers all three paths: via the 10102 app, via the Safe platform (for Safe legacies), and via a blockchain explorer (for any legacy, using the Legacy Claim Card).

## Preflight

Before you can activate:

1. **Enough time must have passed**: the owner must have been inactive (no activity the legacy can see) for at least the configured trigger window.
2. **Your wallet must be one of the configured beneficiaries**: primary, or contingent after the corresponding line has kicked in.
3. **Gas**: activation is a paid transaction, and the assets are distributed to *all* beneficiaries according to the allocations, not just to you. For EOA transfer legacies, you usually **don't need any ETH yourself**; see [Claiming without ETH](#claiming-without-eth) below.

## Via the 10102 app

1. Open the app and go to **Legacies for Me**. Legacies left to you show up here whenever an address in them matches your connected wallet.
2. Click the legacy to open its details.
3. Click **Check contract's status & claim funds**.
4. If the window has elapsed, you're prompted to sign the activation transaction. Sign and pay gas.
5. The legacy's status moves to **Activated**.

### For Transfer legacies

All approved ERC-20s are distributed from the owner's wallet to the listed beneficiaries according to the allocations, and any native tokens the contract holds are distributed the same way.

{% hint style="info" %}
**Big legacies distribute in batches.** The contract can process up to 100 transfers per activation transaction. If the legacy you're claiming has more than that (e.g. 4 beneficiaries × 30 tokens = 120 transfers), a **Claim Remaining Fund** button stays available on the details page until everything is distributed. Any beneficiary can press it, any number of times.
{% endhint %}

### Claiming without ETH

If you're claiming an EOA transfer legacy and your wallet can't cover the network fee (common when the owner generated a fresh wallet for you), the app handles it automatically:

1. Instead of a transaction, your wallet asks for a **free signature** (an EIP-712 message titled *ClaimAuth*). Signing costs nothing.
2. 10102's relay service submits the claim transaction and pays the gas.
3. The app tracks the transaction and shows the result exactly as if you had sent it yourself.

The signature only authorizes the claim you were already entitled to: it names your address, this specific legacy, and the exact asset list, and it can be used once. Nobody, including us, can use it to send funds anywhere other than where the owner's allocations say. If you *do* have ETH, nothing changes: you pay your own fee as before. Owners can disable sponsored claims per legacy on-chain if they prefer; the pay-your-own-gas path always works. Details: [Gas-Sponsored Intents](/architecture/gas-sponsored-intents).

### For Multisig legacies

Activation adds the beneficiaries as signers to the owner's Safe, with the threshold the owner configured. From that point on, the Safe is under your collective control: you can act on it in the normal Safe UI, our UI, or any other tool.

## Via the Safe platform (Safe legacies only)

Safe-backed legacies can be activated from [app.safe.global](https://app.safe.global) independently of our UI:

1. Open the Safe in app.safe.global.
2. Navigate to the Apps tab and open the 10102 Legacy app (or interact with the module directly, for advanced users).
3. Activate from there. The module does the same work as our UI.

Useful as a backup path if our UI is down, or if you already live in Safe's interface.

## Via a blockchain explorer (any legacy)

This is the path your Legacy Claim Card describes. You can reach it any time, with or without our UI.

1. Open an explorer like Etherscan for the network the legacy is on.
2. Navigate to the **Router contract** from the card. It's a **Transfer Legacy Router** (or EOA Router) for Transfer legacies.
3. Connect your wallet (beneficiary address).
4. On the *Contract → Write* tab, call the activation function with the **Legacy ID** from the card as the argument.
5. Sign and pay gas.

The contract will distribute assets exactly as it would have done from the UI; the router has no knowledge of where the call originated.

{% hint style="success" %}
**You don't need a list of assets.** The router reads the approved token list from the legacy contract itself. You only need the Legacy ID.
{% endhint %}

## After activation

* **Status** reads **Activated** for everyone (owner, beneficiaries, watchers).
* **Watchers** still see the legacy under their watchlist for historical context.
* **Owner actions** are disabled: no more edits, no more deletes. The legacy has done its job.
* **Email notifications** (if configured) go out to impacted parties summarizing the distribution.

## Troubleshooting

* **"Not enough time has passed"**: your clock isn't the authoritative one. The contract checks against the owner's last outgoing transaction timestamp on-chain. Wait, or verify the owner really has been inactive for the trigger window.
* **"You are not a beneficiary"**: the address you're connected with doesn't match a configured beneficiary for this legacy ID. Re-check the card; check the address you expect to be listed; ask the owner if you suspect a typo.
* **"Insufficient gas"**: activation for a legacy with many tokens and beneficiaries can be expensive. For EOA transfer legacies the app normally covers this for you automatically ([Claiming without ETH](#claiming-without-eth)); otherwise coordinate with another beneficiary, or use the Claim Remaining Fund batching to split the cost.

## See also

* [Legacy Claim Card](/user-guide/legacy/legacy-claim-card): the printed safety net.
* [Concepts: Activation trigger](/user-guide/concepts#activation-trigger).


# Legacy Claim Card

A printable one-page summary that gives your beneficiaries everything they need to claim, even if our UI or website ever goes away.

A Legacy Claim Card is the paper safety net for your digital legacy. It's a one-pager, generated by the app, that documents the minimum on-chain information a beneficiary needs to activate and claim a legacy without depending on 10102's UI.

The point: **your legacy lives on Ethereum, not on our website.** As long as beneficiaries can reach any Ethereum interface (Etherscan, a wallet's built-in contract interaction, a future app we haven't built yet), a printed card is enough.

## What's on the card

* **Legacy ID**: the on-chain identifier, used directly with the router contract.
* **Legacy contract address**: where the allocations and approvals live.
* **Router contract address**: the router beneficiaries call to activate.
* **Activation instructions**: short, plain-language steps describing the function to call and what arguments it expects.
* **Network**: mainnet, Sepolia, etc.
* **QR codes**: scannable links for the contract address and router address, so beneficiaries don't have to hand-type 42-character hex strings.

## What's intentionally *not* on the card

* **The owner's wallet address.** Many owners don't want beneficiaries to know which wallet the legacy belongs to until activation. The card is designed to be handable to a beneficiary in advance (inside a sealed envelope, with a lawyer, in a safety deposit box) without leaking that link.
* **The list of assets.** This intentionally isn't pinned to paper. Asset lists change over time (you approve more, you remove some) and the card shouldn't go stale. Beneficiaries can look up the current asset list from the contract via any explorer.
* **Personal data or email addresses.** The card is purely on-chain coordinates.

## When to print it

Print (or regenerate) the card whenever:

* You first deploy a legacy.
* You change the legacy's address (e.g. you delete and recreate).
* You change beneficiaries and want the new ones to have a fresh copy.
* Your previous copies are unaccounted for.

## How beneficiaries use it without our app

If `app.10102.io` is unreachable for any reason, a beneficiary can still claim. The card includes step-by-step instructions, but the short version is:

1. Wait until the activation window has elapsed (time since the owner's last outgoing transaction exceeds the configured threshold).
2. Open any Ethereum interface that supports calling an arbitrary contract; Etherscan's *Contract → Write* tab works.
3. Connect the beneficiary's wallet.
4. Call the router's activation function with the **Legacy ID** from the card.
5. Sign. Pay gas. Assets are distributed according to the allocations the owner configured.

This is the same function our UI calls behind the scenes. The contracts don't know where the call came from.

{% hint style="success" %}
**Self-test.** If you're unsure the card is complete, hand a copy to a technically-minded friend and ask them: "If I disappeared and 10102's website didn't exist, could you initiate the claim for my beneficiaries from this alone?" If yes, the card is doing its job.
{% endhint %}

## Where to find it

* On a legacy's details page after creation, an action downloads the card as a printable PDF.
* Regenerate at any time. The card is derived from on-chain data, so it's always up to date.
* We don't store a copy on our servers. Keep the PDF (or a print) somewhere your beneficiaries can reach it when they need it.

## Privacy considerations

* Treat a Legacy Claim Card like you'd treat a will document: give it to people who need it, store copies securely, update when things change.
* The card doesn't contain private keys or anything sensitive beyond on-chain public coordinates, but it *does* contain the pre-activation pointer to a specific legacy, which is information some owners treat as private.
* If you've given someone a copy and want to revoke their ability to claim, delete and recreate the legacy (which generates a new contract address).

## See also

* [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract): the card is generated from here.
* [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds): the beneficiary's side.


# Premium Features

Optional, time-bound capabilities on top of the free legacy features: backup beneficiary layers, watchers with an advisor view, email reminders, automatic renewal, and gas-free check-ins.

Premium adds a second ring of protection around a plan that already works. The free tier is deliberately complete on its own: you can create, edit, activate, and claim legacies without ever subscribing. Premium is for owners who want the plan to keep taking care of itself: extra recovery layers, professional oversight, notifications, and automation that runs while you live your life.

## What Premium unlocks, at a glance

| Feature                                | What it does                                                                                                             | Guide                                                                                           |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
| **Contingent beneficiaries**           | Up to two backup layers that become eligible if your primary beneficiaries never claim                                   | [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries) |
| **Authorized watchers + Advisor view** | Read-only oversight for a lawyer, advisor, or family member, with a consolidated dashboard when they watch several plans | [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers)           |
| **Email reminders**                    | Out-of-band nudges before deadlines, for you and your beneficiaries                                                      | [Configure Email Reminders](/user-guide/premium-features/configure-email-reminders)             |
| **Automatic renewal**                  | Your normal wallet activity keeps your check-in timer fresh; no more remembering to check in                             | [Automatic Renewal](/user-guide/premium-features/automatic-renewal)                             |
| **Gas-free check-ins**                 | 10102 pays the network fee when you reset your timer                                                                     | [Gas-Free Check-ins & Claims](/user-guide/premium-features/gas-free-check-ins-and-claims)       |

{% hint style="info" %}
**Beneficiaries never need Premium (or even ETH).** Gas-sponsored *claims* are free for everyone: if a beneficiary's wallet can't cover the network fee at claim time, the app asks for a free signature and 10102 pays the gas. See [Gas-Free Check-ins & Claims](/user-guide/premium-features/gas-free-check-ins-and-claims).
{% endhint %}

## The Free baseline

Every user starts on the Free plan at no cost. The Free plan includes:

* Unlimited Legacy contracts and Timelocks.
* Unlimited beneficiaries.
* Auto-generated beneficiary keys with a printable backup (the Legacy Claim Card).
* Gas-sponsored claims for beneficiaries who hold no ETH.
* The Guardian AI assistant, with a free allowance for everyone.

On the Free plan you only ever pay Ethereum network gas. There is no subscription required for the core flows.

## Premium subscription

* **Model**: time-bound access, paid upfront, like an ENS name registration. You pick a duration, pay, and your Premium features are active for that window.
* **Accepted tokens**: ETH, USDC, or USDT.
* **On-chain record**: the subscription is recorded on-chain against your address.
* **Per-wallet**: subscriptions are scoped to the wallet that paid. If you manage multiple wallets, each needs its own subscription.

## What Premium unlocks

### Additional contingent beneficiary layers

Up to two additional fallback layers (a second-line and a third-line beneficiary) that become eligible to claim after configurable time windows if the primary beneficiaries don't act. Designed to handle the case where an intended beneficiary can't claim: lost keys, unreachable, deceased. See [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries).

### Authorized watchers

Read-only accounts you authorize to view your legacies under **My Watchlist**. Useful for:

* Coordinating with an estate lawyer, where the lawyer needs to reference the plan without having access to your assets.
* Running a family dashboard, where one person keeps an eye on multiple setups.
* Pairing an off-chain will with an on-chain plan: the watcher sees enough to attest that the plan exists, without you exposing your wallet address.

Watchers have two visibility modes: **limited** (privacy-preserving; addresses are replaced with a unique identifier) or **full** (addresses visible). A watcher who follows several legacies, say a family advisor or estate attorney, gets a consolidated read-only **Advisor view** in the app: every contract they watch in one list, with status and check-in health at a glance. See [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers).

### Email reminders

Opt-in email notifications for the owner and for each beneficiary, at configurable lead times before activation events. Sent for upcoming activations, timeline resets, actual activation, and successful claims. See [Configure Email Reminders](/user-guide/premium-features/configure-email-reminders).

### Automatic renewal

For wallet-based (EOA) legacies, an opt-in attestor watches your wallet's public on-chain activity and renews your check-in timer for you when you've been active near the deadline. Every safety bound is enforced by the contract, and the mechanism can only ever *delay* activation, never accelerate it. See [Automatic Renewal](/user-guide/premium-features/automatic-renewal).

### Gas-free check-ins

When you reset your inactivity timer, the app can ask for a free signature instead of a paid transaction, and 10102's relayer submits it and covers the network fee. Claims by beneficiaries are sponsored for everyone; check-ins are the Premium half of the same machinery. See [Gas-Free Check-ins & Claims](/user-guide/premium-features/gas-free-check-ins-and-claims).

## Creator-only note for Safe legacies

For Safe-backed legacies, watchers and email reminders are managed by the **wallet that created the legacy** (the specific Safe signer who submitted the creation transaction), not by the Safe as a whole. Other Safe signers can still manage on-chain settings (beneficiaries, trigger) at the Safe's threshold, but they'll see a "Notification settings managed by 0x…abcd" badge in the watchers/reminders UIs.

If the creator needs to hand off notification control (for example, if they're leaving the Safe), the current workaround is to delete and recreate the legacy with the new signer as the submitter. See [Concepts: Creator vs. signer](/user-guide/concepts#creator-vs-signer-safe-legacies).

## See also

* [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries)
* [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers)
* [Configure Email Reminders](/user-guide/premium-features/configure-email-reminders)
* [Automatic Renewal](/user-guide/premium-features/automatic-renewal)
* [Gas-Free Check-ins & Claims](/user-guide/premium-features/gas-free-check-ins-and-claims)


# Manage Contingent Beneficiaries

Fallback beneficiary layers that activate only if the primary beneficiaries don't claim within a configurable window. Premium only.

Contingent beneficiaries are the answer to *"what if my primary beneficiaries can't claim?"*. Keys get lost. People become unreachable. People pass. The contingent layers are the safety net.

Premium users can configure up to **two** additional layers on top of their primary beneficiaries:

* **Second-line**: one designated address, activates after a configurable window following the primary activation.
* **Third-line**: one designated address, activates after a further configurable window following the second-line.

{% hint style="info" %}
**Only one contingent beneficiary per layer, and only EOA addresses.** Contingent beneficiaries are intentionally simple: a single address per fallback layer. If you need multi-party fallback logic, that's a case for a Multisig legacy at the primary level.
{% endhint %}

## When does each layer become eligible

Each layer has its own activation window, measured from the moment the *previous* layer became eligible, not from the original trigger:

1. **Primary activation**: the legacy's main trigger elapses; primary beneficiaries can claim.
2. After primaries' window, **second-line** can claim (if configured).
3. After second-line's window, **third-line** can claim (if configured).

At any given time, multiple lines can be simultaneously eligible. The first address to actually claim "wins" the whole remainder; see below.

## Who actually gets the funds

* **Before second-line is eligible**: only primaries can claim, splitting according to the primary allocations.
* **Between second-line eligible and someone claiming**: primaries can *still* claim with the primary allocations. If a primary moves first, second-line is irrelevant.
* **If the second-line claims**: they become the **sole beneficiary** and receive everything remaining. No primary can claim afterwards.
* **Same logic applies between second-line and third-line.**

The model is first-to-act-wins among currently eligible parties. This keeps the contract simple and avoids coordinated-distribution failure modes.

{% hint style="success" %}
**Why one person and not a split for contingents?** Because the fallbacks are typically a different *kind* of person (an estate lawyer, a specialized recovery service, a single trusted proxy), and splitting their allocation doesn't match how those roles work in practice. If you want a split fallback, your primary layer is the right place to configure it.
{% endhint %}

## How contingent beneficiaries see the legacy

Until their line activates, contingent beneficiaries are treated as **watchers with limited visibility**: they see the legacy under **My Watchlist**, not **Legacies for Me**. The UI explicitly shows whether they're viewing as a watcher or as an imminent contingent beneficiary.

Once their line is eligible, the legacy moves to **Legacies for Me** and they get full-visibility beneficiary access.

{% hint style="info" %}
**You can change a contingent beneficiary's visibility.** The defaults are conservative (limited), but the owner can switch a contingent to full visibility from the watcher settings. Useful when the contingent is an estate lawyer who needs to see addresses to coordinate off-chain planning.
{% endhint %}

## Configuring

Contingent layers can be configured:

* **At creation**: during the configure step of a Transfer legacy.
* **Via edit**: at any time before the primary trigger has activated.

For each layer you set:

* The contingent's Ethereum address (EOA only).
* The window (in days) that must pass after the previous layer became eligible.

## Removing

* **Second-line and third-line beneficiaries** can't be removed from the watcher list directly; they're removed by editing the legacy itself.
* Removing a line of contingent activation also removes that beneficiary's watcher entry.

## Real-world example

> Alice sets up a Transfer legacy:
>
> * **Primaries**: her kids Bob and Charlie, 50% each, 180-day activation trigger.
> * **Second-line**: her estate lawyer Daria, 90-day window after primary.
> * **Third-line**: a professional recovery service, 180-day window after second-line.
>
> Alice goes silent. After 180 days, Bob and Charlie can claim. After 90 more days with no claim, Daria becomes eligible. If Bob finally checks his email and claims at that moment, the original 50/50 split to Bob and Charlie still happens. If Daria claims first, she gets everything (she's supposed to professionally recover and distribute off-chain).

## See also

* [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers)
* [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds)


# Manage Authorized Watchers

Read-only accounts you authorize to view a legacy without being able to edit, delete, or alter it. Premium only.

An **authorized watcher** is a read-only spectator on a legacy. They see it under **My Watchlist** in their 10102 dashboard; they can never edit, delete, activate, or otherwise affect it.

Watchers are a first-class way to coordinate with people who need visibility but shouldn't have control: estate lawyers, family members, advisors, compliance officers.

## Configuring

Go to **Settings → Authorized Watchers** and select a legacy to manage watchers for.

For each watcher you add:

* Their Ethereum address (EOA).
* A display name (private label for your own reference).
* A visibility level; see below.

You can add, remove, or change a watcher's visibility at any time.

{% hint style="warning" %}
**For Safe-backed legacies, only the creator can edit the watcher list.** The creator is the specific Safe signer who submitted the original creation transaction. Other Safe signers see the watcher list but with editing disabled and a "Notification settings managed by 0x…abcd" badge. This is documented in [Concepts: Creator vs. signer](/user-guide/concepts#creator-vs-signer-safe-legacies); the workaround for handing off creator control is to delete and recreate with the new signer as submitter.
{% endhint %}

## Visibility levels

### Limited visibility (default, privacy-preserving)

With limited visibility:

* **Owner wallet address**: hidden. Replaced by a unique private identifier tied to the owner's 10102 account.
* **Safe co-signer addresses** (Multisig legacies): hidden.
* **Beneficiary addresses**: hidden. Names (owner-entered labels) are shown.
* **Watchers cannot locate the legacy on-chain** from what the app shows them; the identifier is 10102-internal, not an Ethereum address.

Use when: you want oversight without exposing the on-chain footprint. Typical for a general-purpose family watcher.

### Full visibility

With full visibility:

* All addresses are shown: owner, Safe co-signers (Multisig), beneficiaries.
* Watchers can look up the legacy contract on Etherscan and see the on-chain activity directly.
* Allocations, activation triggers, and asset lists are fully visible.

Use when: the watcher genuinely needs the addresses, typically an estate lawyer coordinating with off-chain documents, or a professional recovery service who needs to be able to act on-chain later.

## How watchers see the legacy

Watchers get a **My Watchlist** section in their dashboard. Each entry shows:

* The legacy's status (Needs finalizing, Live, Activated).
* Activity trigger and its remaining window.
* Asset allocations per beneficiary (at whatever visibility level they're granted).
* Any notes the owner has configured.

Watchers cannot act. No edit. No delete. No activation. They can only read.

## Advisor view

If you're the watcher (a family advisor, estate attorney, or professional service watching several clients' legacies), the app gives you a consolidated **Advisor view**. Connect the wallet that owners have listed as a watcher and every contract you watch appears in one read-only list, sorted most urgent first (soonest check-in deadline at the top, activated contracts last).

Each contract card shows:

* A status chip: **Active**, **Check-in due soon** (the owner's check-in deadline is under 7 days away), **Ready to activate**, or **Activated**.
* Days remaining until the owner's next check-in deadline, where known.
* The owner's identity at whatever visibility level that legacy grants you: the owner's address (or ENS name) with full visibility, the private identifier with limited visibility.

There is nothing for the watcher to enable or pay for: the entry point appears automatically once at least one legacy lists your wallet as a watcher, and it disappears if none do. Authorized watchers are a capability of each **owner's** Premium plan; the watcher doesn't need a subscription of their own.

The same rule applies here as everywhere: the advisor view is read-only. A watcher can never check in, edit, delete, or activate a legacy from it; opening a contract leads to the same read-only detail view as the watchlist.

## Contingent beneficiaries are automatically watchers

Second-line and third-line contingent beneficiaries are, by default, added as watchers with **limited visibility**. The owner can change their visibility at any time (e.g. upgrade an estate-lawyer contingent to full visibility).

* Contingents can't be removed from the watcher list directly; they're removed by editing the legacy itself (removing them from the contingent configuration).
* When their line activates, they move from **My Watchlist** to **Legacies for Me** with full-visibility beneficiary access.

## Real-world use cases

* **Consolidated oversight across wallets.** You manage several EOAs and Safes; watchers let a single dashboard see all of them without any one wallet having access to the others.
* **Estate coordination.** A lawyer references the plan from off-chain documents. Limited visibility preserves the owner's privacy while the unique identifier lets documents unambiguously point to a specific plan.
* **Family peace-of-mind.** A spouse or adult child has visibility without control: they know the plan exists, can see it's still active, but can't accidentally tamper.
* **Monitoring counterparty plans.** Professional setups where one party's 10102 legacy is a contingency for another party's obligations.

## See also

* [Configure Email Reminders](/user-guide/premium-features/configure-email-reminders)
* [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries)
* [Concepts: Creator vs. signer (Safe legacies)](/user-guide/concepts#creator-vs-signer-safe-legacies)


# Configure Email Reminders

Optional email notifications for the owner and beneficiaries at key events in a legacy's lifecycle. Premium only.

Email reminders let the owner and beneficiaries get out-of-band notifications at key moments in a legacy's lifecycle, so nobody has to remember to check the app.

Reminders are **additive**: the on-chain contract doesn't know about emails and doesn't depend on them. If a reminder doesn't reach someone, the plan still works, but reminders make it much harder for something to be silently missed.

## Events that trigger emails

| Event                                                                                           | Who gets it                                                 |
| ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| **Upcoming activation** (X days before the trigger window elapses)                              | Owner + impacted beneficiaries for that stage               |
| **Activation timeline reset** (owner made an outgoing transaction or used the heartbeat action) | Owner + impacted beneficiaries for the impending stage      |
| **Activation happens** (a stage becomes eligible, or a beneficiary actually claims)             | Owner + impacted beneficiaries                              |
| **Successful claim** (assets are distributed)                                                   | Owner + impacted beneficiaries, with a distribution summary |

"Impacted beneficiaries" depends on which stage we're talking about:

* For **primary** activation events: primaries only.
* For **second-line** events: primaries *and* the second-line contingent (primaries are notified because second-line eligibility affects their claim window).
* For **third-line** events: primaries, second-line, and third-line.

The intent is: everyone who can meaningfully act on the information gets it; everyone else doesn't.

## Configuring

Go to **Settings → Email Reminders → Create a Reminder** and pick the legacy to configure.

You'll be asked for:

* **Email addresses**: one per beneficiary (optional, per-beneficiary) and one for the owner (optional).
* **Advance notice period** (in days): how long before each activation event the "upcoming" reminder should go out. Common values are 7, 14, or 30 days.

You can edit or delete a reminder setup at any time from the same screen.

{% hint style="info" %}
**Emails are opt-in.** A beneficiary who doesn't want to share their email can be left unconfigured; they just won't receive reminders. The plan still functions fully.
{% endhint %}

{% hint style="warning" %}
**For Safe-backed legacies, only the creator can edit reminders.** The creator is the specific Safe signer who submitted the original creation transaction. See [Concepts: Creator vs. signer](/user-guide/concepts#creator-vs-signer-safe-legacies). If you're another Safe signer you can view the reminder configuration but not change it; you'll see a "Notification settings managed by 0x…abcd" banner pointing to the creator.
{% endhint %}

## What emails look like

Emails are informational only; they never contain links asking for signatures or private keys. The app URL in an email is there for convenience, not to act as an authentication factor. Beneficiaries can always go straight to `app.10102.io` (or use the printed [Legacy Claim Card](/user-guide/legacy/legacy-claim-card)) instead of clicking through.

Each email includes the Legacy ID so the recipient can look the legacy up on-chain directly if they prefer.

## Privacy considerations

* **Email addresses are not on-chain.** They're stored off-chain, encrypted at rest, and only used for sending reminders.
* **The owner sees their beneficiaries' emails** in the reminder configuration. If a beneficiary prefers total privacy, they can ask to be omitted.
* **Reminders are tied to the legacy**, not the wallet: deleting the legacy deletes the reminder configuration.

## See also

* [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers)
* [Manage Contingent Beneficiaries](/user-guide/premium-features/manage-contingent-beneficiaries)
* [Concepts: Creator vs. signer (Safe legacies)](/user-guide/concepts#creator-vs-signer-safe-legacies)


# Automatic Renewal

Let your normal wallet activity keep your legacy fresh: an opt-in service renews your check-in countdown when you've been active on-chain, with every safety bound enforced by the contract.

Wallet-based (EOA) legacies work on a check-in timer: if you don't interact with your legacy for the inactivity window you configured, it becomes claimable. That's the core promise, but it comes with a chore: remembering to check in, even during years when you never need to touch the plan.

**Automatic renewal** removes the chore. When it's on, 10102 watches your wallet's *public* on-chain activity (its transaction count). If you've been active close to your deadline, we reset the countdown for you: no click, no email, no gas. You keep living on-chain; the plan keeps up.

## Turning it on

1. Open the legacy's details page and find the **Automatic renewal** switch.
2. Flip it on. A confirmation explains exactly what you're agreeing to, in the same words as this page.
3. Confirm the small transaction in your wallet. The setting is recorded on-chain, per legacy, and you can turn it off the same way at any time, Premium or not.

{% hint style="info" %}
**Works with check-in periods of about 13 months or less.** With a longer inactivity window, the renewal machinery could never fire before its own safety budget ran out (see below), so the switch tells you to shorten the window instead of pretending to protect you.
{% endhint %}

## What we watch, and what we can't see

We read one public number: your wallet's transaction count, the same figure anyone can see on Etherscan. There is no tracking beyond that: no browsing data, no location, no off-chain identity. If the count went up near your deadline, you've been active, and the attestor renews your timer.

## The safety rails, in plain words

Every rule below is enforced by the smart contract, not by us promising to behave:

* **Only you can turn it on or off**, per legacy, and it's off by default.
* **Renewals only happen near your deadline** (within the last 30 days of the countdown), and never after a legacy has already become claimable. A lapsed legacy belongs to your beneficiaries; only your own check-in can recover it.
* **Automatic renewals stop 12 months after your last real check-in.** When the budget runs out, reminder emails ask you to check in yourself once, which refills it. The service cannot extend its own leash.
* **The worst possible failure is a delay.** If our monitoring were ever wrong or compromised, the only possible effect is your beneficiaries waiting longer, which is bounded and recoverable by you at any time. Renewals can never speed up activation, redirect funds, or touch your contract in any other way.

The full trust model, including exactly what a compromised attestor key could and couldn't do, is in [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).

## When renewals pause

Renewals stop (and email reminders take over) whenever:

* the 12-month budget since your last real check-in runs out,
* your Premium subscription lapses (your opt-in is remembered; renewals resume if you re-subscribe),
* or you turn the switch off.

Nothing about the legacy itself changes in any of these cases. The timer keeps counting exactly as configured, and checking in yourself always works.

## Common questions

**Does this replace check-ins entirely?** Almost. You'll be asked to check in yourself once every 12 months at most, so that a real signal from you stays in the loop.

**Does it cost anything per renewal?** No. 10102 pays the gas for every automatic renewal. See [Gas-Free Check-ins & Claims](/user-guide/premium-features/gas-free-check-ins-and-claims) for the other ways we cover fees.

**What about Safe legacies?** They don't need this: every Safe transaction already counts as activity automatically, via the Safe Guard.


# Gas-Free Check-ins & Claims

10102 can pay the network fee for you: claims are sponsored for every beneficiary, and check-ins are sponsored for Premium owners. You sign a free message; we submit the transaction.

Every on-chain action normally costs a network fee, and the person who needs to act isn't always the person holding ETH. A beneficiary claiming an inheritance may hold a freshly generated wallet with a balance of exactly zero. An owner checking in pays a fee for what amounts to pressing a button.

Gas sponsoring closes both gaps with the same machinery: **you sign a free authorization message, and 10102's relayer submits the transaction and pays the fee.** The signature is verified by the contract itself, so the relayer physically cannot do anything other than what you signed.

## Claims: free for every beneficiary

This one isn't a Premium feature; it's part of the product's core promise. When a beneficiary starts a claim and their wallet can't cover the network fee, the app automatically switches from "send a transaction" to "sign a free message". The signature authorizes exactly the claim they were already entitled to (their address, that specific legacy, the exact asset list, usable once), and 10102 submits and pays. Beneficiaries who do hold ETH simply pay their own fee as before.

Owners stay in control: sponsored claims are on by default and can be switched off per legacy on-chain. The beneficiary-pays path always works regardless.

The step-by-step flow is in [Activate a Legacy Contract and Claim Funds](/user-guide/legacy/activate-a-legacy-contract-and-claim-funds#claiming-without-eth).

## Check-ins: the Premium half

The same mechanism covers the owner's side: resetting your inactivity timer by signature, with 10102 paying the fee. Claims are sponsored for everyone because a claim is a once-in-a-lifetime moment for someone who may own no ETH at all; check-ins recur for owners who can pay, so we cover those for Premium subscribers.

Two ways your check-ins can be gas-free on Premium:

* [**Automatic renewal**](/user-guide/premium-features/automatic-renewal): the hands-off version. You don't sign anything at all; the attestor renews for you when your wallet has been active, and 10102 pays every renewal.
* **Sponsored check-ins**: the on-demand version. You sign a free message instead of paying for the check-in transaction. The relayer capability is live; the one-click app experience is rolling out.

## Why this is safe

The relayer is a courier, not a signer. The contract recovers *your* signature and acts as you, for you:

* A claim authorization can only send assets to the signer's own allocation, exactly as the owner configured it. Nobody, including 10102, can redirect it.
* Every authorization is single-use (an on-chain nonce) and expires (a deadline you signed).
* If our relayer ever went away, nothing is lost: relaying is permissionless on-chain, and the ordinary pay-your-own-fee path always works.

The full mechanics and trust model are in [Gas-Sponsored Intents](/architecture/gas-sponsored-intents).

## Common questions

**Is "gas-free" really free?** For you, yes. Someone still pays the network, and for sponsored actions that someone is 10102. The relayer applies fair-use bounds (daily caps, a gas-price ceiling); if it ever declines, the app falls back to the normal self-paid path.

**Can a relayer see my keys or assets?** No. It only ever receives the signed message you produced, and the contract checks that message before anything happens. Your keys never leave your wallet.

**I'm an owner and I don't want any third party submitting claims for my legacy.** You can turn sponsored claims off per legacy by calling `setSponsoredClaimsEnabled` on the router (from Etherscan today; an in-app switch is on the way). Your beneficiaries will then pay their own claim fee.


# Timelock

A time-based security layer for self-custody wallets. Lock your own funds against coercion, wrench attacks, or just your own impulse decisions.

A **Timelock** is a contract that holds your assets in a frozen state for a period of time. Nothing can move the locked assets until the lock expires: not your own keys, not a compromised signer, not a thief holding a physical wrench.

Timelocks are unrelated to legacies. They don't need beneficiaries and they don't distribute on activation. Their job is simpler: *prevent movement for a while, then return the funds to you* (or, in one variant, deliver them to a designated recipient).

Three flavors, for three different use cases:

## Timelock

**Locked until a specific date; then the owner reclaims.**

* Pick a duration up front. The contract releases on that date, no exceptions, no early withdrawal.
* Useful for: self-imposed HODL periods, pre-commitment devices, cooling-off periods, protecting against your own impulse trading.

## Soft Timelock

**Locked indefinitely; unlocking triggers a configurable waiting period.**

* Locked assets stay locked until you explicitly initiate an unlock, which starts a waiting clock (days). Only after the clock runs out can you claim.
* This is the anti-wrench-attack variant: even with full access to your keys, an attacker can't immediately drain the balance. They have to initiate an unlock and wait, during which you (or anyone watching) can notice.
* Useful for: high-value cold-storage-style protection without cold-storage operational overhead, compromise-tolerant self-custody.

## Beneficiary Timelock

**Locked until a specific date; then a designated recipient claims.**

* Same release mechanics as a regular Timelock, but the recipient is another wallet, not the owner. (The contract calls this type `Gift` on-chain; the app labels it Beneficiary timelock.)
* Useful for: planned giving, trust-fund-style disbursements, escrow-like arrangements.
* For an actual gift-giving experience (occasion designs, a claim link the recipient opens, printable sheets, free claiming), use [Heirloom](/user-guide/heirloom), which seals the same contract type with a friendlier wrapper.

## Which to pick

| You want to                                                      | Use                                  |
| ---------------------------------------------------------------- | ------------------------------------ |
| Force yourself not to touch funds for N days                     | **Timelock**                         |
| Protect yourself if someone coerces you or compromises your keys | **Soft Timelock**                    |
| Schedule a future transfer to someone else                       | **Beneficiary Timelock**             |
| Send someone a sealed gift they open with a link                 | [**Heirloom**](/user-guide/heirloom) |

## How timelocks hold your assets

* **ERC-20 tokens**: approved to the timelock contract, moved in when you finalize creation. Once in the contract, they can't leave until the lock expires (or, for Soft Timelock, until the waiting period after unlock elapses).
* **ETH**: can't be held directly (ETH isn't an ERC-20 and can't be approved as one). Instead, you swap ETH into a supported **storage token** (WETH or a liquid staking token) through a built-in swap route, then the timelock holds that token. When the lock expires, you get the storage token back; you can swap it back to ETH at your discretion.
* **NFTs and ERC-1155**: not currently supported in timelocks. Timelocks are focused on fungible asset protection.

See [Using Timelock](/user-guide/timelock/using-timelock) for the full create/claim walkthrough.


# Using Timelock

Creating, managing, and claiming each of the three timelock flavors: Timelock, Soft Timelock, Beneficiary Timelock.

Navigate to the **Timelock** tab of the app. You'll see any timelocks you've created, and any beneficiary timelocks others have set up with you as the recipient.

To create a new one, click **Create timelock** and pick a flavor: Timelock, Soft Timelock, or Beneficiary Timelock.

## Common concepts

These apply to all three flavors.

### Approving and including assets

A timelock holds what you explicitly approve for it. For each asset:

* **ERC-20 token**: approve the timelock contract as a spender, then include it. The asset moves into the contract when you finalize creation.
* **ETH**: can't be approved directly. Use the swap action to convert ETH into a supported storage token (WETH, a liquid staking token), then approve and include that token.

{% hint style="info" %}
**Quick setup.** Most timelock create screens offer a one-click "Lock all available ETH" (or similar) shortcut that picks a reasonable default storage token, swaps at market rate, and prepares everything for finalization. Use it when you want the default behavior; switch to manual asset-by-asset selection when you want precise control over which tokens and how much.
{% endhint %}

{% hint style="warning" %}
**Finalizing fails if your approvals don't cover the configured amounts.** If you set a timelock to lock 100 USDC but only approved 50, creation will revert with an `ERC20: transfer amount exceeds allowance` error. The UI guards against this by not letting you finalize until approvals match, but if you edit approvals in your wallet out-of-band, re-check the UI before finalizing.
{% endhint %}

### Status values

| Status                                  | Meaning                                                                                 |
| --------------------------------------- | --------------------------------------------------------------------------------------- |
| **Active**                              | Locked. Funds can't be moved. Progress bar shows how much of the lock has elapsed.      |
| **Unlock pending** (Soft Timelock only) | You've initiated an unlock; the waiting period is counting down. Still can't claim yet. |
| **Ready**                               | Lock period has expired. You (or the recipient, for a Beneficiary Timelock) can claim.  |
| **Claimed**                             | Funds have been claimed back. Timelock is done.                                         |

## Timelock

### Create

1. **Timelock** tab → **Create timelock** → select **Timelock**.
2. Configure:
   * **Name**: private label.
   * **Duration**: how long to lock for. Supports any duration up to contract limits.
   * **Assets to include**: pick which tokens and amounts. Use quick setup for ETH, or approve/include individual tokens.
3. Finalize. One transaction per flavor:
   * If any ETH needs swapping, the swap happens first.
   * The timelock is created and assets move in.

### Claim

Once the lock elapses:

1. Open the timelock's details page; the status will read **Ready**.
2. Click the claim action. Sign one transaction.
3. Assets return to your wallet.

## Soft Timelock

### Create

Same as Timelock, except the duration field is replaced by a **waiting period**: "once unlock is initiated, how many days until funds can be claimed?"

### Unlock

From the timelock dashboard or the details page, click **Unlock**. Sign one transaction. The status changes to **Unlock pending** and the waiting period begins.

While unlock is pending, the timelock is still protected; funds can't be claimed. This is the window during which you'd notice a compromise and take defensive action (cancelling the unlock, moving other funds, rotating keys).

{% hint style="info" %}
**Cancelling an unlock.** From the details page, you can cancel an in-progress unlock and return to the locked state. Useful if you initiated the unlock yourself and changed your mind, or if you suspect the unlock was initiated by an attacker with access to your keys. In the attacker case, though, they could also just cancel your cancellation, so rotate keys in parallel.
{% endhint %}

### Claim

Once the waiting period elapses, status reads **Ready**. Click claim, sign, done.

## Beneficiary Timelock

### Create

Same flow as Timelock, with two extra fields:

* **Recipient address**: the wallet that will be able to claim when the lock expires. Must be an EOA.
* **Name**: something meaningful to the recipient, since they'll see it in their dashboard.

{% hint style="info" %}
**The recipient is notified by the presence of the timelock on their dashboard.** They'll see it in the Timelock tab as the designated recipient, starting as soon as you finalize creation. If you want it to be a surprise, consider sharing the information at delivery time rather than at creation time. For a designed gift experience with a claim link, printable sheets, and free claiming, use [Heirloom](/user-guide/heirloom) instead.
{% endhint %}

### Claim (by the recipient)

1. The recipient opens the Timelock tab; the timelock appears with them as the recipient.
2. Until the lock elapses, status is **Active**. Once elapsed, status reads **Ready**.
3. Recipient clicks claim, signs the transaction, and receives the assets directly into their wallet.

The creator can't reverse a beneficiary timelock after it's created: once locked, the recipient is the only one who can claim at expiry. If the creator wants flexibility to revoke, a regular Timelock (claimable by them, then sent off later) is the right pattern instead.

## Troubleshooting

* **"Transfer amount exceeds allowance" on finalize.** Your approvals don't cover the amounts you've configured for the timelock. Re-approve from inside the app; the UI keeps approvals and the finalize button in sync.
* **"Cannot claim: still locked".** The contract checks on-chain time, not your browser clock. Double-check the lock-end date on the details page.
* **ETH didn't swap.** A swap requires routing liquidity. For very small amounts or thin-liquidity storage tokens, the swap may fail. Try a supported storage token with known liquidity (e.g. WETH) or reduce the amount.

## See also

* [Timelock: overview of the three flavors](/user-guide/timelock)
* [Concepts: Storage token](/user-guide/concepts#storage-token)


# Heirloom (sealed gifts)

Seal ETH or USDC as a gift that opens on a date you choose. The recipient opens it with a link, and claiming is free.

Heirloom seals value for someone until a date that matters: a Bar or Bat Mitzvah, a wedding, a birth, an 18th birthday. The gift is held by the same audited timelock contract the rest of the app uses. Until the opening date nobody can take it out, including you.

The thing you send is a gift. Heirloom is the product that seals it.

## Sending a sealed gift

Open **Heirloom** in the top menu (or the **Send a sealed gift** button on the Timelock tab) and fill one card:

1. **Occasion**: Bar/Bat Mitzvah, Wedding, New baby, Birthday, Graduation, Hanukkah, Christmas, Eid, or Someday. The occasion sets the design of the printable sheets and suggests a message. It also proposes a fitting unlock horizon (five years for most occasions, eighteen for a new baby).
2. **To**: three ways to address it.
   * **Their wallet**: paste the recipient's wallet address.
   * **Just their email**: type the recipient's email. The gift is sealed to a wallet that only that email can open (see "Email gifts" below). Sealing asks for one extra signature, the wallet lookup, before the transaction.
   * **A printed card**: the app generates a fresh wallet for the gift and you hand its key over on paper. The paper is the gift.
3. **Amount**: ETH, or USDC for stable value. Both are escrowed on sealing; the choice changes what the recipient receives, not how the seal works.
4. **Unlocks**: a preset horizon or an exact date. The date is final and can never be shortened.
5. **Message (optional)**: stays off the blockchain. It travels inside the claim link, prints on the paper's cover (first two lines), and shows on the gift page when the link is opened.

Sealing sends one transaction (two for USDC: an exact-amount approval, then the seal). The gift cannot be recalled or changed after it confirms, not even by you.

{% hint style="info" %}
Some wallets show a caution while our escrow contract is still young. This is a reputation flag on a new contract, not a finding. Rather than ignoring any warning, verify: the contract address your wallet shows must match the published list in the public repository (`contract-addresses.json`).
{% endhint %}

## The claim link is the gift

Sealing produces one link, shaped like `app.10102.io/heirloom/1/42#g=...`. The part after `#` carries the names and your message. Browsers never send that part to any server, ours included, so the personal words stay between the two of you.

* Anyone with the link can SEE the gift: who it is from, what it holds, when it opens.
* Only the recipient's wallet can TAKE it, and taking it is free (see claiming below).
* Share it by copy, WhatsApp, email, or the printed card's QR code.

The seal panel can also email the link for you, with a timing choice:

* **Right away**: "a gift is waiting" today, plus a reminder on opening day.
* **On a day you pick**: nothing today; the announcement goes out on the day you choose (the birthday, the wedding), and the opening-day reminder still follows.
* **On opening day**: full surprise; one email when the gift opens.

You sign one free message to authorize it (the signing prompt shows only a fingerprint, never the email). The address is stored encrypted and deleted once its job is done. The same email panel lives on the gift's detail page under Timelocks, so you can add or correct an email any time after sealing.

The names, message, and occasion are also kept on the device that sealed the gift (never on a server), so the gift's detail page on that device can rebuild the full link and the printed card later.

## The printables

* **The key sheet** (paper-key gifts): one paper holds the whole gift. The occasion cover faces front and carries a big scannable code at the heart of the design: scanning it opens the gift page, with the names, the message, and the countdown. "How to open your gift" faces back, and the secret key is sealed inside the fold, clearly marked THE KEY, NOT A WEB LINK. Print single-sided and fold on the printed dashed lines. Whoever holds this paper controls the gift: never photograph it open. The cover is safe to show; the inside is not.
* **The gift card** (wallet-address gifts): the digital greeting for gifts sent to an existing wallet. Occasion design, who it is for, the opening date, your message in quotes, and a QR of the claim link. Safe to share and photograph; it contains no key material and never shows the amount. Paper-key gifts don't need it: their sheet already carries everything.
* **The gift record**: a factual document for the giver, downloadable from the gift's detail page. It leads with the fair market value on the sealing date, then dates, amounts, shortened wallet addresses, the escrow contract, and the sealing transaction as a scannable code and link for direct verification on the public ledger. It is not tax advice and says so; hand it to your advisor.

## Claiming (free for the recipient)

On opening day the recipient opens the link (or scans the paper's front again) and claims:

* **With the paper alone**: the gift page asks for the key folded inside the sheet. Scan it with the camera or type it in; the key signs the claim on the recipient's own device and never leaves it. No wallet app, no account, nothing to install.
* **With their email** (email gifts): the gift page asks for the email the gift was sent to, then for the six-digit code that arrives in that inbox. Typing the code is the whole login. The wallet behind the email signs the claim and 10102 submits it.
* **With a wallet**: connect the wallet the gift was sealed for and sign one free message.
* **Straight to your own wallet**: on the claim page you can paste the address of a wallet you already use, and the gift lands there in the same free transaction. The choice is part of the message the gift's key signs, so nobody else can change where it goes. We recommend it for paper and email gifts: the printed or email key is then used exactly once and never holds the funds. Leave the field empty and the gift goes to the gift's own wallet, as before.
* Whichever way, claiming costs the recipient nothing: 10102 submits the transaction and pays the network fee, and the contract pays out only to the on-chain recipient or to the wallet that recipient named in the signed claim.
* If the sponsored path is ever unavailable, a wallet holder can submit the withdrawal self-paid, and a paper holder can import the key into a wallet app (MetaMask: "Import account") and do the same.
* Before opening day, the gift page shows a live countdown to the second, can add the opening day to Google Calendar or any calendar app, and can be shared or copied with one tap. Nothing is sent to our servers.
* After claiming, the page becomes a small keepsake: sealed date, opened date, and an invitation to seal one forward.

## Email gifts

"Just their email" exists for the recipient who has no wallet and should not need one: a grandparent, a child, a friend who has never touched crypto. Here is exactly what happens, so you can decide if it fits.

* At sealing time we ask Turnkey, an embedded-wallet provider, for a wallet tied to that email. If none exists, one is created. The gift is sealed to that wallet's address, on-chain, like any other gift.
* The wallet's private key lives inside Turnkey's secure hardware enclaves. Nobody, including 10102, can read it. It signs only after the email's owner proves it is them with the code, and 10102 holds no credential that could move the funds.
* On opening day the recipient enters the email and the code, and the wallet signs the claim. The claim page asks where the gift should land: paste the address of a wallet the recipient already uses and the funds go there directly, in the same free transaction. Left empty, the funds stay in the email wallet, and the recipient can log in again on the gift page any time. For gifts claimed to the email wallet before this option existed, write to <info@10102.io> and we walk the recipient through moving them.
* **The honest trade**: this is a step away from pure self-custody. The recipient depends on their email account and on Turnkey's service to reach the key, where the paper gift and the wallet gift depend on nothing but the key holder. If that trade is not right for your recipient, use the printed card.
* Double-check the spelling. The gift can only be opened with the exact email you typed; a typo seals it to a wallet nobody will ever log into, and it cannot be recalled.

## Honest limits

* **Irrevocable**: once sealed, no one can cancel, shorten, or redirect a gift. Triple-check the recipient address, or email, and the date.
* **Paper is a bearer instrument**: for paper-key gifts, losing the key sheet before opening day loses the gift, and anyone who photographs the open sheet can take it. The sheet says this on the sheet.
* **The link shows the gift**: treat the claim link like a greeting card, not like a password. It cannot move funds, but it does reveal names, message, and amounts to whoever holds it.
* **Sponsored claims are capped**: gas sponsorship is bounded by daily caps to keep the feature abuse-proof. If the day's budget is exhausted, claiming still works self-paid, or free again the next day.


# Save (a monthly lock)

Put a little aside every month, locked until a date you choose. Buy on Coinbase, send it to your wallet, lock it. Opens on the day you pick.

Save is the plainest page in the app: one card, three choices, one button. It is for someone who has never used a wallet and wants to set money aside that they cannot touch until a date they choose.

Underneath it is a regular [Timelock](/user-guide/timelock). The page adds nothing new on the blockchain; it only removes the choices you do not need. Every lock you make here also shows in the Timelock tab, where you take it back once it opens.

Open it at `app.10102.io/save`.

## Making a lock

1. **What are you locking.** USDC if you want the value to stay steady, or ETH. The page shows what your wallet holds and starts on whichever you have.
2. **How much.** Type an amount, or tap **Use all of it**. For ETH, "use all" keeps a little back for the network fee.
3. **When does it open.** In 1, 3, 5 or 10 years. The exact opening date is shown before you confirm, and it is final: it cannot be moved earlier, not even by you.
4. **Lock it.** One confirmation in your wallet. USDC asks for a second one the first time, to allow the exact amount. You pay the network fee, usually a few dollars.

The lock appears under **Your locks so far** on the same page, with its opening date, and in the Timelock tab.

## Funding it from Coinbase, once a month

The page walks through this with your own wallet address ready to copy and a code to scan:

1. **Let Coinbase buy for you.** In the Coinbase app: Buy, then Recurring buy, pick USDC or ETH, and choose weekly or monthly. Your bank money turns into USDC or ETH on its own.
2. **Once a month, send it to your wallet.** In Coinbase: Send, paste your wallet address, choose the **Ethereum** network (not Base, not any other), and send. Try a small amount the first time.
3. **Come back to the Save page and lock it.**

Why monthly and not weekly: every lock is a transaction on Ethereum with its own network fee. Weekly buys on Coinbase are fine; lock once a month.

Each month's lock opens on its own date. After a few years of monthly locks you have money opening every month, for as long as you kept saving.

## Taking it back

When a lock's date arrives it shows **Ready** in the Timelock tab. Tap it, confirm once, and the money is back in your wallet. ETH locked here is held as wrapped ETH (WETH) while locked; you can have it back as ETH.

## What you should know

* **No early withdrawal.** A lock opens on its date and not a day sooner. Nobody can open it early, including us.
* **No interest.** You get back exactly what you put in.
* **Not a bank account.** No bank holds the money and no deposit protection covers it. It sits in an audited contract on Ethereum, in your name.
* **Prices move.** ETH goes up and down. USDC is made to stay close to one dollar.
* **Fees.** Locking is a transaction, and so is taking it back. You pay the network fee for each.


# Shield Vault (protect a holding)

Put a token behind a wait you choose. If your key is ever stolen, anything the thief starts waits in plain sight, and your recovery sheet can stop it.

A protected holding is a token you put in the Shield Vault, behind a wait. Anything that leaves it, your own withdrawal included, is public from the moment it starts and only completes after the wait. If someone steals your wallet key, they can start a withdrawal but not finish it before you notice, and a recovery sheet you printed at the start stops it and moves everything to a wallet you chose in advance. If you go silent for a long time, the holding can go to the people you name.

Open it from **Shield Vault** in the menu, or at `app.10102.io/shield`. It runs on Ethereum, in the contract `0xA1EA2F8C0518458975E09ED63bf5D48980f76C38`.

## Making one

Five decisions, one per step. Nothing is sent until the last one.

1. **What to protect.** wstETH, USDC, USDT or WETH, and how much. If you hold plain ETH, pick WETH: the page offers to wrap the ETH you need first (1 WETH is always 1 ETH, and it turns back into ETH any time).
2. **How slowly it can leave.** 7, 30 or 90 days; 30 suits most people. This is how long you have to stop a withdrawal you did not ask for. Every withdrawal waits this long, yours included, and the page shows the date a withdrawal started today would complete.
3. **Who receives it if you go silent.** Optional. Choose 6, 12, 24 or 36 months without activity, then up to 10 wallet addresses with a share each; the shares must add up to 100%. For someone without a wallet, choose a printed card instead of an address: the page makes a card with a key for them, and their share waits in the vault until they claim it. Anything you do on the holding counts as activity, and a check-in is one small transaction.
4. **A recovery sheet.** Recommended. Enter a recovery wallet, ideally a fresh address from a hardware wallet that has never signed anything, and never the wallet you are connected with. The page makes the sheet on your device: a secret, the recovery wallet, a QR code and plain instructions. Print it before going on. If you download it to print elsewhere, delete the file once it is on paper.
5. **Check and protect it.** The page restates everything in sentences, including the first date the holding could go to your people and the fee (below). Then up to three confirmations in your wallet: register the sheet, allow the vault to take the amount (only if needed; USDT asks twice when an old allowance is set), and open the holding. If one is interrupted, come back and it continues where it stopped.

## Straight from ETH: Stake & Shield

If you hold ETH and want it earning while it is protected, open **Stake & Shield** from Home and keep **Maximum protection** selected. Enter an amount: it is staked with Lido into wstETH in one transaction (or, if you already hold stETH or wstETH, you can use that instead). The page then continues straight into the steps above with sensible choices already made: a 30-day wait and your people after 12 months, both changeable before you confirm. wstETH keeps the same amount while its value in ETH grows with staking rewards, and your holding shows what it is worth in ETH today. Prefer instant access? **Keep it in my wallet** leaves the staked ETH in your wallet with a legacy backup instead, with no protection against theft.

## Using it

Your holdings show on the same page, with one main action each:

* **Check in** restarts the silence clock. With Premium it is free: you sign, and we send and pay for the transaction.
* **Add more** puts more of the same token in, under the same settings. It counts as a check-in.
* **Withdraw** starts the wait for an amount or for everything, to an address you choose. You can cancel it any time before it completes.
* **Change settings** (the wait, the people, the sheet) also waits the current delay, so a thief cannot shorten the wait or swap your people first.
* **Finish** appears when the wait is over. After that moment anyone can finish it, which is why a stop must come before the wait ends.

Each holding has a public status page, `app.10102.io/shield/1/<number>`, that family can open without a wallet to see what is waiting.

**Email alerts, free and optional.** Where they are available, the page offers to email you the moment a withdrawal or a change starts on any holding of your wallet, and weeks before a silence period runs out. It takes one signature and no transaction; the address is stored encrypted, used for nothing else, and you can delete it from the same place. Nothing requires it, and Cypherpunk Mode never asks.

## Stopping a withdrawal with the sheet

If a withdrawal or a change you did not ask for appears:

1. Open `app.10102.io/shield` on any phone or computer and choose **Stop it**, or use the button on the holding's status page.
2. Scan the QR code on the sheet with the page's camera button (it works on iPhone and Android alike, and the code is read on the device), or type the secret and the recovery wallet exactly as printed.
3. The page checks the sheet on your device first. A wrong sheet is refused there, costs nothing and never leaves the device.
4. Send it. The page sends it for free when it can; otherwise any wallet with a little ETH for the network fee will do, not only yours. Everything in the holding moves to the recovery wallet on the sheet, right away, and the holding closes. There is no undo.

A copied sheet cannot rob you: it can only send the holding to your own recovery wallet. It still ends the holding early, so keep it as safe as a key. The sheet works against a future quantum computer too, because it is a secret whose hash was registered in advance, not a signature from your key.

## If you made a quantum readiness sheet on Home

That older sheet and a Shield Vault recovery sheet are different things. The readiness sheet registered a dated proof that you owned your wallet before any quantum break; it moves nothing and stops nothing, and it cannot be used here. Keep it: the date is what it is worth. To protect coins now, open a holding and make its recovery sheet, which is tied to that holding, its recovery wallet and this contract. One sheet per holding.

## When you go silent

After the silence period passes with no activity, anyone can release the holding to the people you named, in their shares. If one share cannot be delivered (for example an address a token has blocked), it is kept for that address and can be claimed later from the status page; the others are paid anyway. Finishing a release costs the family nothing: the page sends it for free.

Someone named by a printed card opens `app.10102.io/shield/claim`, scans the card (or types what is printed on it) and enters the wallet the share should go to. The card's key signs on their device and never leaves it; no wallet, no ETH and no fee for the claim itself are needed.

## What you should know

* **It stays yours.** Only the wallet that opens a holding can withdraw from it. We cannot move it, pause withdrawals or change your settings. The governance Safe that owns the contract can only choose which tokens it accepts, pause new deposits, and set the fee for holdings opened later, never above 0.5%.
* **Three ways out, no others.** Your own withdrawal after the wait, your people after the silence period, or your recovery sheet to your recovery wallet.
* **The wait protects you only if you notice.** Turn on the email alerts if you like, check the page from time to time, and share the status page with family so they can watch too.
* **The vault pays no interest.** You get back exactly the tokens you put in. A token that grows by itself, like wstETH, keeps growing while it waits.
* **Reviewed, not yet audited.** The contract had two adversarial reviews before deployment and has not had an independent audit yet. It cannot be upgraded: a fix would be a new vault, and every holding can leave through its own wait.
* **Fees.** 0.25% of what leaves, when you withdraw or when it goes to your people, fixed for each holding when you open it. Stopping it with the sheet is always free, and so is claiming a share that was kept. Steps you send from your own wallet also pay the Ethereum network fee.

How it works underneath, with the threat model: [Quantum Readiness](/architecture/quantum-readiness).


# Architecture

How the whole system fits together: smart contracts on Ethereum, subgraphs on The Graph, and off-chain services for email and activity tracking.

10102 Computing Legacy is deliberately layered so that the **on-chain layer is self-sufficient**, and the **off-chain layer is strictly additive**. If the off-chain services disappeared tomorrow, every existing legacy and timelock would still function: you'd lose email reminders and the pretty UI, but you'd keep the plan.

```mermaid
flowchart TB
    subgraph OFF["3 · Off-chain conveniences (can fail without breaking the plan)"]
        direction LR
        W["Reminder worker<br/>emails · stats · upgrade-queue watch"]
        AT["Auto-renew attestor<br/>opt-in timer renewals"]
        RL["Sponsor relayer<br/>pays gas for signed intents"]
        MCP["Guardian MCP<br/>read-only agent tools"]
    end
    subgraph IDX["2 · Indexing (fast reads, never authoritative)"]
        G["Subgraph on The Graph"]
    end
    subgraph CHAIN["1 · On-chain: the plan itself (self-sufficient)"]
        direction LR
        R["Legacy & Timelock routers<br/>behind timelocked proxies"]
        L["Per-user legacy contracts<br/>EIP-1167 clones, isolated state"]
        V["LegacyPullVault + Permit2<br/>immutable permission rail"]
        S["Safe Guard & Module"]
    end
    UI["Web app / any Ethereum interface"] --> G
    UI --> CHAIN
    G -. indexes events .-> CHAIN
    W -. reads PII-free events .-> G
    AT -. bounded timer resets .-> R
    RL -. relays user-signed transactions .-> R
```

## The layers

### 1. On-chain: the core plan

Solidity contracts on Ethereum. Deployed behind upgradeable proxies administered by a `ProxyAdmin` that is owned by a public 48-hour upgrade timelock; see [Upgrade Policy](/architecture/upgrade-policy). Verified on Etherscan and published at [github.com/10102-io/computing-sc](https://github.com/10102-io/computing-sc).

* **Legacy routers**: `MultisigLegacyRouter`, `TransferLegacyRouter` (Safe owners), `TransferEOALegacyRouter` (plain EOAs).
* **Timelock router**: `TimeLockRouter`.
* **Per-user legacy contracts**: deployed deterministically via `LegacyDeployer` using `CREATE2`, so the address is predictable before deployment.
* **Safe integration**: a Safe Guard tracks last-activity timestamps; a Safe Module executes activation (adding owners or transferring assets).
* **Premium contracts**: `PremiumSetting` stores watcher/reminder configuration (addresses only; reminder emails live off-chain); `PremiumRegistry` records subscriptions; `PremiumReminderView` is a standalone read-only contract the reminder service polls for due reminder windows.

Full address list, for every deployed contract and network, lives in `contract-addresses.json` of the `computing-sc` repository.

### 2. Indexing: The Graph

A single subgraph per chain provides fast, reliable read access to the parts of the system that would be painful to query from raw RPC:

* **Legacy/timelock/reminders subgraph**: indexes every event emitted by the routers and 10102-enabled Safes: creations, edits, deletions, activations, reminder configurations, and the PII-free `LegacyEmailNotifyRequested` notify events (as `NotifyRequested`) that the off-chain reminder worker consumes. The UI reads the bulk of its state from here.

Everything else is direct on-chain. Token balances for the "your assets" pickers during legacy creation are fetched via viem against the canonical `TokenWhitelist` contract plus per-token ERC-20 `balanceOf` (`src/services/web3-assets-service.ts`). System-wide aggregates (total value locked across all legacies, timelocks and 10102-enabled Safes) are computed by the admin panel via `Multicall3` plus ERC-20 `balanceOf` / `allowance` walks against the entity set returned by the subgraph; see the `computing-admin` repository for the implementation.

The UI prefers subgraph reads for the indexed data but falls back to direct on-chain reads (via viem) for post-mutation freshness, so stale subgraph data never blocks a newly-valid action.

### 3. Off-chain services

Strictly additive layers that improve UX but can fail without breaking the plan:

* **Reminder worker**: an off-chain service (Railway + Postgres) that drives email reminder evaluation and delivery. It reads PII-free notify events from the subgraph plus a read-only on-chain "due" view (`PremiumReminderView`), keeps recipient emails encrypted off-chain, and sends through the mail service. This **replaces the retired Chainlink Automation cron and Chainlink Functions email path** (decommissioned on mainnet 2026-06-02).
* **Auto-renew attestor**: a dedicated key, run alongside the reminder worker, that serves EOA legacies whose owner has **opted in** to auto-renew (Premium): it observes the owner's public transaction count and resets the inactivity timer for them near the deadline, within strict on-chain bounds. It can only delay activation, never accelerate it. See [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).
* **Sponsor relayer**: accepts a user's signed EIP-712 intent (a beneficiary's claim, or an owner's check-in), submits the transaction, and pays the gas. All safety bounds are verified by the contract; relaying is permissionless. See [Gas-Sponsored Intents](/architecture/gas-sponsored-intents).
* **Guardian MCP**: a read-only [Model Context Protocol](https://modelcontextprotocol.io) service for AI agents: indexed legacy/timelock reads, portfolio health, and pre-filled setup links. See [Agents & Builders](/agents-and-builders).
* **Mailjet**: SMTP delivery for reminder emails, behind the 10102 mail proxy the worker posts to.
* **Public RPC providers + Etherscan**: fallback read paths the UI can switch to.

## Section index

* [Legacy Contracts Created with Safe SDK](/architecture/legacy-contracts-created-with-safe-sdk): how Multisig and Safe-backed Transfer legacies work, including the Safe Guard and Safe Module integration.
* [Legacy Contracts Created with EOAs](/architecture/legacy-contracts-created-with-eoas): how pure-EOA Transfer legacies work, including the approval model and CREATE2 deployment.
* [How Legacy Creation Works (v2)](/architecture/create-flow-v2): the one-transaction create (EIP-1167 clones, Permit2 permissions to the immutable `LegacyPullVault`, transaction-based consent, PII-free events).
* [New Account Generation for Beneficiaries](/architecture/new-account-generation-for-beneficiaries): client-side keypair generation for beneficiaries without an Ethereum address.
* [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking): how The Graph keeps the UI fast, and how the on-chain inactivity timers decide activation.
* [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew): the opt-in attestor that lets an EOA owner's general wallet activity renew their timer, with all safety bounds on-chain.
* [Gas-Sponsored Intents](/architecture/gas-sponsored-intents): how beneficiaries claim without holding ETH with signature-authorized intents, relayed and paid for by 10102.
* [Email Reminders](/architecture/email-reminders): the off-chain encrypted reminder-worker that sends out-of-band notifications (replacing the retired Chainlink path).
* [Upgrade Policy](/architecture/upgrade-policy): how contract upgrades work through a public, on-chain 48-hour queue that anyone can watch.

## A note on upgradeability

Every contract deployed by 10102 sits behind a transparent upgradeable proxy administered by a single `ProxyAdmin`, and that ProxyAdmin is owned by an on-chain **upgrade timelock**: no implementation can change without first sitting in a public queue for 48 hours, during which anyone can inspect the queued code and we can cancel. We can patch bugs and ship improvements. We *cannot* silently drain assets or retroactively alter an existing legacy's terms. Beneficiaries, owners, allocations, and activation windows are stored in per-legacy state that upgrades leave intact. The full commitment, including what is deliberately *not* timelocked and how to watch the queue yourself, is in [Upgrade Policy](/architecture/upgrade-policy).


# Legacy Contracts Created with Safe SDK

How Safe-owned legacies (Multisig and Transfer) integrate with an existing Safe via Safe Guards and Safe Modules, and how the lifecycle events flow.

A [Safe](https://app.safe.global) is a multi-signature smart account on Ethereum: a predefined threshold of owner keys is required to execute any transaction. 10102 integrates with Safe using the two extension points Safe exposes to third-party code: **Guards** and **Modules**.

* [Safe Guards](https://docs.safe.global/advanced/smart-account-guards): hooks that run on every transaction a Safe executes. 10102 uses a Guard to capture the timestamp of the Safe's last outgoing transaction.
* [Safe Modules](https://docs.safe.global/advanced/smart-account-modules): code that can execute transactions on behalf of the Safe without the usual multi-sig approval flow. 10102 uses a Module to execute the final activation action (transferring assets, or adding beneficiaries as owners) when the inactivity window elapses.

Two legacy flavors live on this path:

* **Multisig legacy**: hands over control of the Safe itself by adding beneficiaries as co-signers on activation.
* **Transfer legacy (Safe owner)**: transfers specific assets out of the Safe to beneficiaries on activation, proportional to configured allocations.

## Contract roles

| Contract                            | Purpose                                                                                                       |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `MultisigLegacyRouter`              | Creates and updates Multisig legacies. Enforces that edits come from the Safe itself (at threshold).          |
| `TransferLegacyRouter`              | Creates and updates Safe-owner Transfer legacies.                                                             |
| Per-legacy `MultisigLegacyContract` | Stores beneficiaries, activation trigger, name/note for a single Multisig legacy.                             |
| Per-legacy `TransferLegacyContract` | Stores beneficiaries, allocations, asset list, activation trigger for a single Safe-owner Transfer legacy.    |
| `SafeGuard`                         | Installed on the owner's Safe. Persists `lastTimestampTxs` on every Safe execution.                           |
| `SafeLegacyModule`                  | Installed on the owner's Safe. Empowered to execute the activation on behalf of the Safe at threshold-bypass. |

All of these live in the public [`computing-sc`](https://github.com/10102-io/computing-sc) repository; addresses are in `contract-addresses.json`.

## Creating a legacy from a Safe

### Step 1: Have a Safe

The user needs an existing Safe wallet. If they don't have one, they create it at [app.safe.global](https://app.safe.global) with their chosen signer set and threshold. 10102 does *not* deploy Safes on your behalf.

### Step 2: Connect and configure

1. The user connects to the 10102 app as a Safe (via WalletConnect or the Safe app embed).
2. They configure the legacy in the UI: beneficiaries, allocations (Transfer) or threshold-on-activation (Multisig), activation trigger (inactivity window), name/note.
3. The app builds a Safe transaction bundle containing:
   * `setGuard(SafeGuard)`: installs the 10102 guard on the Safe.
   * `enableModule(SafeLegacyModule)`: enables the 10102 module on the Safe.
   * `createLegacy(...)`: calls the appropriate router with legacy configuration.
4. The bundle goes through the Safe's normal multi-sig approval and execution flow: co-signers sign until threshold is reached, then it executes atomically.

### Step 3: On-chain effects

Once the bundle executes:

* The Safe emits `ChangeGuard` and `EnableModule` events. The subgraph indexes them and marks the Safe as 10102-enabled.
* The Router emits a `LegacyCreated` event (exact name varies by router; see the ABIs). The subgraph creates a legacy entity with the Safe address as creator, the beneficiaries, allocations / threshold, and activation trigger.
* `SafeGuard` initializes `lastTimestampTxs` to the creation block timestamp.

## Activity tracking (the happy path)

Every time the Safe executes *any* outgoing transaction (not just 10102 ones), the Safe's execution hooks call `SafeGuard.checkTransaction(...)`, which updates `lastTimestampTxs`. This is the entire "heartbeat" mechanism for Safe-owned legacies: no explicit check-in button needed, because normal Safe usage *is* the check-in. The UI also exposes an explicit `I'm still alive` action for owners who want a deliberate heartbeat.

Because the Guard lives *inside* the Safe, activity detection for Safe-owned legacies is fully on-chain and passive: every Safe transaction counts, with no oracle and no check-in chore. Pure-EOA legacies use a per-legacy timer instead; see [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking) for that story.

## Editing a legacy

Any Safe owner can initiate an edit (beneficiary changes, allocation changes, name/note, activation trigger). The edit is a normal Safe transaction and requires threshold signatures just like the creation. When it executes:

* The per-legacy contract's state is updated.
* The Router emits an `LegacyUpdated` event (name varies); the subgraph updates the entity.
* `SafeGuard.lastTimestampTxs` is updated by the underlying Safe execution, so edits implicitly reset the inactivity timer.

One asymmetry worth naming: **off-chain notification settings (watchers, email reminders) are managed by `PremiumSetting`, which gates those edits on the original creator EOA, not the Safe at threshold.** So any Safe owner can edit beneficiaries and activation triggers, but only the single EOA who submitted the original creation transaction can edit watchers or reminder configuration. This is tracked as a known asymmetry to resolve via a future `PremiumSetting` upgrade.

## Deleting a legacy

Delete is also a Safe transaction at threshold. The bundle includes:

* `deleteLegacy(...)`: tells the Router to tear down the per-legacy contract state.
* `setGuard(0x0)`: removes the 10102 guard from the Safe.
* `disableModule(SafeLegacyModule)`: removes the 10102 module from the Safe.

The Safe emits `ChangeGuard`, `DisableModule`, and the Router emits a `LegacyDeleted` event. The subgraph marks the legacy as deleted. The Safe is left in exactly the state it was in before creation: no residual permissions, no residual guards.

Users can also tear down manually via Safe's Transaction Builder at [app.safe.global](https://app.safe.global) (calling `setGuard(0x0)` + `disableModule(...)` on the Safe directly), which is the fallback path if the 10102 UI is ever unavailable.

## Activation: the endgame

When a beneficiary attempts to activate a legacy (via the app, via Safe, or via Etherscan using the [Legacy Claim Card](/user-guide/legacy/legacy-claim-card)), the Router checks:

1. The caller is one of the configured beneficiaries (primary, or contingent after their window elapses).
2. `block.timestamp - SafeGuard.lastTimestampTxs >= configuredInactivityWindow`.

If both checks pass, the Router invokes the `SafeLegacyModule` to execute the activation action on behalf of the Safe, bypassing the normal threshold, because the Module is pre-authorized for this one specific action and nothing else.

### Multisig legacy activation

The Module executes `addOwnerWithThreshold(beneficiary_i, newThreshold)` once per beneficiary, then `changeThreshold(configuredThreshold)` to the value the owner specified at creation. The Safe emits `AddedOwner` and `ChangedThreshold` events; the subgraph updates the Safe's owner set and records the legacy as activated. Post-activation, the Safe is now co-owned by the beneficiaries at the new threshold, and everything it holds, stakes, or governs is under their collective control.

### Transfer legacy (Safe owner) activation

The Module executes a series of `transfer` calls (ETH and ERC-20), moving the configured allocations out of the Safe to the beneficiary addresses. The per-legacy contract emits an `Activated` event; the subgraph marks it activated. The Safe itself is untouched (it just becomes lighter by the allocated amounts).

## Why this design

Keeping the Module strictly single-purpose (authorized only for the activation action, never for arbitrary transactions) preserves the security model of the Safe. No matter how badly the Module were compromised, it can only do the one thing the owner explicitly configured at creation. This is the same pattern Safe itself recommends for third-party integrations.


# Legacy Contracts Created with EOAs

How Transfer legacies work when the owner is a plain EOA (MetaMask, Ledger, Trezor, …) with no Safe involvement: clones, the single-transaction create, heartbeat, editing, deletion, and activation.

An **externally owned account (EOA)** is an Ethereum account controlled by a single private key, the wallet most people have in their browser or hardware device. EOAs have no on-chain code, which makes them elegant but creates one genuine constraint for legacy plans: **there is no built-in way for a smart contract to read an EOA's last outgoing transaction timestamp**. The 10102 EOA flow is shaped around that constraint.

This page describes the pure-EOA **Transfer legacy** path. Multisig legacies are Safe-only; Safe-backed Transfer legacies are covered in [Legacy Contracts Created with Safe SDK](/architecture/legacy-contracts-created-with-safe-sdk).

## Contract roles

| Contract                                  | Purpose                                                                                                                                                                                                                                                               |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TransferEOALegacyRouter`                 | Creates, edits, deletes, and activates EOA-owner Transfer legacies. Holds the address of the shared `TransferEOALegacy` implementation used by all clones.                                                                                                            |
| `LegacyDeployer`                          | CREATE2 factory. Deploys per-user legacy contracts to a deterministic address. For EOA legacies this deploys an EIP-1167 minimal proxy (\~45 bytes of on-chain code) that delegates to the shared implementation.                                                     |
| Shared `TransferEOALegacy` implementation | The actual contract logic. One deployment per network; every EOA legacy clone delegates to it.                                                                                                                                                                        |
| Per-legacy clone                          | A thin EIP-1167 proxy at a CREATE2-predictable address. Stores beneficiaries, allocations, included asset list, activation trigger, and last-activity timestamp in its own storage; executes shared code via `DELEGATECALL`.                                          |
| `LegacyPullVault`                         | Immutable, admin-free singleton that acts as the single Permit2 spender for all v2 creates. Holds a first-write-wins `owner → legacy` binding; only an owner's own bound legacy can pull their tokens. See [How Legacy Creation Works](/architecture/create-flow-v2). |

Routers are upgradeable behind transparent proxies (see the [Upgrade Policy](/architecture/upgrade-policy)). Per-legacy clones are *not* upgradeable at all: **each clone pins its implementation and its vault at creation time**. The router's `_codeAdmin` can point *new* clones at a new shared implementation, but existing clones keep the exact code they were created with, forever. An implementation swap is therefore a change to what gets created next, never a retroactive change to anyone's existing contract.

## CREATE2 for a predictable, auditable address

10102 uses `CREATE2` to make the legacy contract's address predictable *before* deployment. The address is derived from the deployer, a salt (the owner's EOA), and the initcode hash. Because every EOA legacy clone uses the same EIP-1167 initcode (parameterised only by the shared implementation address), the hash is stable across users and the address derivation is deterministic and auditable. This lets us:

* Show users the legacy address in the create form and have it match what actually gets deployed.
* Let beneficiaries verify the legacy address on Etherscan against a known pattern (every EOA legacy is a 45-byte EIP-1167 clone pointing at the published shared implementation address; easy to recognise once you've seen one).

The predicted address is deliberately *not* what users grant token permissions to. Permissions name the `LegacyPullVault`, one published contract every wallet can verify, rather than a per-user address that has no code at signing time. The reasoning is covered in [How Legacy Creation Works](/architecture/create-flow-v2).

## Why clones: the EIP-1167 refactor

Before the clone refactor, each EOA legacy was a full `TransferEOALegacy` deployment: \~6M gas per create, multiple dollars of mainnet fees at typical gas prices. Because every instance's code was byte-identical, paying to redeploy the same bytecode per user was pure waste.

Switching to EIP-1167 keeps the per-user storage isolation (each clone has its own state slots) while dropping the on-chain code to the \~45-byte forwarder stub. `createLegacy` now costs roughly 1.05M gas on mainnet, an 80%+ reduction. The mainnet cutover happened with Legacy #23 (the first clone-based creation); everything before that remains as an independently-deployed contract and continues to function normally.

The trade-off is that "bug in one user's legacy can't corrupt another's" now means *in storage*: the executable code is shared. In practice the shared implementation is a small, audited contract that does not touch the router's storage and has no mechanism to reach sibling clones, so the isolation guarantee we actually care about (one user's state is untouched by another's activity) is preserved. The `_codeAdmin`-controlled pointer lets us patch the shared logic for **new** creations; existing clones pin their implementation at creation and are never affected by a swap. The cost of that immutability is honest too: a bug in the implementation stays with the clones created from it (see the [Upgrade Policy](/architecture/upgrade-policy) for how we handle that).

## Creating an EOA legacy

Creation is a single transaction, `TransferEOALegacyRouter.createLegacyV2(...)`, that deploys the clone, registers the owner's Permit2 token permissions with the `LegacyPullVault` as spender, and records the owner's terms consent, atomically. The full mechanics (Permit2, the vault, transaction-based consent, PII-free events) have their own page: [How Legacy Creation Works](/architecture/create-flow-v2). In outline:

1. The user configures beneficiaries, allocations, activation trigger (inactivity window in days), and included assets in the UI. Names and notes stay on the user's device; they are not transaction inputs.
2. The user signs one gas-free Permit2 batch covering the included ERC-20s, then submits `createLegacyV2(...)`.
3. The Router deploys the clone via `LegacyDeployer` with a deterministic salt (CREATE2, so the address matches the prediction shown in the UI), registers the Permit2 batch, binds the owner to the new legacy in the vault, and records consent against the published terms hash.
4. The Router emits the (PII-free) create event. The subgraph creates the legacy entity.
5. The per-legacy contract initializes `lastActivityTimestamp` to the creation block.

A legacy contract holds *rules*, not custody, with one small exception for ETH:

* **ERC-20**: covered by the Permit2 permission signed at create. Tokens stay in the owner's wallet; on activation the claim path pulls *only what the permission covers, only on activation*. Tokens can also be added later with a small on-chain Permit2 approval.
* **ETH**: ETH cannot be permissioned like an ERC-20. The owner swaps ETH for a supported storage token (WETH, a liquid staking token) via the in-app Uniswap integration, and the resulting token is permissioned as above. This keeps the contract's permission surface uniform across assets.

The owner can add or remove assets at any time before activation; removal means revoking the token's permission (directly in the wallet via Permit2, or `approve(0)` for pre-v2 direct approvals), or deleting and recreating the legacy.

## Heartbeat (reset activation timer)

Because the EOA has no on-chain code to hook into, the per-legacy contract tracks its own `lastActivityTimestamp`. Two things reset it:

* **Explicit heartbeat**: the owner clicks `I'm still alive` in the UI, which submits a tiny transaction to the Router. Cheap, unambiguous, on-chain.
* **Edit**: any on-chain edit to the legacy (beneficiaries, allocations, trigger) resets the timestamp as a side effect, because the edit is itself an outgoing transaction from the owner's EOA.

*Not* a heartbeat: arbitrary transactions from the owner's EOA that don't touch the legacy. The per-legacy contract has no way to see those, and there is **no oracle that fills the gap**: activity tracking is exactly "interactions with this legacy," nothing more. This is the deliberate trade-off of the EOA path: a fully on-chain inactivity timer with no external dependency, in exchange for the owner having to check in if they aren't otherwise editing the legacy. See [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking) for how this compares to the Safe path.

## Editing

Edits are single-EOA transactions, not multi-sig, so they're instant:

* Any field can change: beneficiaries, allocations, activation trigger, asset list. (Names and notes are stored on the owner's device and change without a transaction.)
* The Router emits an `LegacyUpdated` event; the subgraph refreshes the entity.
* `lastActivityTimestamp` is reset as a side effect of the outgoing transaction.

There's no notion of "co-signers need to approve the edit"; the whole point of an EOA legacy is that the owner has sole authority.

## Deleting

`TransferEOALegacyRouter.deleteLegacy(...)` does three things atomically at the protocol level, with an optional revoke loop at the UI level:

1. Marks the legacy as deleted in the Router + per-legacy contract, and **releases the owner's binding in the `LegacyPullVault`**: after this, the Permit2 permissions signed at create can no longer be used by anything. The subgraph updates the entity status.
2. Returns any ETH held *inside* the per-legacy contract (there's a small amount of dust possible from storage-token mechanics) to the owner.
3. For **pre-v2 legacies** that were set up with direct ERC-20 approvals, the UI then walks the owner through a sequence of `approve(legacyContract, 0)` calls (one per token with a live allowance) to revoke spender permissions. This is best-effort; a partial success still leaves the legacy deleted.

Empty legacies (no tokens ever approved) skip the revoke loop entirely. The revoke loop is strictly a "for your protection" cleanup; the deleted legacy contract can no longer pull tokens anyway, but dangling approvals are a general hygiene problem worth fixing. v2 owners who want zero residue can additionally clear the Permit2 allowance entries from their wallet (Permit2 supports mass revocation via `lockdown`).

## Activation

Activation is a single transaction any beneficiary can submit:

1. Beneficiary calls `TransferEOALegacyRouter.activeLegacy(legacyId, ...)` from an address matching one of the configured beneficiaries (primary, or a contingent whose window has elapsed).
2. The per-legacy contract evaluates the activation trigger entirely on-chain (`_lastTimestamp + lackOfOutgoingTxRange <= block.timestamp`), with no external call. There is no oracle and no off-chain activity lookup: the only "activity" the contract considers is the owner's interactions with this legacy (see [Heartbeat](#heartbeat-reset-activation-timer) above). If the owner hasn't touched the legacy for the configured window, the claim is allowed; otherwise it reverts.
3. If the check passes, the Router iterates the allocations and moves each (asset, beneficiary) amount from the owner's EOA, per token, through the most generous rail available to that legacy: a direct ERC-20 allowance (pre-v2), a Permit2 permission naming the legacy itself, or a Permit2 permission through the `LegacyPullVault` (v2). Every generation of legacy stays claimable without migration.
4. The Router emits an `Activated` event; the subgraph marks the legacy activated.

Batches over 100 transfers are executed in chunks, with the remaining distribution callable via a `Claim Remaining Fund` follow-up; see the user guide for the beneficiary-side flow.

## No external dependency at activation

EOA activation has no off-chain dependency: the eligibility decision is a single on-chain comparison inside the per-legacy contract, so it works even if our app, backend, or indexer are entirely down. The flip side is that the inactivity timer is only ever reset by the owner's own interactions with the legacy; there is no oracle watching the owner's broader wallet activity. An owner who is active elsewhere but never touches the legacy will still see the timer count down, which is why the [heartbeat](#heartbeat-reset-activation-timer) exists. Safe-owned legacies get a softer version of this: their Safe Guard records activity on every Safe transaction, so normal wallet use keeps the legacy fresh automatically.

## Why split EOA and Safe paths at the contract level

The two flows share 80% of their semantics, but the 20% that differs (how activity is tracked, who can authorize edits, how activation executes) is different enough that conflating them would force both paths to carry the other's complexity. Two thin routers with clear contracts are easier to audit and easier to upgrade in isolation.


# How Legacy Creation Works (v2)

Why creating an EOA legacy is a single wallet confirmation: EIP-1167 clones, Permit2 permissions to one immutable vault contract, no personal data on-chain, and consent recorded by the transaction its

Creating a Transfer legacy from an EOA wallet used to take three to five wallet interactions: sign an agreement message, send a deploy transaction, then send one `approve` transaction per included token. Today it is **one transaction**. This page explains the architecture that made that possible without weakening anything a user could previously verify, and the trade-offs we accepted along the way.

## The flow at a glance

|                     | Before                                                     | Now (v2)                                                                          |
| ------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Agreement to terms  | Separate signed message                                    | Recorded by the create transaction itself                                         |
| Contract deployment | One transaction                                            | Same single transaction                                                           |
| Token permissions   | One `approve(legacyAddress)` transaction per token         | One gas-free Permit2 signature, registered inside the create transaction          |
| Permission target   | Your freshly-deployed legacy contract (unknown to wallets) | One published, immutable, Etherscan-verified vault, the same address for everyone |
| Names and notes     | Stored on-chain                                            | Stored on your device; never on-chain                                             |

The single on-chain call is `TransferEOALegacyRouter.createLegacyV2`. In one transaction it deploys your legacy contract as an EIP-1167 clone at a CREATE2-predicted address, registers your signed Permit2 token permissions, and records your consent to the current terms.

```mermaid
sequenceDiagram
    autonumber
    participant O as Owner's wallet
    participant R as TransferEOALegacyRouter
    participant D as LegacyDeployer<br/>(CREATE2)
    participant P as Permit2
    participant V as LegacyPullVault<br/>(immutable singleton)
    O->>O: Sign one gas-free Permit2 batch<br/>covering the included tokens
    O->>R: createLegacyV2(config, permit batch, consent)
    R->>D: Deploy EIP-1167 clone<br/>at the predicted address
    R->>P: Register the permit batch<br/>spender = LegacyPullVault
    R->>V: Bind owner → new legacy<br/>(first write wins)
    R->>R: Record terms consent, emit PII-free event
    R-->>O: One confirmation: legacy is live,<br/>tokens never left the wallet
```

## EIP-1167 clones: pay for state, not code

Every EOA legacy has identical logic and unique state, so deploying the full contract bytecode per user was pure waste. Each legacy is instead a \~45-byte [EIP-1167](https://eips.ethereum.org/EIPS/eip-1167) minimal proxy that delegates to one shared, published implementation, cutting creation gas by 80%+ (roughly 6M → 1.05M on mainnet) while keeping its own isolated storage (beneficiaries, allocations, trigger, timestamps).

Crucially, **each clone pins its implementation and its vault at creation time**. When we ship a new implementation, it applies to new creations only; your existing contract keeps the exact code it was created with, forever. (An earlier design let existing clones follow a router-held pointer; that is no longer the case.) See the [Upgrade Policy](/architecture/upgrade-policy) for the full picture of what can and cannot change.

## Permit2 + LegacyPullVault: one spender everyone can verify

The hard problem in a one-transaction create is token permissions. Arbitrary ERC-20s don't support gasless approvals natively, so we use [Permit2](https://github.com/Uniswap/permit2), Uniswap's audited, immutable permission contract deployed at the same address on every major chain and shared by much of the ecosystem. At create time you sign one EIP-712 message covering all your included tokens; `createLegacyV2` registers that batch with Permit2 inside the create transaction. Your tokens never move; Permit2 just records that a specific spender may pull them under your signed limits.

**Who is that spender?** Not your legacy contract. At the moment you sign, your legacy contract doesn't exist yet (it's deployed later in the same transaction), and wallets rightly treat a permission naming a code-less address as a drainer fingerprint. A per-user counterfactual address can never be allowlisted, verified, or rendered by name in a wallet.

So the spender is the **LegacyPullVault**, a singleton contract that is:

* **Immutable and admin-free.** No owner, no upgrade path; its behavior was frozen at deployment. On mainnet it lives at [`0x95F0981026C7e804fD6ba8bE738cA7c380C7f978`](https://etherscan.io/address/0x95F0981026C7e804fD6ba8bE738cA7c380C7f978), Etherscan-verified.
* **Codehash-pinned.** The vault only accepts bindings for genuine legacy clones: it checks the EIP-1167 codehash against the exact implementation it was deployed for. A contract with any other code can never bind.
* **First-write-wins.** The create transaction binds your address to your new legacy inside the vault. While that binding is live, it cannot be re-pointed, not even by a router upgrade. Only your own bound legacy can pull your tokens, only through Permit2's per-owner accounting, only within what you signed.
* **Released on delete.** Deleting your legacy clears the binding, after which nothing can pull through the vault for your address.

One stable spender address is what lets wallets show you a consistent, checkable permission request instead of a red warning, and what makes registrations with wallet-security providers and clear-signing descriptors possible at all.

## What the permission actually says

Two properties of the signed Permit2 batch are deliberately broad, and worth stating plainly:

* **The amount is unlimited** (Permit2's maximum). The actual amounts beneficiaries receive are decided by your allocations and your wallet balance at activation: the permission is a ceiling, not a transfer. An itemized amount would go stale the moment you moved funds.
* **The expiration is far in the future** (on the order of decades). A legacy must remain claimable years after you can no longer re-sign anything. A short expiry would silently break the product's core promise.

Both are revocable at any time: delete the legacy, or use Permit2's own `lockdown` / per-token revocation directly from your wallet; no 10102 infrastructure required.

## PII-free events, consent in the transaction

* **Nothing personal goes on-chain.** v2 removed names, nicknames, and notes from legacy storage and events. On-chain there are addresses, percentages, and timing. Nothing else. Your legacy's name and your beneficiaries' names are stored on your device (browser local storage), which also means they don't follow you to a new browser unless you re-enter them.
* **Consent is transaction-based.** The terms you accept are published on-chain as a version tag plus a content hash. When you create with the terms checkbox ticked, the create transaction records your consent bound to that exact document hash: wallet-attributable, timestamped, and version-bound, with no separate message-signing ceremony. (The older signed-message path still exists for Safe flows and older frontends.)

## What happens on delete

* **v2 legacies:** the delete transaction releases the vault binding, which disables the Permit2 permissions: no contract can pull through the vault for your address afterwards. For belt-and-suspenders you can also clear the underlying Permit2 entries from your wallet.
* **Pre-v2 legacies** (created with direct ERC-20 approvals): those approvals keep working for the life of the legacy, and the delete flow walks you through revoking each one (`approve(0)` per token).

At claim time, a legacy pulls each token through the most generous rail available to it (a direct ERC-20 allowance, a Permit2 permission naming the legacy itself, or a Permit2 permission through the vault), so every generation of legacy stays claimable without migration.

## The honest trade-offs

* **The vault is shared by every user.** A bug in it would be a bug for everyone. We accepted this because the vault is tiny (\~1.5 KiB), immutable, and structurally narrow: it can only forward pulls from an owner's own bound legacy, through Permit2's per-owner signed envelope. The alternative, per-user spenders, is precisely what wallets cannot verify.
* **Permit2 is a trust assumption.** If Permit2 itself had a critical flaw, every token approved to it by any app would be exposed. It is immutable, extensively audited, and carries a large share of ecosystem flow; we accept this on par with using major DeFi infrastructure at all.
* **A narrow admin capability remains.** The role that rotates the clone implementation for *new* creates could, in theory, bind a legacy to an address that has **no** live binding. It can never re-point an existing live binding, and the same role could already change what new creates deploy, so the vault doesn't widen the admin trust surface. That role's upgrade powers now sit behind the public 48-hour queue described in the [Upgrade Policy](/architecture/upgrade-policy).
* **One extra transaction can still appear.** The first time a wallet uses a given token with Permit2 (in any app), a one-time `approve(Permit2)` transaction is required. It amortizes across the whole Permit2 ecosystem, but it's not zero.

## Related pages

* [Legacy Contracts Created with EOAs](/architecture/legacy-contracts-created-with-eoas): the full EOA legacy lifecycle (heartbeat, editing, activation).
* [Upgrade Policy](/architecture/upgrade-policy): what can change, who can change it, and how to watch.
* [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract): the user-facing walkthrough.


# New Account Generation for Beneficiaries

How the app generates an Ethereum keypair for a beneficiary who doesn't already have one, entirely in the browser, and why we never see the private key.

Not every intended beneficiary has an Ethereum address. For a will-like flow to be useful to everyday humans, the app needs a way to produce a fresh Ethereum account for a beneficiary without degrading the security model. 10102 does this with **client-side keypair generation**: the private key is created in the owner's browser, printed onto the [Legacy Claim Card](/user-guide/legacy/legacy-claim-card) as a QR code, and *never* leaves the owner's device.

<figure><img src="https://3623842229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fw65pHuXHWcWv8OoljdYD%2Fuploads%2Fgit-blob-40c14a0bddc31986f5d0affef4f85d4ea0ac80ed%2FScreen%20Shot%202024-12-20%20at%203.08.40%20PM.png?alt=media" alt=""><figcaption><p>Optional "Generate a new address" flow during beneficiary configuration. The QR code is downloaded directly to the owner's device.</p></figcaption></figure>

## The mechanics

Ethereum accounts are not registered anywhere; they are simply derived from random entropy. The app uses the standard client-side crypto that every major Ethereum wallet uses:

1. **Random entropy**: the browser's `crypto.getRandomValues()` (a WebCrypto primitive backed by the OS CSPRNG) produces 256 bits of random data. This is the same entropy source MetaMask and hardware wallets rely on for key generation.
2. **Private key**: those 256 bits *are* the private key, represented as a 64-character hex string.
3. **Public key**: derived from the private key via elliptic-curve multiplication on the `secp256k1` curve. This is a one-way operation: you can get the public key from the private key, never the reverse.
4. **Ethereum address**: the last 20 bytes of the Keccak-256 hash of the public key, checksummed per EIP-55.

The whole derivation takes milliseconds and runs synchronously in the browser.

## Custody model: the owner's responsibility

At no point in this flow does 10102 (the company, the app's backend, the smart contracts) see or touch the private key. It exists only:

* In volatile memory in the owner's browser, for the duration of the key-generation step.
* Printed as a QR code on the Legacy Claim Card the owner downloads / prints.
* Wherever the owner physically stores that card afterwards.

The owner is fully responsible for delivering the printed key to the beneficiary through whatever out-of-band channel they trust: sealed envelope with their estate lawyer, safe deposit box, encrypted message, physical handover. The app's job ends when the PDF is generated.

This is the same trust model as a hardware-wallet seed phrase: the chain of custody is physical and human, not digital and automated. That's a feature, not a limitation: it means there's no single digital attack surface for "steal all legacy private keys at once."

## How the beneficiary uses it

At claim time, the beneficiary has two paths:

* **Via the 10102 app**: scan the QR code with the app's import flow, which writes the key into a freshly-generated WalletConnect-compatible session. From there they activate the legacy like any other beneficiary.
* **Via any Ethereum wallet**: scan the QR with MetaMask Import, Rainbow, or a hardware wallet's recovery flow. Then use the legacy's contract address (also on the Legacy Claim Card) via Etherscan's "Write Contract" tab to call the activation function directly. No 10102 UI required.

See [Legacy Claim Card](/user-guide/legacy/legacy-claim-card) for the printable artifact and the claim instructions it carries.

## Known limits

* **Printed keys are hot keys.** Once printed, anyone with physical access to the card has the funds. Treat claim cards like cash.
* **Single-key security.** Generated accounts are EOAs with a single key: if the key is lost before claim, the transferred funds are unrecoverable. A beneficiary who is crypto-comfortable should ideally bring their own address instead of using the generated one.
* **No recovery.** There is no recovery service. The app does not store a copy. This is intentional; a custodial copy would be a honeypot.

If any of these feel wrong for a given legacy, the answer is to use a real beneficiary address (e.g. a Safe they control) instead of a generated one. The generated-account path is a convenience for beneficiaries who wouldn't otherwise have an address at all, not a recommendation for high-value plans with crypto-savvy recipients.


# Indexing & Activity Tracking

Subgraphs on The Graph keep the UI fast; activity tracking is an on-chain inactivity timer, different for Safe and EOA owners, with an optional attested auto-renew path for EOAs.

Two distinct problems sit under one banner here:

1. **Indexing**: reading structured data out of on-chain events quickly. Solved with [The Graph](https://thegraph.com).
2. **Activity tracking**: knowing whether an owner has been inactive long enough to trigger activation. The activation decision itself is entirely on-chain: a Safe Guard for Safe owners, and a per-legacy inactivity timer for EOA owners. EOA owners can additionally opt in to [auto-renew](/architecture/eoa-activity-auto-renew), where an attestor resets the timer for them within strict on-chain bounds.

The indexing layer is strictly additive: the on-chain contracts are authoritative, and the UI falls back to direct RPC reads when the indexed layer is stale or unavailable. The activation decision never depends on it.

> **Retired:** earlier drafts of this product described EOA activity tracking as a "Chainlink Functions + Moralis hybrid" that bridged an off-chain check of the owner's wider wallet activity back on-chain. That mechanism is **not in use** (the Chainlink Automation/Functions integration was retired and its subscriptions cancelled on mainnet and Sepolia). Its successor is the strictly opt-in [auto-renew attestor](/architecture/eoa-activity-auto-renew), a much narrower mechanism whose safety bounds live in the contract, not in an oracle network. Without opting in, EOA activation relies solely on the on-chain inactivity timer described below.

## Subgraphs on The Graph

We maintain a single subgraph per chain:

* **Legacy + timelock + reminders subgraph**: indexes every event emitted by the routers: `LegacyCreated`, `LegacyUpdated`, `LegacyDeleted`, `Activated`, `TimelockCreated`, `ReminderConfigured`, plus the Safe's own `ChangeGuard` / `EnableModule` / `AddedOwner` / `ChangedThreshold` for 10102-enabled Safes. The UI reads the bulk of its state from here.

Earlier versions also ran a separate "token balance" subgraph for the "your assets" pickers during legacy creation, and an "ETH totals" subgraph for system-wide aggregate metrics. Both were retired in v2026.05.15 once the equivalent reads were moved on-chain:

* Token balances are now fetched via viem against the canonical `TokenWhitelist` contract plus per-token ERC-20 `balanceOf` (`src/services/web3-assets-service.ts` in `computing`).
* System-wide TVL is computed by the admin panel, which walks the legacy/timelock subgraph for the entity set and then reads balances directly via `Multicall3.getEthBalance` plus per-token ERC-20 `balanceOf` / `allowance`.

The remaining subgraph stays narrow, indexing time stays bounded, and freshness-critical reads bypass it entirely.

### Mainnet and Sepolia

Every subgraph is deployed on both mainnet and Sepolia. Deployment IDs and endpoint URLs are configuration; the app picks the right set based on the connected chain.

### Freshness and the on-chain fallback

Subgraphs are eventually-consistent. After a transaction is mined, it typically takes a handful of blocks for an event to appear in subgraph responses. During that window, the UI cannot trust "legacy not found in subgraph" as ground truth: a legacy that was just created would be falsely reported as nonexistent.

The app handles this in two places:

* **Post-mutation freshness**: hooks like `useHasExistingLegacy` do a direct on-chain `readContract` call via viem with `blockTag: 'latest'` immediately after a mutation, so the UI state reflects the latest mined state without waiting for the subgraph.
* **Retry loop**: if an on-chain read returns an unexpected state (for example, the legacy still appears after a deletion), the hook retries a few times with short backoffs to let the node catch up.

The net result: subgraphs give us speed, and on-chain reads give us correctness when speed isn't enough.

## Activity tracking

Solidity cannot directly read "the timestamp of `wallet.address`'s most recent outgoing transaction." The EVM doesn't expose it. So instead of trying to observe an owner's *general* wallet activity, both legacy paths track an activity timestamp that the contracts can update natively; the difference is only in *what* counts as activity.

### Safe owners: the Safe Guard

A smart-contract wallet can track activity internally. When the owner is a Safe, we install a **Safe Guard** (see the [Safe Guard integration](/architecture/legacy-contracts-created-with-safe-sdk)) that records the timestamp of every Safe transaction. Any normal Safe activity (DeFi, staking, voting) implicitly keeps the legacy fresh, with no deliberate check-in. At activation time the Router reads that timestamp directly from the Guard and compares it against the configured inactivity window. Fully on-chain, no oracle.

### EOA owners: a per-legacy inactivity timer

A plain EOA has no on-chain code to hook into, so an EOA legacy tracks activity on the only surface it controls: **itself**. Each EOA legacy stores a `_lastTimestamp` (last-activity timestamp) and a `lackOfOutgoingTxRange` (the configured inactivity window). The eligibility check is a single on-chain comparison with no external call:

```solidity
// TransferEOALegacy._checkActiveLegacy()
if (_lastTimestamp + lackOfOutgoingTxRange > block.timestamp) {
  return false; // still considered active, activation not allowed
}
return true;     // inactive long enough, eligible
```

`_lastTimestamp` is reset to `block.timestamp` by any owner interaction with the legacy: creation, edits (beneficiaries / allocations / trigger / name), withdrawals, the auto-swap / unswap helpers, receiving ETH directly from the owner, or the explicit `activeAlive` ("I'm still alive") heartbeat. A beneficiary then activates permissionlessly via `TransferEOALegacyRouter.activeLegacy(legacyId, ...)`, and the contract itself decides whether the window has elapsed.

The deliberate limitation: arbitrary transactions the owner makes *elsewhere* are invisible to the per-legacy contract. By default, nothing bridges that information in: an EOA owner who is active on-chain but never touches their legacy will still see the timer count down, which is exactly why the heartbeat exists.

For owners who want their general wallet activity to count, there is one deliberate, opt-in exception: **auto-renew** (Premium). An attestor service observes the owner's public transaction count and calls the router to reset the timer when the owner has been active near the deadline. Every safety bound is on-chain (attestor-only entry point, opt-in required, strictly increasing nonce, a 30-day near-deadline window, and a 365-day budget since the owner's last real check-in), so a compromised attestor can only *delay* activation (bounded), never accelerate it or touch funds. Full mechanics and trust model: [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).

### Trust and verification

* **The contract is authoritative and self-contained.** Both paths reduce activation to an on-chain timestamp comparison. Nothing off-chain can fabricate a "yes, activate" signal or block a legitimate activation.
* **No external party can trigger or accelerate activation.** There is no oracle network or third-party API in the activation path. The only off-chain writer anywhere near the timer is the opt-in [auto-renew attestor](/architecture/eoa-activity-auto-renew), and it can only *reset* the timer (i.e. delay activation) within on-chain bounds; it has no power to make a legacy claimable earlier, and it never touches legacies that haven't opted in.

### Failure modes

Because activation is purely on-chain, an outage of our app, backend, or the subgraph has **no effect on the ability to activate**: a beneficiary can call the router directly. The realistic EOA failure mode runs the other way: the owner forgets to check in and the timer elapses while they're still alive. That is recoverable (they heartbeat or edit to reset it), whereas a premature disbursement would not be. So by default the timer only ever resets on the owner's own deliberate, on-chain interactions, and even the opt-in auto-renew path can only err in the recoverable direction (a bounded delay, never an early activation).

## What this means operationally

* Activation never waits on us. There is no activity oracle to be "down," and no subscription that can run dry and block a claim.
* The off-chain pieces that *do* exist around the legacy (the [reminder worker](/architecture/email-reminders), the [auto-renew attestor](/architecture/eoa-activity-auto-renew), and the subgraph) are conveniences only, and all of them fail safe. If the attestor stops, renewals pause and reminder emails take over; if the worker or subgraph degrades, owners may miss a nudge or the UI may lag. Correctness and the ability to claim are unaffected in every case.
* Moving toward "every wallet is a smart wallet" (EIP-4337 account abstraction) would let EOA owners get the same passive, broad activity tracking Safe owners enjoy today; we expect to add an AA-specific integration once such wallets standardize a way to expose it.


# EOA Activity & Auto-Renew

How opt-in auto-renew lets an EOA legacy follow your real wallet activity: an off-chain attestor observes your transaction count, and every safety bound is enforced on-chain, so the worst failure is a

An EOA legacy's inactivity countdown normally resets only when the owner interacts with the legacy itself: an edit, a deposit, a withdrawal, or the explicit heartbeat. Ordinary wallet activity (a send, a swap somewhere else on-chain) is invisible to the legacy contract, because the EVM gives a contract no way to read another account's transaction history. Active owners still had to remember to check in.

**Auto-renew** closes that gap for owners who want it: an attestor service watches your wallet's public transaction count (its nonce), and when it sees you've been active near your deadline, it renews the timer for you: no email, no click, no gas from you. It is a Premium feature, strictly opt-in per legacy, and off by default.

This page explains how it works and, more importantly, exactly what the attestor can and cannot do, because "a service watches your wallet" is a claim that deserves scrutiny.

## The shape

* **The attestor is off-chain; the rules are on-chain.** A dedicated key held by our reminder service polls the owner's transaction count. When the count has risen and the legacy is near its activation deadline, the attestor calls `recordActivity(legacyId, observedNonce)` on the EOA legacy router. The router resets the legacy's inactivity timer exactly as an owner check-in would.
* **Router-only.** The mechanism lives in the upgradeable router, not in the per-legacy contracts, so it covers every existing EOA legacy with zero changes to deployed legacy contracts.
* **The attestor only ever attests.** It holds no funds, has no claim rights, and its only entry point is the timer reset described here.

## The on-chain bounds

Every safety property is enforced by the contract, not by the attestor behaving well. A buggy or malicious attestor gets a loud revert, not a silently shifted timeline.

| Bound                         | What it enforces                                                                                                                                                                                                                                                                                                                                 |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Opt-in only**               | You enable it per legacy with `setAutoRenew(legacyId, enabled)`: owner-only, Premium-gated, default off. Premium is re-checked at every renewal; if your subscription lapses, renewals pause and reminder emails take over. Disabling is always allowed, Premium or not.                                                                         |
| **Strictly increasing nonce** | Each attestation must cite a higher transaction count than the last one recorded. An old observation can never be replayed, not even across disable/re-enable toggles.                                                                                                                                                                           |
| **Near-deadline window**      | Attestations only land within 30 days of the activation deadline, and never at or after it. That means roughly one renewal per inactivity period, and a legacy that has already become claimable can never be re-armed by an attestation: the claim window belongs to the beneficiaries, and only your own check-in can recover a lapsed legacy. |
| **365-day budget**            | Renewals stop 365 days after your last *real* check-in. Attested renewals deliberately do not refill this budget: the attestor can't extend its own leash. When the budget runs out, reminder emails ask you to check in yourself, which refills it.                                                                                             |

Enabling also fails loudly when the feature could never fire: on a deleted legacy, or when the configured inactivity window is so long (past roughly 395 days) that the renewal window would only ever open after the budget was already spent.

## The trust model, honestly stated

A fully compromised attestor key can only **delay** activation: never accelerate it, never claim, never move funds, never touch a legacy that hasn't opted in, and never re-arm a legacy that is already claimable.

Stated precisely: the last renewal a compromised attestor can land is up to 12 months after your last real check-in, and activation then follows one further full inactivity period. So the worst-case delay is **12 months plus one inactivity period** past the natural deadline, about 15 months for a 90-day trigger. Bounded, and recoverable by you at any time.

Known edges, stated out loud:

* **Disable front-running.** An attestor watching the mempool could front-run your `setAutoRenew(id, false)` with one final renewal. That is bounded to a single period, and your disable still lands.
* **Nonce poisoning.** A malicious attestor could record an absurdly high nonce, permanently breaking auto-renew for that legacy. This fails *safe*: renewals stop, reminder emails take over, and activation proceeds on schedule. We accepted this rather than adding an owner-callable nonce reset, which would weaken the replay protection for a pure availability gain in an already-compromised scenario.
* **The kill switch.** The contract admin can rotate the attestor key or zero it entirely. Zeroing pauses all renewals system-wide without touching any owner's opt-in state. And because the router sits behind the timelocked upgrade process, the bounds themselves can't be quietly changed; see [Upgrade Policy](/architecture/upgrade-policy).

The consent summary we show at opt-in is the same claim: *we watch this wallet's public transaction count and renew for you when you're active; after 12 months of renewals we ask you to check in yourself. If our systems were ever compromised, the worst possible outcome is your beneficiaries' claim being delayed, never redirected, never accelerated.*

## How it interacts with reminders

Auto-renew and [email reminders](/architecture/email-reminders) are designed to hand off to each other:

* If renewals stop for any reason (budget exhausted, Premium lapsed, attestor paused, or you raised your inactivity window past the feasibility limit), reminder emails take over and ask you to check in.
* An attested renewal is **not** treated as proof that you're reachable. Renewals emit a dedicated on-chain event distinct from a real check-in, and the reminders that ask you to "check in for real" as the budget runs down are never suppressed by attested renewals.

## Verify it yourself

* The EOA legacy router (mainnet proxy): [`0x4E81E1Ed3F6684EB948F8956b8787967b1a6275b`](https://etherscan.io/address/0x4E81E1Ed3F6684EB948F8956b8787967b1a6275b). Read `activityAttestor()` to see the current attestor (the worker key, `0x4B05aC1b0BF109A9CE30dCEc2831990d694d74D0`), and watch the `TransferEOALegacyAutoRenewed` event for every attested renewal.
* Every bound above is in the verified router source on Etherscan; nothing depends on the attestor's off-chain code being correct.
* Without opting in, nothing changes for you: your legacy's timer resets only on your own interactions with it, exactly as described in [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking).


# Gas-Sponsored Intents

How beneficiaries claim without holding any ETH: signature-authorized intents the contract verifies on-chain, relayed and paid for by 10102.

The hardest moment in an inheritance product is the claim: the beneficiary is often new to Ethereum, holding a freshly generated wallet with a balance of exactly zero, and an on-chain claim costs gas. Gas-sponsored intents close that gap: **the beneficiary signs a free message, and 10102 submits the transaction and pays the fee.** The same mechanism lets an owner reset their inactivity timer without paying gas.

## The one-sentence version

**You sign an EIP-712 authorization (free); any relayer (normally ours) can submit it, but the contract only ever acts as the signer, for the signer.**

## How it works

```mermaid
sequenceDiagram
    autonumber
    participant B as Beneficiary<br/>(no ETH needed)
    participant A as 10102 app
    participant R as Relay service
    participant C as EOA legacy router<br/>(on-chain)
    B->>A: Start claim
    A->>B: Request free EIP-712 signature<br/>(ClaimAuth: legacy id, asset list, nonce, deadline)
    B->>A: Signed authorization
    A->>R: Forward signed intent
    R->>C: Simulate, then submit activeLegacyFor(...)<br/>relayer pays the gas
    C->>C: Verify signature, nonce, deadline,<br/>asset hash, then act as the signer
    C-->>B: Assets distributed per the owner's allocations
```

The EOA legacy router exposes signature-authorized twins of its two identity-bound entrypoints:

| Direct call (you pay gas)      | Sponsored twin (relayer pays gas) | Who signs       |
| ------------------------------ | --------------------------------- | --------------- |
| `activeLegacy` (claim)         | `activeLegacyFor`                 | the beneficiary |
| `activeAlive` (owner check-in) | `activeAliveFor`                  | the owner       |

Instead of proving identity with `msg.sender`, the sponsored twins recover it from an EIP-712 signature (domain `10102 Legacy Sponsored`, bound to the router's address and the current chain). The recovered signer is then used exactly where `msg.sender` would have been; the relayer's own address plays no role in what happens.

A claim authorization binds, in one signature:

* **the beneficiary** (recovered signer; funds only ever go to their own allocation),
* **the specific legacy** (its id),
* **the exact asset list** being claimed (hashed into the signature; the relayer cannot add, drop, or reorder assets),
* **a single-shot nonce** (each signer has a sequential on-chain nonce; a signature is consumed exactly once and can never be replayed),
* **a deadline** (expired intents are worthless; check-in signatures additionally cannot be dated more than one hour ahead, so a relayer cannot hoard one and submit it months later).

Anyone who changes their mind about an outstanding signed intent can cancel it on-chain by advancing their nonce (`invalidateSponsorNonce`).

## What a malicious relayer could do

Submit your intent, or not submit it. That is the whole list. It cannot redirect funds (they flow to the recovered signer's own allocation), cannot alter what is claimed (the asset list is inside the signature), cannot replay (single-shot nonce), and cannot act without a signature that you produced. The worst case (a relayer that silently drops your intent) degrades to the world before this feature existed: you submit the direct call yourself. Relaying is deliberately **permissionless** for the same reason; if our relayer disappears, anyone can run one.

## Owner control

Sponsored **claims are on by default** for every EOA transfer legacy. An owner who does not want third parties submitting claim transactions for their legacy can turn them off (and back on) at any time with `setSponsoredClaimsEnabled`; the direct, beneficiary-pays claim path is always available regardless.

## 10102's relayer

The app wires this in automatically. When a beneficiary starts a claim and their wallet cannot cover the network fee, the app switches from "send a transaction" to "sign an authorization", forwards it to our relay service, and tracks the resulting transaction exactly as if the beneficiary had sent it. Beneficiaries with ETH simply pay their own fee as before.

The relay service applies operational bounds of its own, none of which are load-bearing for safety (that all lives on-chain):

* it simulates the call first, so an intent that would revert is rejected for free instead of wasting gas;
* daily relay caps (global and per-legacy) and a gas-price ceiling bound the worst-case spend;
* **claims are relayed free for everyone.** Sponsored **check-ins are a premium perk**: an owner resetting their own timer is alive, able to pay, and doing something recurring, so we cover that fee only for subscribers. This is a policy choice in the relayer, not a protocol rule: the contract entrypoints themselves don't distinguish.

## Honest limits

* **Not gasless, but gas-sponsored.** Someone still pays; for claims it's us. The daily caps mean that in an extreme rush the relayer can decline and beneficiaries fall back to paying their own fee.
* **Smart-contract wallets are supported** (ERC-1271 signature validation, including Safe), with one inherent caveat of that standard: a contract wallet decides validity at verification time, so rotating its owners can invalidate an intent that is already signed but not yet submitted.
* **This is the signed-intent generation, not account abstraction.** The long-term end-state for fee abstraction is EIP-7702/paymasters; this mechanism is compatible with that future and doesn't block it.

## Related pages

* [Legacy contracts created with EOAs](/architecture/legacy-contracts-created-with-eoas)
* [Create flow v2](/architecture/create-flow-v2)
* [EOA activity auto-renew](/architecture/eoa-activity-auto-renew): the other "10102 pays the gas" mechanism, for automatic timer renewals
* [Upgrade Policy](/architecture/upgrade-policy)


# Heirloom Gifts

How Heirloom seals gifts on the TimeLockRouter, why claim links keep the personal note off every server, and how gasless claims stay abuse-proof.

Heirloom is a presentation layer over the deployed `TimeLockRouter` contract: a sealed gift IS a timelock of the contract's `Gift` type, created with `createTimelockedGift`. No new contract was deployed for the feature; everything below runs on the audited router that also powers beneficiary timelocks.

## Escrow: two lanes, one seal

* **ETH gifts** ride the router's storage-token swap lane. The sealed ETH is converted into a whitelisted storage token at creation (WETH preferred: a 1:1 wrap with no DEX dependency) and held by the router's vault. At claim time the withdrawal unwraps back to ETH, so the recipient receives ETH.
* **USDC gifts** ride the plain ERC-20 lane. `createTimelockedGift` performs `safeTransferFrom` into the `TimeLockERC20` vault at sealing, after an exact-amount approval. The recipient receives the tokens themselves.

Both lanes escrow at creation. The giver keeps no allowance, no custody, and no recall path: the unlock date and recipient are immutable contract state.

On-chain metadata is deliberately generic (`name: "Gift"`, empty `giftName`): personal information never touches the chain.

## The claim link and the privacy model

A claim link is `/heirloom/{chainId}/{timelockId}#g=<base64url payload>`.

* The **path** carries only public on-chain identifiers. The gift page reads everything factual (recipient, unlock time, assets, claimed state) from the subgraph for that chain.
* The **fragment** (`#g=...`) carries the recipient name, giver name, and personal message. Fragments are never sent in HTTP requests, so no server (ours, an email provider's link scanner, anyone's) sees the note. The gift page decodes it locally.
* The **query** may carry two non-personal hints: `o=<occasion>` selects the themed link-preview card (crawlers must see it, hence not in the fragment), and `paper=1` marks paper-key gifts so the page shows the paper guidance however the visitor arrived.

Paper-key gifts get a second, address-based entry: `/heirloom/for/{giftWalletAddress}` — the target of the QR printed on the key sheet's COVER. The sheet must print before sealing, when no timelock id exists yet, but the gift wallet's address is already known. The page resolves the newest gift sealed to that address via the subgraph and forwards to the canonical gift page, carrying the fragment through. The cover QR embeds the personal payload in its fragment too, so a scanned paper opens the page fully personalized.

* The sealing device also stores a **keepsake** (payload, occasion, card mode) in `localStorage`, keyed by chain and timelock id. This lets the gift's detail page rebuild the full link and the themed card later, on that device only. It is the same device-local posture as private legacy names: no server copy exists.

Whoever holds the link can view the gift. Only the on-chain recipient can withdraw, regardless of who submits the transaction, and only the recipient's own signature can name where the funds go.

## Gasless claims: the sponsored withdrawal relay

The recipient signs an EIP-712 `WithdrawAuth` (free, no gas) and the reminder-worker's relayer submits `TimeLockRouter.withdrawFor`, paying the network fee. Since the router's domain version 2 (mainnet, 24 September 2026) the struct carries `payTo`, the wallet that receives the funds; `address(0)` means the recipient itself.

```mermaid
sequenceDiagram
    participant R as Recipient (browser)
    participant W as Reminder worker
    participant C as TimeLockRouter

    R->>C: read eip712Domain() and sponsorNonce(recipient)
    R->>R: sign WithdrawAuth (recipient, payTo, timelockId, skipSwap, nonce, deadline)
    R->>W: POST /sponsor/gift-withdraw
    W->>W: rate limits, daily caps, payload checks
    W->>C: estimateGas withdrawFor(...)
    C-->>W: ok (reverts cost nothing)
    W->>C: withdrawFor(timelockId, skipSwap, auth)
    C->>C: verify signature, exact nonce, deadline within 7 days
    C-->>R: pays payTo, or the RECOVERED SIGNER when payTo is empty
    W-->>R: txHash
```

Why this cannot be drained:

* **The contract is the judge**: `withdrawFor` recovers the signer from the typed-data signature, requires that signer to be the lock's recipient, and pays out to the `payTo` bound in that same signature (or to the signer). A relayer cannot alter the destination, the id or any other field without invalidating the signature; a forged or replayed request reverts, and the relayer's `estimateGas` catches it before any gas is spent.
* **Exact sequential nonce** (`sponsorNonce`) and a deadline bound every authorization to one use. The deadline may not sit more than seven days out at submission, so a signature obtained long before an unlock is useless at the unlock.
* **Vault-side**: the destination is applied through a router-only `withdrawTo` on the escrow vaults; the open `withdraw` path still pays the recipient and nobody else. Signatures over the previous struct (domain version 1) fail by construction rather than paying the wrong wallet.
* **Why a destination at all**: a claim signature reveals the recipient key's public key. Paying a wallet the recipient already controls means a paper or email key signs once and the funds never need to rest in the revealed address. This is best effort: anyone can trigger the plain `withdraw` to the recipient first, in which case nothing is lost and the recipient moves the funds later.
* **Worker caps** bound the spend: a global daily relay cap, a per-gift daily cap, a gas-price ceiling, and per-IP rate limits. The numbers live in the reminder-worker configuration; at current mainnet fees a claim costs roughly a dollar of gas, and the worst full-saturation day is bounded to tens of dollars.
* The realistic abuse is cap exhaustion (sealing tiny gifts to yourself and claiming them sponsored), which burns the day's free-claim budget but never other people's funds. Self-paid claiming always remains available.

Availability is reported by `GET /sponsor/status` as a `gift` field, separate from the legacy sponsor's readiness.

**Paper-key claims** ride the same relay with a different signer: the claim page accepts the printed key directly (camera scan via the native BarcodeDetector where available, typed otherwise), builds an in-memory account from it, and signs the same `WithdrawAuth` locally. The key never leaves the device and is never persisted; only the signature travels. This path is sponsored-only by design, because the gift wallet holds the escrowed gift but no ETH for gas.

## Email-addressed gifts (Turnkey)

A gift is sealed to an address, so "send it to an email" means "seal it to the address that email controls". Two halves, one relay:

* **Seal side.** The giver signs an EIP-712 `GiftEmailWallet{emailHash, deadline}` (the hash rides in the message; the email itself only in the request body, over TLS) and the frontend calls the worker's `POST /gift/recipient-wallet`. The worker finds or creates a Turnkey **sub-organization** for that email, keyed by a salted hash, whose only root user is the email (email OTP authenticator) and which holds one Ethereum wallet. It returns the address; the seal transaction is the ordinary one. Per-IP limits and a daily creation cap bound the minting. The worker stores `emailHash -> subOrgId` only; the raw email rides the existing encrypted notify path, and the claim link carries `email=1`.
* **Claim side.** The gift page talks to Turnkey's Auth Proxy directly with two public IDs (organization and auth-proxy config): send the code, verify it, log the session in, then the embedded wallet signs the same `WithdrawAuth` the paper key signs. The signer seam in the claim hook is the only thing that changes; the relay and the contract do not know which kind of signer produced the signature.

Custody, stated plainly: the key lives in Turnkey's enclaves and signs only after the email's owner verifies with the code; 10102's API key can create sub-organizations but holds no authority inside them. This is a step away from self-custody (the recipient depends on their inbox and on Turnkey's service), which the user guide says in as many words. The paper key stays the fully self-sovereign path.

Readiness is reported by `GET /sponsor/status` as `giftEmail` (all three `TURNKEY_*` variables set on the worker); the create page offers the mode only when it reads true, and the frontend has a kill switch (`VITE_FEATURE_GIFT_EMAIL=false`).

## Notify emails

`POST /gift/notify` lets the GIVER register a recipient email with a timing choice: "a gift is waiting" immediately, on a scheduled day of the giver's choosing (`notify_at`, e.g. the birthday itself), or not at all — plus "your gift just unlocked" on opening day in every mode.

* **Owner-signed EIP-712**: the signature covers the sha256 HASH of the payload (`GiftNotify2`), binding the exact content while keeping the email out of wallet signing prompts. The worker hashes the payload it receives, verifies the signature, and checks the signer against the timelock's on-chain owner via the subgraph. Only the actual giver can email anyone; this is the anti-spam core.
* **Claim-link origins are allowlisted** so a malicious payload cannot point victims at a phishing domain wearing our email template.
* **Encrypted at rest**: the payload (email, names, the full claim link including its fragment) is AES-GCM encrypted with a per-row derived key.
* **Crypto-shredded at maturity**: the unlock-day pass deletes every matured row, silently when the gift is already claimed, right after the unlock send otherwise. Encrypted personal data never outlives opening day (plus a retry window if the email proxy is down).
* **Dedupe survives deletion**: send idempotency lives in a separate ledger keyed by a hash of the email, so a deleted row can never re-arm a duplicate send, while correcting a typo'd address still gets its copy.

## Printable artifacts

All three artifacts render client-side on a canvas (no server round trip) at Letter size, 200 dpi:

* **Key sheet**: a wrap-fold three-panel packet. The flat sheet renders the secret on the top panel, the occasion cover on the middle, and the "how to open" back panel rotated 180 degrees so it reads upright after folding. QR codes are generated with margin 2 and error correction M; the secret panel is always pure white for scan reliability.
* **Gift card**: occasion-themed certificate carrying the claim link QR and the personal message. Never the key, never the amount.
* **Gift record**: an austere factual document for the giver, headlined by fair market value on the sealing date (historical price lookup for past gifts, live price for same-day ones, an honest "no price source" line offline), with a not-tax-advice disclaimer.

Occasion designs (palettes, canvas-drawn motifs, greetings, message templates) are a reviewed content pack; religious occasions use only symbols customary on greeting cards.

## Known operational notes

* Wallet reputation engines can flag young contracts. The create page explains the caution in place and points at address verification; the false-positive appeal is an operational task tracked in the app repository's ops checklist.
* A gift is also visible as a `Gift`-type row in the giver's Timelock tab; the shield score deliberately does not credit outgoing gifts as a protection layer.


# Email Reminders

How email reminders are driven from on-chain state: an off-chain reminder-worker reads PII-free notify signals, keeps recipient emails encrypted, and sends them, while the plan keeps working even if e

Email reminders are an opt-in Premium capability that gives owners and beneficiaries out-of-band notifications at key moments in a legacy's lifecycle. They are **additive**: the on-chain contract doesn't depend on email delivery, and the whole email layer can fail without affecting the legality or executability of a legacy.

For the user-facing behavior (what events trigger emails, who gets what), see [Configure Email Reminders](/user-guide/premium-features/configure-email-reminders). This page covers the architecture.

{% hint style="info" %}
**Architecture change (2026-06-02).** Reminders used to run on-chain through Chainlink Automation (a daily cron) and Chainlink Functions (the `PremiumMail*` consumers that called the mail service), with recipient emails stored on-chain. That path is **retired**; see [Retired: the Chainlink path](#retired-the-chainlink-path) below. Reminders now run from an off-chain `reminder-worker`, and recipient emails are **no longer stored on-chain**.
{% endhint %}

## Components

| Component             | Role                                                                                                                                                                                                                                 |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Router contracts      | Deploy the per-legacy contracts at legacy creation, and emit PII-free notify events (e.g. `LegacyEmailNotifyRequested`) at activation. Not otherwise involved in reminders.                                                          |
| `PremiumSetting`      | Stores reminder configuration **as addresses only**: which beneficiaries to notify and the advance-notice windows. No emails or names are stored or emitted on-chain.                                                                |
| `PremiumReminderView` | A standalone, stateless, read-only contract. The worker polls it (`dueRemindersBatch`) to learn which time-based reminder windows are currently open for a legacy. Falls back to a 7-day window when a creator hasn't set their own. |
| `reminder-worker`     | Off-chain service (Railway + Postgres). Holds recipient emails/names **encrypted at rest**, reads notify signals from the subgraph and `PremiumReminderView`, dedupes, and dispatches email.                                         |
| `email-proxy`         | The existing 10102 mail service the worker posts to. Fills in template variables and hands off to the SMTP provider.                                                                                                                 |
| Mailjet               | SMTP-as-a-service provider behind `email-proxy` that actually puts email in recipients' inboxes.                                                                                                                                     |
| The Graph subgraph    | Indexes the PII-free `LegacyEmailNotifyRequested` event into a `NotifyRequested` entity (subgraph v0.4). The worker reads these to know when an activation/reset happened.                                                           |

The on-chain pieces (`PremiumSetting`, `PremiumReminderView`, routers) live in the public [`computing-sc`](https://github.com/10102-io/computing-sc) repository. The `reminder-worker` and `email-proxy` services live alongside the frontend in `computing/services`.

## Where recipient emails live

Recipient emails and names are **off-chain and encrypted**:

* Each recipient is one row keyed by `(chainId, legacy, recipientAddress)`. The `email` and `name` fields are encrypted with **AES-256-GCM** under a **per-record key**, derived (HKDF) from a master key plus a per-row salt.
* The master key (`EMAIL_ENC_KEY`) is a deployment secret held by the hosting platform and is **never** stored in the database.
* A per-record key means a single recipient can be erased independently: deleting the row **crypto-shreds** it (its key material is gone, so the ciphertext is unrecoverable). This is how erasure / GDPR "right to be forgotten" is satisfied.
* The worker is **PII-minimal**: the only personal data it stores is the recipient's own name/email. Everything else in an email (owner address, legacy name/type, beneficiary addresses, amounts) is reconstructed from public on-chain / subgraph data at send time.

## Authenticating to the worker

The frontend talks to the worker with **EIP-712 wallet signatures**; no shared secret ever ships in the browser. The owner signs a typed message and the worker recovers the signer and checks it against the legacy's on-chain `creator()`. To avoid one signature per recipient, the save/erase/read flows are **batch-signed once per legacy**:

| Endpoint             | Purpose                                                                                        | Who may sign                                                    |
| -------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `/ingest-legacy`     | Save the legacy's complete recipient set (recipients absent from the list are crypto-shredded) | The legacy's on-chain `creator()`                               |
| `/recipients`        | Load the decrypted recipients back so the owner can re-display / edit their config             | The legacy's on-chain `creator()`                               |
| `/erase-legacy`      | Wipe the legacy's entire recipient set                                                         | The legacy's on-chain `creator()`                               |
| `/send-instructions` | Send the manual "send instructions" email to a legacy's recipients                             | The legacy `owner` (also checked `creator() == owner` on-chain) |

The worker **fails closed** if it can't read `creator()` on-chain. "Send instructions" runs entirely server-side (the browser never sees the recipient emails) and is throttled by a **per-owner cooldown stored in Postgres** (replacing the old client-side guard).

## Workflow

### Step 1: Subscription and configuration

1. The owner purchases a Premium subscription (paid in ETH, USDC, or USDT to the `PremiumRegistry` contract). The subscription is on-chain, time-bound, and scoped to the paying wallet.
2. While Premium is active, the owner configures reminders. The **addresses** to notify and the advance-notice windows are written **on-chain** to `PremiumSetting`; the matching **emails/names** are synced to the `reminder-worker` over an EIP-712-signed `/ingest-legacy` call.
3. No cron registration happens on-chain. The off-chain worker discovers legacies to watch from the subgraph and the on-chain configuration.

### Step 2: Evaluation

The worker runs on a schedule (its own tick, not an on-chain cron). Each tick does two passes:

1. **Event pass**: pulls recent `NotifyRequested` entities from the subgraph (owner-reset, multisig activation, transfer activation). For transfer activations it reconstructs per-recipient ERC-20 amounts from the activation transaction's `Transfer` logs.
2. **Due pass**: calls `PremiumReminderView.dueRemindersBatch(...)` for the watched legacies to learn which **time-based** windows are open (e.g. "approaching activation", "ready to activate", second-line windows). The chain is the trust anchor for *when* a reminder is due.

### Step 3: Reminder dispatch

Both passes funnel into a single dispatch step:

1. Resolve the recipient rows for the legacy.
2. Claim an idempotency key in the **sent-ledger** (`claim-before-send`) so the same `(legacy, recipient, event)` is only ever sent once, even across worker restarts or subgraph re-org replays.
3. Decrypt the recipient's email **in memory only** and POST to `email-proxy`, which fills template variables and delivers via Mailjet.
4. Record the provider message id. A failed send releases the claim so the next tick retries.

### Resolved: no more duplicate emails

The old Chainlink path executed on multiple oracle nodes that each made an independent mail call, and the mail service didn't dedupe, so **the same reminder could arrive more than once**. A single worker with a **claim-before-send sent-ledger** removes that fan-out entirely: each reminder is claimed once and sent once. This previously-documented limitation is **resolved**.

## Retired: the Chainlink path

The following on-chain email machinery has been **decommissioned**:

* **Chainlink Automation**: the per-user upkeep crons (via `PremiumAutomationManager`) that called `checkUpkeep` / `performUpkeep` to evaluate when a reminder was due.
* **Chainlink Functions**: the `PremiumMail*` consumer contracts that bridged the "send email" signal to the off-chain mail call.

Scheduling moved to the worker's own tick + `PremiumReminderView`; delivery moved to the worker + `email-proxy`. On **mainnet**, the teardown completed on **2026-06-02**: the upkeeps were cancelled, the Functions subscription was cancelled, and remaining LINK was withdrawn. `PremiumSetting` was slimmed in the same cutover: emails/names are no longer stored or emitted, activation triggers are emit-only, and the spoofable mail-trigger path was removed.

{% hint style="info" %}
This page covers **email reminders** first (with the worker's other passes summarized [below](#beyond-email-the-workers-other-passes)). How activity and inactivity are actually tracked is a different subsystem, documented in [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking) and [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).
{% endhint %}

## Privacy and opt-in

* **Email addresses are not on-chain.** They're held off-chain by the worker, encrypted at rest with a per-record key, and only decrypted in memory at send time. A reader of the chain sees only addresses and reminder windows, never emails or names.
* Reminders are strictly opt-in per recipient. An owner cannot secretly enroll a beneficiary's email; the flow requires the owner to input the address explicitly, and the worker only accepts writes signed by the legacy's on-chain creator.
* A recipient can be erased independently (crypto-shred), and deleting the legacy wipes its recipient set.
* 10102 never asks a beneficiary to sign anything to "enable reminders." If a recipient ever gets an email claiming they need to sign or connect a wallet to continue receiving reminders, it's not us.

## What happens when email breaks

If the email layer is entirely broken (worker down, `email-proxy` down, Mailjet down), the only consequence is that reminder emails don't send. The legacy itself continues to work exactly as specified on-chain. A beneficiary whose reminder never arrives can still activate on time via the app, or via Etherscan using the [Legacy Claim Card](/user-guide/legacy/legacy-claim-card), because the on-chain state has all the information needed.

This is the "plan survives us" principle in action: email reminders are a *better experience*, never a *requirement*.

## Beyond email: the worker's other passes

The reminder-worker has grown into the protocol's general off-chain watcher and relayer. Besides reminders, it runs several additional passes. Each is independently optional (a deploy without the configuration simply skips the pass), none of them touches recipient PII, and none of them is something a legacy depends on.

### Protocol stats and token prices

The worker periodically computes aggregate protocol statistics (counts and value secured across legacies and timelocks) and serves them from a read-only `GET /stats` endpoint; this is what feeds the stat line on the app's landing page. Alongside it, `GET /stats/prices` serves a snapshot of token prices read from Chainlink price feeds on-chain, refreshed every few minutes, which the app uses for USD estimates. Both endpoints expose only aggregate, public, on-chain-derived numbers: no addresses, no emails, nothing per-user.

### Upgrade-queue watch

The worker also watches the protocol's `UpgradeTimelock`, the contract every proxy upgrade must be publicly queued on, per the [Upgrade Policy](/architecture/upgrade-policy). It scans the timelock's logs and raises an alert the moment anything happens there: an operation scheduled, executed, or cancelled, or the minimum delay changed. Alerts always go to the service log, and additionally to an ops email when configured.

This is the operational half of the upgrade policy's honesty story: the 48-hour queue only protects users if someone is actually watching it. A queued upgrade nobody expected is the signal to cancel and rotate keys. And because the events are public, anyone can run the same watch themselves straight from Etherscan.

### Gas-sponsored relaying

The worker is also the relayer behind [gas-sponsored intents](/architecture/gas-sponsored-intents): it accepts a user's signed EIP-712 authorization (a beneficiary's claim, or an owner's check-in), submits the corresponding router transaction, and pays the gas. Every safety property lives on-chain; the worker only adds spending bounds (daily caps, a gas-price ceiling) and simulates each call before paying for it. Claims are relayed free for everyone; sponsored check-ins are a Premium perk. If this pass is down, nothing is lost but the convenience: the direct, pay-your-own-gas paths always work.

### Auto-renew attestations

The [auto-renew attestor](/architecture/eoa-activity-auto-renew) runs as a pass of this same worker: for EOA legacies whose owner opted in, it observes the owner's public transaction count and renews the inactivity timer near the deadline, within the strict on-chain bounds described on its page.

### Ops-status readout

Finally, the worker exposes a read-only ops-status readout used by an internal founder-facing status page. It reports which optional passes are configured on the running deploy, as booleans and public on-chain facts only, never secret values. It is gated by its own low-privilege secret, deliberately separate from the worker's powerful operational secret (which guards data-erasure and send paths and never leaves the server side); until that secret is set, the endpoint doesn't exist. Leaking it would expose configuration posture, nothing more.


# Upgrade Policy

How 10102's contracts can change, who can change them, and how you can watch: every upgrade waits in a public 48-hour queue, a multisig queues it, and a separate hardware key can stop it.

10102 is non-custodial: your assets stay in your wallet or in contracts only you control. But parts of the protocol (the routers that create legacies and timelocks, the premium stack) are upgradeable proxies, and an upgradeable contract is only as trustworthy as its upgrade process. This page is our standing commitment on how upgrades work, written so a stranger can verify every claim on-chain.

## The one-sentence version

**No contract implementation can change without first sitting in a public, on-chain queue for 48 hours; the key that queues an upgrade and the key that can stop it are different devices; and nothing that lets you exit (claim, check in, delete, withdraw) can ever be paused.**

## How it works

Every upgradeable proxy in the protocol is administered by a single `ProxyAdmin` contract, and that ProxyAdmin is owned by a **timelock** ([`UpgradeTimelock` on Etherscan](https://etherscan.io/address/0xc0Fee69ffAA1d62D701Bb277031CEc0d98AFA4Ad#code), based on OpenZeppelin's audited `TimelockController`):

1. An upgrade is **scheduled** on the timelock by a **proposer**. This emits a public `CallScheduled` event naming the target contract and the new implementation.
2. It **waits at least 48 hours**. During this window anyone can inspect the queued implementation's verified source code, and a **canceller** can stop it.
3. Only then can it **execute**. Execution is permissionless: once the delay has passed, nobody can block a queued operation, and before it has passed, nobody can accelerate it.

The timelock administers itself: changing the delay or the roles is itself a queued, delayed operation.

```mermaid
flowchart LR
    A["Proposer (multisig) schedules<br/>public CallScheduled event"] --> B["48-hour public queue<br/>anyone can inspect the verified code"]
    B -->|"guardian key spots a problem"| C["Cancelled<br/>nothing changes"]
    B -->|"delay elapsed"| D["Executed<br/>permissionless: nobody can block it"]
    B -.->|"you disagree"| E["You can exit first:<br/>claim, check in, delete, withdraw<br/>(never pausable)"]
```

## Who holds which key

Since 24 September 2026 the roles are split across devices, so that no single key can both queue a change and wave it through:

| Role                    | Holder                                                                                                                                                                                | Can do                                                              | Cannot do                                                  |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------- |
| Proposer                | The governance multisig, a [Safe](https://app.safe.global) at [`0x60B3da49f05E21a1fcD7e210075A23b75939C3eA`](https://etherscan.io/address/0x60B3da49f05E21a1fcD7e210075A23b75939C3eA) | Queue upgrades and role or delay changes                            | Execute early, cancel                                      |
| Proposer (transitional) | The maintainer key `0xfe8b…b630`                                                                                                                                                      | Queue routine upgrades from scripts                                 | Cancel; it loses the proposer role once the Safe is 2-of-3 |
| Canceller               | A hardware wallet, [`0x7B61dD775422f465D6b9f28C8EFEE39263ef2579`](https://etherscan.io/address/0x7B61dD775422f465D6b9f28C8EFEE39263ef2579), never connected to a browser extension    | Stop anything queued                                                | Queue anything                                             |
| Executor                | Anyone                                                                                                                                                                                | Execute an operation whose delay has passed                         | Execute early                                              |
| Admin                   | The timelock itself                                                                                                                                                                   | Grant or revoke roles, change the delay, all through the same queue | Act instantly                                              |

The Safe starts with a threshold of one signer while its third owner is added; raising it to two of three is the next change, and it is visible on the Safe itself. Read the live table any time: `hasRole` on the timelock, or the open-source `verify-governance` script in the contracts repository, which prints every row above as pass or fail.

What the timelock and the Safe own today:

* The `ProxyAdmin` of every proxy, and the three timelock vaults that hold every escrowed timelock and gift (their settings, such as the swap router an ETH gift uses at claim, are queued operations too).
* The timelock router (creation settings and the create pause) is owned by the Safe.

## What we will and won't upgrade

* **We will** ship upgrades for security fixes, gas savings, and new features, announced in the changelog when they are queued, not after they land.
* **We won't** upgrade in ways that move or restrict user assets: claims, check-ins, deletions and withdrawals are permanent capabilities. They are not pausable today, and no upgrade weakening them will be queued.
* **Existing legacy contracts never hot-swap.** Each legacy clone pins its implementation and its Permit2 vault at creation time. Upgrades affect how NEW contracts are created; your existing contract keeps the exact code you audited (or your beneficiary's claim card references) forever.

## What is deliberately NOT timelocked

Honesty over theater. Two classes of admin action work instantly:

* **The create pause.** In an active incident we can halt NEW legacy or timelock creation immediately (from the maintainer key for legacies, from the Safe for timelocks). Exit paths are unaffected: pausing can protect new users, never trap existing ones.
* **Operational settings** (token whitelists, plan configuration, rotation of the clone implementation / pull vault used for *new* creates). These cannot touch existing contracts or user balances; the blast radius is limited to new creations, which the 48-hour window doesn't meaningfully protect anyway.

## The honest limit

The timelock is a transparency window with a brake, not yet full multi-party control. Until the Safe is two-of-three, the maintainer key can still queue an upgrade on its own; what it can no longer do is cancel, and what it never could do is skip the queue. A malicious or mistaken operation cannot land silently: our monitoring alerts on every `CallScheduled`, the guardian key has 48 hours to cancel, and you have 48 hours to exit if you disagree with any queued change. The remaining steps, in order and each visible on-chain when it happens: the Safe to two of three, the maintainer key losing the proposer role, and the delay rising from 48 hours to 7 days.

## Watch the queue yourself

* Timelock contract (mainnet): [`0xc0Fee69ffAA1d62D701Bb277031CEc0d98AFA4Ad`](https://etherscan.io/address/0xc0Fee69ffAA1d62D701Bb277031CEc0d98AFA4Ad). Watch the `CallScheduled`, `CallExecuted` and `Cancelled` events (the Events tab on Etherscan, or an address watch/alert service pointed at the contract).
* ProxyAdmin (owned by the timelock): [`0xA41299408EB78D67B9b599e38E3259C11A005145`](https://etherscan.io/address/0xA41299408EB78D67B9b599e38E3259C11A005145). Its `owner()` is the timelock; verify it yourself.
* Roles: call `hasRole(role, account)` on the timelock with `PROPOSER_ROLE`, `CANCELLER_ROLE` or `EXECUTOR_ROLE` (`keccak256` of those strings) and the addresses in the table above.
* Every implementation we queue is verified on Etherscan before scheduling, so the diff is inspectable during the full waiting period.
* Changelog entries are written when an operation is queued, with its operation id and the time it becomes executable, not after it lands.


# Quantum Readiness

What quantum computers mean for Ethereum keys, what 10102's on-chain recovery registry does today, and, just as important, what it does not do.

Your 10102 plan is measured in decades. On that horizon, one risk stands out as both real and widely misunderstood: sufficiently large quantum computers are expected to break the elliptic-curve signatures (secp256k1 ECDSA) that every Ethereum wallet uses today. This page explains the honest threat model, what we ship now, and where it goes next.

One vocabulary rule up front: nothing here is "quantum-proof". We say **quantum-ready**, and we mean exactly what is written below, no more.

## The threat, honestly

* **No quantum computer today can break an Ethereum key.** Current machines are several orders of magnitude short of the roughly 1,200 to 1,450 error-corrected (logical) qubits the attack needs. Credible estimates for a cryptographically relevant machine cluster around 2030 to 2035.
* **The margin is shrinking, not growing.** Research published in 2026 cut the estimated hardware requirement by roughly 20x versus prior estimates, and major hardware roadmaps now target hundreds of logical qubits before 2030. The comfortable "decades away" framing is gone.
* **Not all addresses are equally exposed.** An Ethereum address is a hash of the public key. A wallet that has **never signed a transaction** only reveals that hash, which quantum algorithms barely dent; it is in a strong position. A wallet that **has signed** reveals its public key forever, and an exposed key is exactly what a future quantum computer could target.
* **A Safe is a special case.** The Safe's own address derives from no key, so there is nothing to expose at the Safe itself. Its owners' keys are the attack surface: every co-signed transaction publishes an owner signature. An attacker would need to break threshold-many owner keys.
* **AI does not break cryptography.** There is no credible evidence that machine learning threatens ECDSA or keccak256 mathematically. AI's real contribution to this risk is indirect: it may accelerate quantum hardware engineering. We will never market "protection against AI cracking your keys"; that claim would be theater.

## The recovery paradox, and why acting early matters

If ECDSA breaks, an attacker holding your cracked key is cryptographically indistinguishable from you. No future rescue mechanism, whether built by 10102 or by Ethereum itself, can tell owner from thief at that point, **unless a quantum-safe second factor was bound to the account before the break**.

That is the entire logic of acting now. A commitment (the hash of a secret only you hold) stored on-chain today costs one small transaction. Hashes are safe against quantum attack, so registering reveals nothing. What the chain provides is the one thing that cannot be forged after the fact: the **timestamp**. Any recovery mechanism that appears later can honor commitments recorded before a publicly agreed breach date and reject everything after it.

## What we ship today

### The readiness readout

The dashboard shows a quantum readiness card for the connected account:

* Whether the account is an EOA or a smart account.
* For EOAs, whether the public key is already exposed (the wallet has signed before) or still shielded behind its hash.
* Whether a recovery commitment is registered, and since when.

Agents can query the same facts through the Guardian MCP tool `get_quantum_readiness`. See [Agents & Builders](/agents-and-builders).

### The recovery registry

[`QuantumRecoveryRegistry` on Etherscan](https://etherscan.io/address/0xaB3C8C69fD17ba980b3D11064200c866904e360E#code) is deliberately minimal:

* **Append-only.** Registering again never erases an earlier entry, because the earliest pre-breach timestamp is exactly what a future verifier needs.
* **Ownerless and immutable.** No admin, no proxy, no pause switch. A "quantum-safe" registry whose admin key could rewrite history would undercut its own claim.
* **Address-agnostic.** An EOA (hardware wallets included) registers by signing one normal transaction. A Safe registers by routing the same call through its usual transaction flow, so the commitment is recorded for the Safe address itself. There is no dependency on Safe or on any wallet brand.

The app's register flow generates a fresh 32-byte secret on your device, has you download a printable backup sheet (the only copy), and registers `keccak256(secret)` on-chain. The secret never leaves your device except on that sheet. Losing the sheet risks no funds; it only forfeits the head start, and you can register a fresh secret at any time.

```mermaid
sequenceDiagram
    autonumber
    participant U as You (EOA or Safe)
    participant A as 10102 app
    participant R as QuantumRecoveryRegistry<br/>(immutable, ownerless)
    U->>A: Reserve recovery path
    A->>U: Generate secret on-device,<br/>download backup sheet
    U->>R: register(keccak256(secret))<br/>one ordinary transaction
    R-->>U: Commitment stored with timestamp,<br/>append-only forever
```

## What this does not do, stated plainly

The registry on its own is a **readiness step, not an enforcement mechanism**. Nothing in it can move funds, veto a transaction, or stop an attacker. Its value is the provable pre-break timestamp, which enforcement layers can honor. The first such layer is live: [Protect a holding](/user-guide/shield) (ShieldVault) reads a registry commitment as the secret that stops a withdrawal. Coins outside it, in a plain wallet or a legacy, are exactly as protected as before. We would rather tell you exactly what you bought than sell you a stronger-sounding claim.

## Enforcement: what is live, what is next

1. **Delay plus veto, in a standalone holding. Live since 2026-09-28.** ShieldVault (`0x83074f8519F54AF05f7C48911E432e0C44dBEE69` on Ethereum): withdrawals and setting changes announce themselves and wait a delay the owner chose; during the wait, revealing the pre-registered secret moves everything to the recovery wallet bound into it. It works even against an attacker who fully controls the owner's key, classical or quantum. Reviewed adversarially before deployment, not yet independently audited. See [Protect a holding](/user-guide/shield).
2. **A Safe module** adding the same delay and veto to an existing Safe without moving funds. Next, not scheduled.

Practical hygiene that costs nothing meanwhile: prefer receiving long-term holdings at fresh addresses that have never signed, and treat a Safe (whose address exposes no key) as a better long-term container than a well-used EOA.


# Agents & Builders

How AI agents and developers can discover and use 10102 Computing Legacy: the Guardian AI guide, ERC-8004 discovery, the MCP server, and pay-per-call inference.

This page is for two audiences: developers building software (including AI agents) that needs to read or set up on-chain legacies, and autonomous agents that act on behalf of their users. It explains how to discover 10102 Computing Legacy as a registered agent, what you can call for free, and how metered inference works.

The product is non-custodial and fully on-chain. Nothing here takes custody of funds, and no endpoint can move assets on its own: every contract write requires the user's wallet signature.

## Meet Guardian: the AI digital-legacy guide

Guardian is the AI assistant inside 10102 Computing Legacy. It helps people set up their digital legacy and timelock contracts: it interviews a wallet owner about goals, helps them choose a matching contract type (Legacy or Timelock), and builds pre-filled setup links that the user completes by connecting a wallet and signing on-chain.

* **Powered by Venice AI.** Guardian runs on Venice's privacy-preserving inference. Conversations are not stored and are not used to train models. The chat model tracks Venice's function-calling default (currently GLM 5.2), with Venice's server-side web search available for questions that need live information.
* **Free allowance for everyone.** A free inference allowance applies per caller, so anyone can use Guardian without bringing their own credits.
* **A guide, not an advisor.** Guardian helps you configure legacy and timelock contracts. It does not give legal, tax, or financial advice.

## Discover us as an agent (ERC-8004)

10102 is registered under [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004), the agent-discovery standard. Agent identities live in an Identity Registry implemented as an ERC-721 on Ethereum mainnet, so any agent or tool can resolve our identity on-chain.

* **Agent name:** 10102 Guardian
* **Agent id:** `34821`
* **Agent registry:** `eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432`

The identity is discoverable through standard ERC-8004 explorers such as [8004scan.io](https://8004scan.io).

### A2A agent card

The agent capabilities are described by an A2A agent card (protocol version 0.3.0):

```
https://app.10102.io/.well-known/agent-card.json
```

The card advertises these skills:

* **Suggest a legacy plan** (`recommend-legacy-plan`): interview a wallet owner about goals and help them choose the matching contract type.
* **Build pre-filled setup URL** (`build-setup-url`): generate a deep link that pre-fills the web form with beneficiaries, durations, name, and type. The user finishes by connecting a wallet and signing on-chain.
* **Query legacy status** (`query-legacy-status`): read LegacyDetail records (status, beneficiaries, triggers, Safe context) from the subgraph or on-chain router views.
* **Query timelock status** (`query-timelock-status`): read Timelock entities (unlock time, lock type, recipient, token contents, withdrawal status).
* **Verify on-chain deployment** (`verify-contract-deployment`): confirm canonical router addresses and read live contract state via Ethereum mainnet RPC.

## Model Context Protocol (MCP)

Guardian exposes a read-only MCP server:

```
https://mcp.10102.io/mcp
```

(MCP protocol version `2025-06-18`.)

Reads are free. The MCP server lets you look up legacies and timelocks and generate pre-filled setup links. There are no keys to manage and no write paths: the server returns indexed state and deep links, but contract creation still requires the user's wallet signature in the app or via a direct contract call.

In practice that means an agent can:

* Query indexed Legacy and Timelock state for an address.
* Build a pre-filled setup URL that hands the user off to the web app to review and sign.
* Read a wallet's portfolio-health summary (below).

### Portfolio health

Agents can read a wallet's token-health summary: the same readout the app's dashboard widget shows, powered by the Computing Tokens research pipeline ([tokens.10102.io](https://tokens.10102.io)). Two ways in:

* **MCP tool:** `get_portfolio_health` returns the cached report for an address: an average health score and any flagged holdings.
* **REST proxy:** `GET https://mcp.10102.io/portfolio-health?address=0x…` returns the same headline numbers as plain JSON. It's CORS-open (browser apps can call it directly) and exists because the upstream research API key stays server-side; it never ships in a client bundle.

The REST proxy is rate-limited per IP, and responses are cached per address for a few minutes. Both surfaces are privacy-shaped: they report on **public on-chain holdings only**, nothing an observer couldn't derive from the chain itself. A wallet that has never been scanned gets a "no report" response; the owner can run a free scan at tokens.10102.io to generate one.

### Quantum readiness

The `get_quantum_readiness` MCP tool reports, for any address: whether it is an EOA or a contract account, whether its public key is already exposed on-chain (any EOA that has signed exposes it permanently, which is the class of funds a future quantum computer could target first), and whether the account has registered a post-quantum recovery commitment in the on-chain [QuantumRecoveryRegistry](https://etherscan.io/address/0xaB3C8C69fD17ba980b3D11064200c866904e360E#code), with the earliest registration timestamp. Everything it reads is public chain state. Registration itself happens in the app dashboard (one transaction); see [Quantum Readiness](/architecture/quantum-readiness) for the honest threat model behind the readout.

## Partner access (B2B)

The anonymous MCP surface above is free and stays open; partner keys never restrict public access. Partners building products on top of it (estate-law practices, wallet providers, agent platforms) can additionally get a **bearer key** for the same read-only tool surface:

* Send it as `Authorization: Bearer <key>` on your MCP requests; the partner context is bound to your MCP session when it initializes.
* A key does not unlock extra data or any write path; the tools are identical to the public ones. What it adds is identification (so we can support and reason about your integration) and attribution: setup links your integration builds carry your partner reference instead of the generic one.
* A key can also carry your **referral-program code**: setup links then attribute Premium purchases by the clients your agent onboards to your partner account, on the same on-chain-verified ledger as regular referral links. See [Partner Program](/partners).
* An unknown key is rejected with `401` rather than silently falling back to anonymous access, so a typo is visible immediately.

Partner keys are provisioned manually. To request one, reach out via [GitHub](https://github.com/10102-io/computing) or <info@10102.io>.

## Pay-per-call inference (x402)

Guardian chat inference is available through an OpenAI-compatible endpoint (the venice-proxy):

```
https://venice-proxy-production.up.railway.app/v1/chat/completions
```

* It is **OpenAI-compatible**, so you can point an existing `/v1/chat/completions` client at it.
* A **free tier** applies per caller, subject to a rate limit.
* For unmetered, metered-by-you usage, bring your own Venice credits via [x402](https://www.x402.org) (the `X-Sign-In-With-X` header). The agent registration advertises `x402Support: true`, so you pay per call from your own wallet credits rather than relying on the shared free allowance.

## Build with us

* **Source code:** the contracts and routers are open source at [github.com/10102-io/computing-sc](https://github.com/10102-io/computing-sc).
* **Agent docs:** the canonical agent onboarding doc is published at [AGENTS.md](https://github.com/10102-io/computing/blob/main/AGENTS.md).
* **Subgraph:** indexed Legacy and Timelock state is served from The Graph gateway: `https://gateway.thegraph.com/api/subgraphs/id/FXzZDbZxzdWaYGTPEcxN2AatbucRooQWfY67moam8oCd`.
* **Non-custodial and on-chain:** every flow is operable directly from the Ethereum contracts. Reads are free, setup is a handoff to a wallet signature, and no part of this stack can move a user's assets without that signature.


# For Estate Planners

For estate planners, attorneys and advisors: how clients include crypto in their plan with 10102, what you see as their authorized watcher, and the partner program.

Crypto is the one asset class that most estate plans cannot reach: if the keys are lost with the owner, a will cannot recover them, and handing the keys to someone else in advance is a custody risk. 10102 closes that gap without anyone holding the keys, you and us included.

Start here: [app.10102.io/advisor](https://app.10102.io/advisor?from=advisor).

## What your client sets up

Your client creates a **legacy contract** from their own wallet: who receives what and in which shares, optional backup people, and how long a silence triggers it. They check in from time to time (or it renews itself from their normal wallet activity, with Premium). If they go silent past the period they chose, the people they named can claim, including with a printed claim card that needs no crypto knowledge.

Nothing is custodial: the assets stay in the client's wallet until a claim happens, and they only ever go to the people the client named. See [Create a Legacy Contract](/user-guide/legacy/create-a-legacy-contract) and [Legacy Claim Card](/user-guide/legacy/legacy-claim-card).

For holdings they want protected against theft as well, the [Shield Vault](/user-guide/shield) adds a waiting period on every withdrawal and a printed recovery sheet.

## What you see as their watcher

Your client adds your wallet address as an **authorized watcher** in Settings, Authorized watchers (part of their Premium plan; you pay nothing). They choose the visibility:

* **Limited** (the default): no addresses. The contract is identified by a private identifier your documents can reference.
* **Full**: every address, so you can look the contract up on Etherscan.

Connect that wallet at [app.10102.io/advisor](https://app.10102.io/advisor?from=advisor) and every client contract you watch appears in one read-only list, most urgent first: its status (Active, Check-in due soon, Ready to activate, Activated), the days left to the next check-in, and the allocations at the visibility you were given. Details in [Manage Authorized Watchers](/user-guide/premium-features/manage-authorized-watchers).

## What you never control

A watcher can never check in, edit, delete, activate, move or redirect anything. This is deliberate: the plan still works if the owner has died, if you are unreachable, and if 10102 no longer exists, because nothing in a claim depends on a third party. You carry no key and no custody.

## Tying it to your documents

* Reference the contract in the will or letter of wishes by the identifier the Advisor view shows (limited visibility) or by its contract address (full visibility).
* Keep the printed claim cards and recovery sheets with the estate papers, in the same way as any other instrument of access.
* The legal effect of a legacy contract, and how it interacts with the client's will and local succession law, is your professional judgement: 10102 moves assets according to the contract, not according to a court.

## Partner program

Firms and advisors who bring clients can join the **advisor tier** of the [Partner Program](/partners): a recurring share of your clients' Premium renewals, attributed on-chain so every statement can be checked on Etherscan. If your profession bars referral fees (for example French avocats and notaires), **discount mode** gives your clients a lower Premium price instead, and you receive nothing.

To start, write to [info@10102.io](mailto:info@10102.io?subject=Advisor%20partner) with your firm, the partner code you would like, and a USDC payout address (or "discount mode").


# Partner Program

The 10102 partner program: share a link, get verifiably attributed on-chain purchases, reconcile every statement yourself on Etherscan.

10102 Computing Legacy is free to use; revenue comes from the optional Premium plan ($99/year or $399 lifetime, paid on-chain) and a small fee when assets are delivered. Partners who introduce their audience or clients to the app earn a share of the Premium purchases they bring, with an attribution system designed so you never have to take our word for a number.

This page is the practical guide. The legally binding mechanics live in the published [Partner Program Terms](https://10102.io/partner-terms) (EN and FR).

## How it works

1. We agree on your partner code, for example `acme`.
2. You share your link: `https://app.10102.io/?via=acme`. No signup, no dashboard, no integration work. Links written on `www.10102.io` or the bare `10102.io` carry the code through as well; the `app.10102.io` form is the canonical one to publish.
3. When someone arrives through your link, their browser remembers your code for **90 days** (last qualifying click wins). If they buy Premium in that window, the purchase is attributed to you.
4. We settle monthly in USDC on Ethereum, with a statement listing the purchases behind the number.

## Why you don't have to trust us

Premium is bought on-chain, so every attributed purchase corresponds to a real, public Ethereum transaction. Our attribution ledger refuses to record anything it cannot verify against the chain:

* The transaction must be mined, successful, and contain a Premium purchase event from the real registry contract.
* Each purchase can be credited **once**, ever; replayed or duplicate reports are rejected.
* The system stores no personal data: an attribution is a transaction hash, a wallet address that is already public on-chain, and your code.

Your statement gives you the transaction references, and you can confirm every one of them on Etherscan yourself.

## Self-serve stats

Every partner receives a private stats token (`pt_…`). It is scoped to your code only and never exposes purchaser addresses:

```bash
curl -H "Authorization: Bearer pt_your_token" \
  https://api.10102.io/referral-stats
```

The response contains your totals (`purchases`, `unique_purchasers`, first and last purchase timestamps, and `active_subscribers`) plus your most recent attributed transactions.

`active_subscribers` is computed live from the chain: it counts your unique purchasers whose Premium is still active right now (lifetime plans stay counted; expired annual plans drop off). This is the number volume bonuses are measured against.

Treat the token like a password. If it leaks, we rotate it on request; rotation is always explicit, so routine account changes never silently invalidate it.

## Commission and payout terms

| Tier          | Commission                                        | Best for                                         |
| ------------- | ------------------------------------------------- | ------------------------------------------------ |
| Standard      | 20–25% of the first purchase                      | Creators, communities, media                     |
| Advisor / B2B | 10–15% recurring on renewals, plus volume bonuses | Advisors and businesses bringing ongoing clients |

Exact rates are set in your partner agreement; we keep deal terms private on both sides.

* Monthly settlement in USDC on Ethereum, to a wallet you control.
* Balances under $100 roll over to the next month. If participation ends, the final balance pays out in full, even below that threshold.
* Statements can be disputed within **60 days** of issue.
* Either party may end participation with **30 days' written notice**; attributions already recorded are honored at the terms they were earned under.

## Discount mode (fee-barred professionals)

Some partners are legally barred from taking a percentage of a client's purchase, for example French avocats and notaires. For those relationships the code runs in **discount mode**: the buyer gets a reduced Premium price instead, and the partner receives no commission. The stats token works the same way, so you can still see and reconcile your attributed activity. Commission and discount never both apply to the same purchase. If your profession or engagement letter forbids referral fees, say so when we set up your code.

## Attribution through AI agents

If you build on the [MCP server](/agents-and-builders) with a partner key, your key can carry your referral code: setup links your integration generates then attribute Premium purchases by the clients your agent onboards to your partner account, on the same verified ledger and the same statement.

## Fair play

No self-referral, no paid-search bidding on our brand terms, no representing yourself as 10102, and no marketing that promises investment returns. Purchases that are refunded, reversed, granted as promotions, or made by the partner themselves do not qualify. Partners are independent parties responsible for their own taxes and for the disclosure rules that apply to them (for example, telling your audience a link is a referral link where required).

## Getting started

Send us two things: the code you'd like, and the USDC address for payouts, to <info@10102.io>. Your link works the same day.

Where this page and the published [Partner Program Terms](https://10102.io/partner-terms) differ, the published terms control; a signed partner agreement controls over both.


# Design & Engineering Notes

The "why" behind the harder engineering decisions in 10102 Computing Legacy. Useful for auditors, integrators, and future maintainers.

This section is for readers who want to understand why the app is shaped the way it is, not just what it does. If you're picking up the codebase to contribute, audit, or integrate against it, this is the place that explains the trade-offs the [Architecture](/architecture) section takes as given.

We deliberately kept this section small. There are thousands of small decisions in the codebase; only a handful are load-bearing enough to warrant a page here.

## What's in this section

* [Inactivity Detection](/dev/technical-analysis): the hard problem at the heart of the product, and why the EOA and Safe paths look different.
* [Core Mechanisms](/dev/core-mechanisms): the system's moving parts (CREATE2, upgradeable proxies, heartbeat, the router pattern) explained at the level of "what each piece is responsible for and why it exists."
* [Roadmap](/dev/backlog): public ledger of planned work and explicitly deferred items, with enough context to understand each trigger condition.

## Principles we try to live by

A few opinions we fall back on when we're not sure which way to go:

* **Plan survives us.** Every feature must have a path to activation that doesn't require our UI, servers, or company. This is the single most important principle. It shows up as the Legacy Claim Card, as verified contracts on Etherscan, as public source code and audits, as multisig-controlled upgradeability.
* **On-chain authoritative, off-chain additive.** Anything our backend or any third-party service (e.g. Mailjet for the off-chain reminder worker) contributes must be verifiable against on-chain state, and its absence must degrade UX but not correctness. Activation itself takes no off-chain input; there is no activity oracle in the trust path.
* **Two thin routers beat one fat one.** The EOA and Safe legacy flows share \~80% of their semantics, but the 20% that differs is different enough that conflating them makes both paths carry each other's complexity. The same applies to the three timelock flavors (Timelock / Soft / Gift) being distinct code paths.
* **Explicit is better than clever.** For a long time this principle meant the EOA create flow was two separate transactions (deploy, then approve), because the explicit version was easier for users to verify than a wallet-magic bundle. Create-flow v2 collapsed that to a single confirmation *without* giving up the property the two steps protected: the permission the user grants is a Permit2 allowance to one immutable, published vault contract that any wallet can verify, which is strictly easier to audit than N approvals to a fresh per-user address. The durable form of the principle: never trade verifiability for fewer clicks; look for the design that gets both. See [How Legacy Creation Works](/architecture/create-flow-v2).
* **Fail closed on activation.** We bias every uncertain case toward *not* activating early: a delayed real claim is recoverable (the owner heartbeats, the beneficiary retries once the window elapses), a premature disbursement is not. For EOAs this is why the inactivity timer only resets on the owner's own legacy interactions rather than on a best-effort guess about their wider wallet activity.

## What's *not* here

We deliberately don't publish:

* The specific signer set of the `DefaultProxyAdmin` Safe. Available on request; not broadcast to reduce targeting.
* Operational runbooks, incident playbooks, or internal monitoring dashboards. Those belong in a private ops repo, not in user-facing docs.
* Unsigned/unpublished upgrade plans. When we do upgrade, the plan is published before the transaction.

## Where things actually live

* **Contracts + tests + audits** → [`github.com/10102-io/computing-sc`](https://github.com/10102-io/computing-sc)
* **Audit reports** → [`github.com/10102-labs/audits`](https://github.com/10102-labs/audits)
* **Contract addresses (per network)** → `contract-addresses.json` in the `computing-sc` repo
* **Security disclosures** → `security@10102.io`
* **General questions** → `info@10102.io`


# Inactivity Detection

The core engineering challenge behind an on-chain legacy product, and the trade-offs baked into how we solved it.

Every legacy flow in this product turns on one question: *has the owner been inactive long enough to trigger activation?* Getting that question right, **on-chain**, for an arbitrary Ethereum wallet, is harder than it sounds, and the shape of our product is largely a consequence of the trade-offs we accepted.

## The core problem

A smart contract executing on the EVM has very limited information about other accounts:

* It can read state of *contract* accounts it's given the address of.
* It can read its own past transactions.
* It **cannot** directly read the timestamp of the most recent outgoing transaction from an externally-owned account (EOA).

The last point is the constraint. There's no `block.getLastTxOf(wallet)` or equivalent. You can read *what* happened to an account's storage, but an EOA has no storage: just a balance and a nonce, neither of which timestamps anything.

This is a deliberate EVM design choice (the state trie doesn't carry per-account metadata like last-tx-time), not an oversight. Working around it is the job of the application layer.

## Four possible approaches

When we started, four approaches were on the table:

1. **Off-chain oracle**: have a backend service watch wallets and submit activity attestations on demand. *Rejected as the mandatory path:* centralizes trust on our backend, violates "plan survives us." (A much narrower, strictly **opt-in** form of this later shipped as [auto-renew](/architecture/eoa-activity-auto-renew), with every safety bound on-chain so the attestor can only ever delay activation; see below.)
2. **Decentralized oracle**: delegate to a general-purpose oracle network that already tracks wallet activity. *Rejected:* no decentralized oracle we evaluated had production-grade coverage of EOA activity data, and bridging a third-party activity verdict back on-chain at activation time adds an external dependency (and a recurring cost) to the one moment that matters most. We'd rather not put an oracle in the activation trust path.
3. **Custom wallet functionality**: require the owner to use a wallet that exposes a last-tx hook. *Partially adopted:* this is exactly what the Safe Guard integration does for Safe users.
4. **Restructured flow**: redesign the UX so the contract doesn't need to know the owner's *general* last-tx timestamp at all, and instead tracks activity that the contract *can* see natively. *Adopted for EOAs:* each EOA legacy keeps an on-chain inactivity timer scoped to the legacy itself, reset by any interaction with it (edits, withdrawals, swaps) or an explicit "I'm still alive" heartbeat.

We ended up with (3) for Safe owners and (4) for EOA owners.

## The Safe path: approach 3

When the owner's wallet is a Safe (a smart-contract wallet with the plug-in points we need), we install a **Safe Guard**: a small contract (`SafeGuard`) that Safe calls before every transaction execution via the Guard interface's `checkTransaction` hook. Our Guard stamps `lastTimestampTxs = block.timestamp` on every such call, storing it in its own contract state.

That's the entire trick. At activation time, the per-legacy contract's on-chain check reads that timestamp directly from the Guard (`getLastTimestampTxs()`) and gates activation on `lastTimestampTxs + inactivityWindow <= block.timestamp`. Fully on-chain, no oracle, no trust.

There's a subtle elegance here: the Guard works regardless of what the Safe is doing. A Safe owner's *normal* transactions (DeFi, staking, voting, whatever) update the Guard implicitly. The owner doesn't need to remember to "check in." Normal usage *is* the check-in.

This is why the Safe flow is the path we recommend for users who already have a Safe. It's cleaner, cheaper, and fully self-contained.

## The EOA path: an on-chain inactivity timer

EOAs have no code, so there's nothing to hook and no way for a contract to observe what the owner does *elsewhere* on-chain. Rather than reach for an external oracle to fill that gap, the EOA path narrows the question to something the contract *can* answer by itself: **has the owner interacted with this legacy recently?**

Each EOA legacy stores its own `_lastTimestamp` (a last-activity timestamp) and a `lackOfOutgoingTxRange` (the configured inactivity window). The check at activation time is a single on-chain comparison, with no external call:

```solidity
// TransferEOALegacy._checkActiveLegacy()
if (_lastTimestamp + lackOfOutgoingTxRange > block.timestamp) {
  return false; // owner still considered active; activation not allowed
}
return true;     // inactive long enough; eligible for activation
```

`_lastTimestamp` is reset to `block.timestamp` by any owner interaction with the legacy: creating it, editing beneficiaries/allocations/trigger/name, withdrawing, the auto-swap / unswap helpers, receiving ETH directly from the owner, or the explicit `activeAlive` ("I'm still alive") heartbeat. A beneficiary can then call activation permissionlessly; the contract itself decides whether the window has elapsed.

This is, in effect, the check-in model: the thing teams usually reject as "babysit the app" UX. We make it tolerable two ways: **normal management of the legacy already counts** (any edit resets the timer, so an owner who is actively maintaining their plan rarely needs a bare heartbeat), and **the heartbeat is cheap and explicit** (\~21k gas, one button) for owners who aren't otherwise touching it.

The honest trade-off: an EOA owner who is busy on-chain elsewhere but never touches their legacy will see the timer keep counting. Arbitrary transactions from their EOA are invisible to the per-legacy contract, and by default nothing fills that gap; the owner is expected to check in. We accept that limitation in exchange for an activation path that is fully on-chain, free of external dependencies, and impossible for any off-chain party to spoof.

For owners who want the gap filled, **auto-renew** (Premium, opt-in, default off) adds a bounded attestor: it observes the owner's public transaction count and resets the timer near the deadline, with every safety property (opt-in gate, strictly increasing nonce, 30-day near-deadline window, 365-day budget since the last real check-in) enforced on-chain, so a compromised attestor can only delay activation, never accelerate it. Full trust model: [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).

### Why the Safe path looks different

Safe owners get a strictly nicer property: the Safe Guard updates the activity timestamp on *every* Safe transaction, so a Safe owner's normal on-chain activity (DeFi, staking, voting) implicitly keeps the legacy fresh; no deliberate check-in required. EOA owners only get credit for activity that touches the legacy. Both paths are fully on-chain at activation time; the Safe path simply observes a broader definition of "active" because the wallet itself cooperates.

## Failure modes and their consequences

| Failure                                              | Safe legacy                                                                                                                              | EOA legacy                                                                                                                                                                                                                                   |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| App / backend / indexer outage                       | No impact on activation: the on-chain comparison runs without any of them.                                                               | No impact on activation: same on-chain comparison, no oracle in the path.                                                                                                                                                                    |
| Owner active elsewhere but never touches the legacy  | Guard captures the activity automatically; timer stays fresh.                                                                            | By default the timer *keeps counting*, since only legacy interactions count; the owner must heartbeat or edit to reset it. With [auto-renew](/architecture/eoa-activity-auto-renew) enabled, the attestor renews for them near the deadline. |
| Owner changes signer set on Safe                     | Guard still tracks activity; legacy continues to work.                                                                                   | N/A                                                                                                                                                                                                                                          |
| Owner rotates EOA key                                | N/A                                                                                                                                      | Key rotation isn't visible to the legacy at all; the inactivity timer keeps counting. Owners need an explicit heartbeat or edit after rotation.                                                                                              |
| Guard gets disabled without a matching legacy delete | Edge case we test against. Router detects missing Guard at activation and blocks. Legacy can be cleaned up via the explicit delete flow. | N/A                                                                                                                                                                                                                                          |

The failure we care about most is the one that activates *too early*, because it's irreversible. For EOAs the relevant risk runs the other way: the timer can only be reset by the owner, so the realistic failure is activating *too late* (owner forgot to check in), which is recoverable; they just heartbeat. Our design prefers a recoverable delay over an irreversible premature disbursement.

## Future: account abstraction

EIP-4337 and the broader account-abstraction push make this problem easier. An AA wallet can expose its own last-transaction timestamp as naturally as a Safe's Guard does today, and eventually "every wallet is a smart wallet" collapses the EOA/Safe distinction entirely. We expect to add an AA-specific integration when AA wallets have standardized a reasonable way to expose this.

Until then, the two-path design is the best honest trade-off we've found.


# Core Mechanisms

The moving parts of the system and what each one is responsible for. Useful as a mental model before diving into specific contracts.

This page is a map of the primitives the app is built on. Each section is short by design: the goal is to give you enough vocabulary to navigate the [Architecture](/architecture) section with confidence, not to re-explain it.

## Private keys and the custody model

Every Ethereum account, EOA or smart contract, is ultimately secured by one or more private keys. The 10102 app **never handles the owner's private key**: all signing happens in the user's wallet (browser extension, hardware device, Safe co-signing flow). We have no custodial fallback, no password reset, no "sign in with Google" backdoor. This is a feature.

When the app does generate a new key (for a beneficiary who doesn't have an Ethereum address), it happens entirely client-side and the key is delivered to the owner as a QR code on the printable [Legacy Claim Card](/user-guide/legacy/legacy-claim-card). The app's backend never sees it. See [New Account Generation for Beneficiaries](/architecture/new-account-generation-for-beneficiaries) for the mechanics.

## Smart contracts

Every piece of state that matters long-term (a legacy, a timelock, a premium subscription) lives in a smart contract on Ethereum, not in our backend. Three traits shape how they're designed:

* **Per-user contracts.** Each legacy or timelock gets its own contract instance, deployed deterministically via `CREATE2` (see below) at a predictable address. Per-user *storage* is always isolated: one user's activity can't reach another's slots. For EOA transfer legacies, the on-chain code is shared across users via an [EIP-1167 minimal proxy](https://eips.ethereum.org/EIPS/eip-1167): each clone is a \~45-byte forwarder pointing at one audited `TransferEOALegacy` implementation per network. Multisig and timelock flows still deploy full per-instance contracts; the EOA path adopted clones to cut creation gas by \~80% on a high-volume flow.
* **Upgradeable routers.** The code that *creates* legacies (the routers) sits behind a transparent proxy whose admin is owned by a public 48-hour upgrade timelock (see [Upgrade Policy](/architecture/upgrade-policy)). We can patch bugs and ship improvements (after a public queue anyone can watch), but cannot silently change the rules of an existing legacy because per-legacy state is in the per-legacy contract, not in the upgradeable router.
* **Verified.** Every deployment is verified on Etherscan. Addresses and ABIs are published in `contract-addresses.json` of the `computing-sc` repo.

## CREATE2 and predictable addresses

The EVM has two deploy opcodes: `CREATE` (address depends on the deployer nonce, changes over time) and `CREATE2` (address depends on the deployer + a salt + the initcode hash, fully deterministic).

10102 uses `CREATE2` for all per-user contract deployments. Practical consequences:

* **Pre-deploy disclosure.** We can show the owner the address of their legacy contract *before* they sign the creation transaction. What they sign is what they get.
* **Stable Etherscan history.** Because the initcode hash is the same across all users' legacies of a given type, wallets and explorers can recognize the contract family and drop "suspicious contract" warnings on post-deploy approvals.
* **Auditability.** The address of any legacy can be recomputed from the owner + salt + version. Beneficiaries can verify.

## The router pattern

Routers are the "front door" to each flow:

* `MultisigLegacyRouter` / `TransferLegacyRouter` / `TransferEOALegacyRouter` for the three legacy flows.
* `TimeLockRouter` for all three timelock flavors.
* `PremiumRegistry` for subscriptions; `PremiumSetting` for watcher/reminder configuration.

Each router owns the *deploy-or-update* logic for its flow. Per-legacy (or per-timelock) contracts are minimal: they hold state, emit events, and are callable by the router. This split lets us:

* Upgrade a router to fix bugs or add features without touching existing per-instance contracts.
* Audit each flow in relative isolation.
* Keep per-instance gas cost low: the EOA transfer flow uses EIP-1167 clones that cost \~1.05M gas per create on mainnet (down from \~6M pre-refactor), and the other flows keep their per-instance bytecode deliberately small.

## Heartbeat and activity tracking

A legacy's activation trigger is an inactivity threshold: "activate if the owner has been idle for N days." The app tracks activity in two fundamentally different ways:

* **Safe owners** have a [Safe Guard](/architecture/legacy-contracts-created-with-safe-sdk) installed (the `SafeGuard` contract) that stamps `lastTimestampTxs = block.timestamp` on every Safe transaction. Activity tracking is passive and fully on-chain.
* **EOA owners** use a per-legacy on-chain inactivity timer that resets on heartbeat / edit / withdraw / swap events. Activation is a single on-chain comparison against that timer. Activity that doesn't touch the legacy is invisible to it by default, so EOA owners are expected to check in, unless they opt in to **auto-renew** (Premium), where an attestor observes the wallet's public transaction count and renews the timer for them within strict on-chain bounds (it can only delay activation, never accelerate it). See [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking) and [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).

Both paths surface an explicit "I'm still alive" button in the UI for owners who want a deliberate heartbeat. The button is cheap (\~21k gas for EOAs) and unambiguous.

## Indexing

The app reads most of its state from subgraphs on [The Graph](https://thegraph.com), which index router events for fast, reliable queries. Subgraphs are eventually consistent (after a transaction mines, there's a brief window before events appear), so the UI falls back to direct on-chain reads via viem for freshness-critical paths like "did my legacy actually get deleted?" See [Indexing & Activity Tracking](/architecture/indexing-and-activity-tracking) for the details.

## Premium

Premium is a time-bound subscription sold for ETH, USDC, or USDT, recorded on-chain in `PremiumRegistry`. While a subscription is active, its wallet can configure:

* **Contingent beneficiaries**: fallback layers that activate if primaries don't claim within a configurable window.
* **Authorized watchers**: read-only accounts that can view a legacy but never edit or activate.
* **Email reminders**: opt-in notifications at key lifecycle events, powered by an off-chain reminder worker that keeps recipient emails encrypted off-chain (replacing the retired Chainlink Automation cron + Chainlink Functions email path; see [Email Reminders](/architecture/email-reminders)).

Premium is deliberately orthogonal to the core flows: every legacy works without it, and losing Premium (letting the subscription lapse) doesn't break existing legacies; it just freezes configuration changes on the Premium-gated surfaces until renewal.

## Storage tokens

ETH can't be granted "approval" the way ERC-20 tokens can. To include native ETH in a Transfer legacy or a Timelock with a uniform approval model, the owner swaps ETH into a **storage token** (WETH, or a liquid staking token like wstETH) via the in-app Uniswap integration, then grants the legacy/timelock approval on that storage token. On activation, the storage token is distributed to beneficiaries; they can unwrap it back to ETH themselves if they want.

This keeps the contract's permission surface uniform (everything is ERC-20) without forcing the contract to custody native ETH.


# Roadmap

What we're working on, what we've decided to defer, and the triggers that would bring deferred items back onto the active list.

This page is the public-facing summary of work ahead. It's deliberately high-level: specific implementation plans, test matrices, and detailed deferred items live alongside the code in the [`computing-sc`](https://github.com/10102-io/computing-sc) repo.

We publish this because the "plan survives us" principle applies to development too: users and integrators should know what's coming, what's on hold, and why, not just what shipped.

## Active work

Areas we're actively investing in over the next few release cycles:

* **Upgrade-timelock proposer hardening.** Contract upgrades already wait in a public 48-hour queue (see [Upgrade Policy](/architecture/upgrade-policy)); the planned next step is moving the proposer role from a single maintainer key to a multisig. Thanks to the timelock, that change will itself be publicly visible when it happens.
* **Asymmetric-permission fix for Multisig legacies.** Today, any Safe owner can edit on-chain fields (beneficiaries, activation trigger, name/note) at Safe threshold, but only the original creator EOA can edit off-chain notification settings (watchers, email reminders). We're designing a `transferCreator` function in `PremiumSetting` to resolve the asymmetry; it needs a proxy upgrade, which we're bundling with the next round of other improvements rather than shipping alone.
* **Better error messages and offline tolerance.** Ongoing: the generic "something went wrong" errors are being replaced with specific, actionable messages. Includes distinguishing subgraph outages, RPC latency, wallet rejections, etc.

## Recently shipped

Formerly on this list, now live on mainnet:

* **Partner referral program (phase 1).** Partners share a link (`app.10102.io/?via=code`); attribution is recorded only after the purchase transaction is verified on-chain, each purchase credits once, and every partner gets a scoped stats token to reconcile statements independently, including a live `active_subscribers` count read from the chain. See the [Partner Program](/partners) page. On-chain attribution proofs and automatic payment splits remain deferred until volume justifies the contract-upgrade surface.
* **Audit round 2 (CDSecurity).** The follow-up audit is complete: CDSecurity reviewed the full suite, including the timelocks and premium contracts added since the first audit, with the report published October 2025 in [`github.com/CDSecurity/audits`](https://github.com/CDSecurity/audits) and mirrored in [`github.com/10102-labs/audits`](https://github.com/10102-labs/audits). The original legacy contracts were audited by RockSolid Security ([report January 2025](https://github.com/10102-io/computing-sc/blob/main/Security_Review_Computing_Will.pdf)).
* **Permit2 one-confirmation creates.** Creating a Transfer legacy or timelock is now a single confirmation: one signed Permit2 batch replaces the per-token `approve` transactions, and tokens stay in the owner's wallet until claim. This also delivered the single-prompt create flow we previously tracked under EIP-5792 batching.
* **EIP-1167 minimal-proxy clones for EOA legacies.** New EOA legacies deploy as \~45-byte clones of one audited implementation per network, cutting creation gas by 80%+. Existing legacies are unaffected.
* **EOA activity auto-renew.** Opt-in Premium feature: an attestor observes the owner's public wallet activity and renews the inactivity timer for them, with every safety bound on-chain. See [EOA Activity & Auto-Renew](/architecture/eoa-activity-auto-renew).
* **Timelocked upgrades.** `DefaultProxyAdmin` is now owned by an on-chain upgrade timelock: every implementation change waits in a public 48-hour queue before it can execute. See [Upgrade Policy](/architecture/upgrade-policy).
* **Gas-sponsored claims.** A beneficiary with no ETH can claim by signing a free EIP-712 authorization; 10102's relayer submits the transaction and pays the gas. The app switches to this path automatically when the beneficiary's wallet can't cover the fee. See [Gas-Sponsored Intents](/architecture/gas-sponsored-intents).

## Under evaluation

Ideas we think are promising but haven't committed to:

* **SafeNet integration.** Safe Foundation's forthcoming decentralized transaction-security layer. We've drafted a technical brief ([available on request](mailto:info@10102.io)) covering how our Safe Guard interacts with SafeNet's Transaction Guard contract. Waiting for SafeNet's Phase 2 to stabilize before committing.
* **ERC-8211 smart batching.** Runtime parameter injection and pre/post assertions for multi-transaction flows. Most relevant for the beneficiary-side batch claim path (100+ transfers). Evaluating whether it adds enough over EIP-5792 to justify the complexity.
* **AA wallet integration (EIP-4337).** When AA wallets standardize a way to expose "last outgoing transaction timestamp" on-chain, we can collapse the EOA/Safe activity-tracking distinction. Not a standard yet; tracking the ecosystem.
* **EAS attestations.** Using the Ethereum Attestation Service to let third parties attest to legacy validity (trusted auditor attestations, beneficiary co-testimony for conflict resolution). Schema design is the open question.
* **More beneficiary-onboarding paths.** The current "generate a new address" flow is good for crypto novices but limited. Ideas include passkey-based smart accounts and delegate.xyz-style hot/cold separation for the claim address.

## Deferred

Items we've explicitly decided to *not* do now, with enough context to pick them up later:

* **Native NFT transfer for Multisig legacies.** NFTs held by the Safe are covered automatically because the whole Safe passes. NFTs as first-class asset types in *Transfer* legacies are intentionally not supported yet: the allocation semantics ("how do you split a single NFT across 3 beneficiaries?") don't have a clean product answer.
* **Multichain deployment beyond mainnet + Sepolia.** Technically straightforward but substantially increases operational surface. We'd rather do mainnet + Sepolia extremely well than ship on 5 chains with half-working cross-chain UX.

A more granular list, with triggers for when each item becomes urgent, lives in the `computing-sc` repo alongside the code, so `git log` is the audit trail.

## How to influence this

* **Security issues** → `security@10102.io`. We take these seriously and will disclose per responsible-disclosure norms.
* **Feature requests and bug reports** → issues on [`github.com/10102-io/computing-sc`](https://github.com/10102-io/computing-sc/issues).
* **General feedback** → `info@10102.io`.

We don't promise to ship everything that's requested, but we read all of it and it genuinely shapes what moves from "under evaluation" to "active work."


