live · mainnetoc · docs
specs · api · guides
docs / federation custody

OC Me · Federation custody

me.ochk.io is built to be federation-custodied by default, with a self-custody graduation flow on demand. This page is the user-facing explanation; the protocol-level contract is at oc-attest-protocol/FEDERATION-CUSTODY.md (v1.2-draft-1, additive extension).

Honest current state. The non-custodial audit (NON_CUSTODIAL_AUDIT.md) is the load-bearing reference for what is actually wired today. Read it before integrating against the federation surface — the descriptor schema below is a forward-looking contract, not a description of running guardians. The two paths that DO exist today are: BIP-322 (you sign in directly with your Bitcoin wallet, OC never holds keys) and email-OTP (a federation client scaffold is wired in oc-me-web/src/lib/fedimint, but Lightning send/receive and the graduation withdraw envelope are not yet shipped). Custodial state for email-OTP users today is NOT a running guardian set — it is a state machine that refuses to fabricate one.

What "federation-custodied" means

Your me.ochk.io identity is bound to a Bitcoin address (BIP-322 path) or a federation-issued ecash note set (email-OTP path). For the federation path, the private key that controls the underlying on-chain UTXOs is held collectively by an M-of-N guardian set — no single guardian (and not OC the company) can spend or freeze. Recovery is by re-proving your email, not by remembering twelve words.

When you sign in, the federation guardians threshold-sign on your behalf. You don't see this. You never need to.

The three options at threshold

signing_methodhow it workslive today?
federation custody (default)fedimint_thresholdguardians collectively hold the key. recovery by re-proving email.client scaffold + state machine wired; production federation invite pending.
fedimint clientfedimint_threshold (different federation)sweep to a fedimint federation you trust more (your community's, your country's, your own).once (1) is live; depends on graduation envelope.
self-custodybip-322sweep to any BIP-322-capable Bitcoin wallet (UniSat, Xverse, Leather, Alby, Sparrow, hardware wallet). only you can sign.sign-in is live (in-place, no redirect); explicit graduation envelope is in build.

You can return to federation custody at any point — the protocol accommodates the round-trip via attestation re-issuance under the new custody descriptor.

Graduation envelope

Per the v1.2-draft-1 oc-attest extension, graduation publishes an envelope carrying both an M-of-N guardian quorum sig (federation releases custody) and a self-key sig (you prove you hold the key now). The envelope is anchored to a bitcoin block via OpenTimestamps so any verifier can confirm graduation happened at a specific time.

{
    "v": 1,
    "kind": "orangecheck-graduation",
    "address": "bc1q...",
    "from_federation": "fed:abc123…",
    "to": "single-key",
    "graduated_at": "2026-04-30T20:00:00Z",
    "proof": [
        { "address": "bc1qg1…", "sig": "..." },
        { "address": "bc1qg2…", "sig": "..." },
        { "address": "bc1qg3…", "sig": "..." },
        { "address": "bc1q...", "sig": "...", "kind": "self-key" }
    ]
}
FieldRule
from_federationContent hash of the federation custody descriptor releasing the address.
to"single-key" (graduating to BIP-322) or "federation" (re-binding to a new descriptor).
proofM signatures from M of N declared guardians PLUS one self-key signature.
graduated_atISO-8601 timestamp; the OTS proof anchors this to a Bitcoin block.

The envelope contract is finalized at the spec level and reflected in the /me/graduate UI. The producing path (quorum sig collection from a real federation) is the integration the production-federation invite unlocks.

Guardian descriptor

A federation custody descriptor is a content-addressed canonical JSON object — same shape as oc-agent-protocol's federation principal, re-purposed for custody:

{
    "v": 1,
    "kind": "attest-federation-custody",
    "address": "bc1q…",
    "threshold": "3-of-5",
    "guardians": [
        { "address": "bc1qg1…", "alg": "bip322", "name": "alice" },
        { "address": "bc1qg2…", "alg": "bip322", "name": "bob" },
        { "address": "bc1qg3…", "alg": "bip322", "name": "carol" },
        { "address": "bc1qg4…", "alg": "bip322", "name": "dave" },
        { "address": "bc1qg5…", "alg": "bip322", "name": "erin" }
    ],
    "implementation": {
        "kind": "fedimint",
        "federation_id": "fed11qgqzcq…",
        "version": "0.4"
    }
}

The descriptor id is fed: + lowercase hex SHA-256(canonical_descriptor_bytes).

What stays the same when you graduate

Stays the sameChanges
Your bitcoin address (the canonical identifier)The signing method (fedimint_thresholdbip-322)
Your attest tier (anonymous / bonded / kyc-light / kyc-strong)Who holds the private key (you, instead of the federation)
Your /me/earn history, connected sites, agent delegationsHow recovery works (you own backup; lose the key, lose the funds)
Your sat-earning rateThe shape of signing_method in attestation envelopes

Guardian rotation

Guardian rotation produces a new descriptor with a new id. Old attestations remain verifiable against the old descriptor; new attestations bind to the new descriptor. Rotation envelopes are authenticated by M-of-N signatures from the old descriptor and OTS-anchored so any verifier can resolve the active descriptor at any historical instant.

Reading further