oc · me
§ custody · honest current state

OC never holds keys. Two custody paths live — BIP-322 self-custody + federation custody.

Two things are simultaneously true: (1) OC holds zero private key material in any code path that exists (the integrator's project_key is theirs; BIP-322 users hold their own wallet; the Fedimint web client's mnemonic stays in the user's browser); (2) federation custody is live — a federation is bound and email-OTP users provision a wallet against it. Who actually holds the keys is shown live below — during bootstrap OC operates the guardian seats, so key-diversity across independent operators is the exit criterion before 'OC holds zero shares' is cryptographically true. This page is honest about all of it.

§ live custody posture
OC Testnet (bootstrap) · live
bootstrap

OC-operated custody during bring-up. Graduate to self-custody for zero trust in OrangeCheck — available today.

Any single operator can currently move funds. This is custody, not self-custody. You can hold your own keys today.

OC operates the guardian seats during bring-up — treat this as OC-operated custody.

§ who can move funds

OrangeCheck — seat roster not yet published

threshold 1-of-1 · 0 distinct operator keys · smallest colluding set 0 · trust anchor: OrangeCheck (bootstrap operator)

criteria · derived from the seat roster + signed charter
  • ≥4 guardian seats filled [verified]0/1 seats populated; production BFT floor is 4 (tolerates 1 fault). §1.1
  • threshold is a true majority [verified]1-of-1: 1 > ⌊1/2⌋ = 0. §1.2
  • every seat a distinct operator key [verified]0 distinct key(s) across 0 seat(s). The load-bearing §1.3/§1A check — bootstrap fails it.
  • charter hash published [verified]no valid 64-hex charter_hash on the row yet. §1.4
  • charter ratified by the guardians [verified]0/1 operator signature(s) match the current charter hash. §1.4
  • Lightning gateway run by a non-OC party [manual]the Lightning gateway is OC-provisioned today — honestly unmet. §1.5
  • OrangeCheck holds zero seats [verified]OC operates the guardian seats during bring-up. §1.6
  • distinct legal entities, ≥3 jurisdictions [attested]no signed operator-independence attestation yet. §1.3
  • on-chain exit clause in the charter [verified]no charter to carry the exit clause yet. §1.7
  • ongoing attestation is fresh [verified]no independence attestation to age. §1A
guardian membership is frozen post-DKG — climbing further means a NEW federation (fresh ceremony) + user migration, not an in-place upgrade
§ what works today

State (01) — BIP-322 self-custody — is fully live. State (02) — federation custody — is live too: a federation is bound, so the wallet provisions. State (03) (sweep to your own federation) and the graduation flow are unblocked. The live custody posture above is derived from the seat roster.

Email-OTP signin issues an opaque OC identity today (the user's session JWT carries did_oc = did:oc:<32-hex>; the email itself stays in a separate linked_identities table encrypted at rest). The Fedimint provider in /me/wallet is wired and binds once a federation is available — via NEXT_PUBLIC_FEDIMINT_FEDERATION_INVITE OR a registry federation with status: 'live'. That federation is now bound; the wallet client provisions in the browser on next visit. Federation provisioning is shipped (OC provisions federations; the derived posture above names who currently holds the keys). The remaining gated piece for cash-out is the federation's Lightning gateway that routes ecash↔Lightning.
[01]

self-custody · BIP-322

live · today

you hold your own keys, today.

signing_method:
bip322

Connect any BIP-322-capable Bitcoin wallet (UniSat, Xverse, Leather, Alby, Sparrow, your hardware wallet). Sign one challenge to bind the address as your OC identity. From that moment on, OC sees only your public address and your signatures — never private key material. Cashback streams as Lightning to the wallet you control. This is the path that works end-to-end today; states 02 + 03 depend on a federation being live (the derived posture above shows the current federation and who holds its keys).

§ what's good
  • + true sovereignty — only you can sign
  • + no third-party censorship · no recovery dependency
  • + verifies fully offline once you have the keys
  • + the protocol's native end-state
§ the trade
  • you own backup and recovery — lose the keys, lose the funds
  • requires comfort with Bitcoin wallet UX from day one
  • lightning self-custody requires a wallet that handles channels
[02]

federation custody · default for email-OTP

live · today

federation-custodied wallet on email-OTP signup; Lightning cash-out gated on the federation gateway.

signing_method:
fedimint_threshold

The architecture (target): signup via email-OTP provisions a Bitcoin wallet held by a Fedimint federation. Threshold-signing across the federation's guardians (M-of-N). OC integrates as a CLIENT of the federation, not as a guardian — so at full decentralization OC has zero shares, cannot reach the threshold by itself, cannot move funds unilaterally. Recovery is between the user and the federation, not OC. What's shipped: the Fedimint web client (provider, panels, mnemonic-stays-in-IndexedDB, /me/graduate performs a real on-chain withdraw via the SDK) and federation provisioning. Whether a federation is actually bound + live — and, if so, its tier and who currently holds the keys — is shown by the derived posture above, not asserted here. HONEST CAVEAT — a federation launches in BOOTSTRAP: during bring-up OC operates the guardian seats, so it is effectively OC-operated custody until guardian-key diversity (independent operators, jurisdiction + hosting diversity) is reached — the exit criterion before the cryptographic 'OC cannot move funds' invariant fully holds. If you want zero trust in OC, graduate to self-custody (01) at any time. Full cash-out also needs the federation's Lightning gateway. (See FEDERATION-DEPLOYMENT.md §1A — operational independence is enforced by operator-key diversity, and Fedimint threshold-signing prevents any single vendor from moving funds once the seats are held by distinct operators.)

§ what's good
  • + no seed phrase to lose · email-OTP recovery flow
  • + works for users who do not (yet) know what bitcoin is
  • + sat-earning starts immediately on signup
  • + graduates to BIP-322 self-custody whenever you want
§ the trade
  • federation custody is custody — guardians can collude (requires threshold)
  • recovery depends on the federation operator, not OC
  • Lightning cash-out is gated on the federation gateway coming online
[03]

federation client · choose your own federation

gated on (02)

AVAILABLE · (02) is bound — sweep to a Fedimint federation you trust more.

signing_method:
fedimint_client

Once a federation is bound for state (02), this becomes the migration path: sweep your sats from the OC-introduced federation to a Fedimint federation you trust more (your community's, your country's, your own). Same OC identity, different guardian set. Supports any fedimint-compatible client. The same Fedimint client that ships (02) handles this — `withdrawOnchain` to your destination, then re-bind to the new federation's invite. Gated only on (02) actually being live (i.e., a federation bound).

§ what's good
  • + choose guardians whose jurisdictions and operational profile you trust
  • + OC identity continues unchanged across the move
  • + most existing fedimint federations require no KYC
§ the trade
  • still custodial — just by a different threshold group
  • federation-level censorship is still possible
  • the migration path itself is operator/community-side; OC just provides the client
§ which federation, when (02) binds

OC integrates as a client, not as a guardian.

Critical design point: OC the company is NOT a guardian of the federation that will hold email-OTP user wallets. We integrate via the Fedimint client SDK (browser-side WASM, IndexedDB-backed wallet state) against an existing production federation. OC's role is to introduce the user to the federation at signup and provide the consumer UI; key shares live with the federation's independent operators, not OC. This is the architecture that makes the "OC cannot move user funds" claim cryptographically true rather than policy- only.

§ target backend

The target: four guardian seats, 3-of-4 threshold, distinct hardware-backed operator keys held by independent operators, jurisdiction + hosting diversity — and OC not holding a guardian seat. During bootstrap OC operates the seats to bring a federation up; the posture above reports the CURRENT tier honestly (bootstrap → key-diverse → operator-independent → decentralized). The first federation to reach live binds as the email-OTP default; subsequent federations register as alternate invites so users can pick whichever guardian set they prefer.

§ what OC contributes

UI surface (the React app at me.ochk.io), the federation introducer flow at signup (handing the user a federation invite), Lightning routing helpers (some API endpoints to facilitate receive/send via the federation's gateway). None of those operations require key material; OC the server holds none.

§ how the federation gets bound

The §1 properties (≥4 guardians, threshold > N/2, operational independence, signed content-addressed charter, non-OC LN gateway, OC not a guardian, exit clause), the three deployment paths (existing public federation / coordinated federation / federation pool at scale), and the idempotent provisioning script live in docs.ochk.io/me/federation. Public-facing explainer at docs.ochk.io/me/federation. Operator binds via yarn provision-federation --invite=… --charter=…, dry-runs first, then re-runs with --commit; the script refuses to bind if §1 fails.

§ graduation

federation → self-custody · wired, gated on federation bind.

Graduation is the bridge from federation custody (state 02) to self-custody (state 01). Mechanically: the user provides a destination Bitcoin address + signs a BIP-322 challenge proving control of it; the federation client initiates a withdraw to that address; on-chain (or Lightning) confirmation observed; the user's identity record's signing_method flips from fedimint_threshold to bip322 (every transition is recorded as an anchored rebind envelope · OTS-submitted, Nostr-published, visible on /verify/[id]). No fund custody passes through OC at any step.

§ honest current state

The /me/graduate UI is wired to the Fedimint client's withdrawOnchain primitive — when an email-OTP user has a provisioned federation wallet, clicking "sweep to self-custody" requests guardian threshold sigs and broadcasts the on-chain transaction. What's still pending is the production federation operator (NEXT_PUBLIC_FEDIMINT_FEDERATION_INVITE env var). Until that lands, the wallet stays in the "federation not yet configured" state and graduation isn't reachable because there's nothing to graduate from. Audit reference: NON_CUSTODIAL_AUDIT.md §2.8.

why federation custody is the right onboarding bridge

Self-custody is correct, eventually. Asking a brand-new user to handle a seed phrase on day one is the wrong onboarding. Most consumers will lose the seed, retreat to centralized exchanges, and the Bitcoin onboarding story stalls there.

Federation custody is the bridge. A threshold of operators collectively holds the keys; no single party (OC included) can spend or freeze. Recovery is by re-proving your email or phone via the federation's flow, not by remembering twelve words. When the user is ready, /me/graduate sweeps the balance to a wallet they own.

OC does not need to operate the federation to deliver this experience. Integrating as a client of an existing production federation gives users the federation operator's mature guardian set + recovery flow + uptime, while keeping OC out of the custody path entirely. That trade — zero key material at OC, in exchange for trusting the federation's published guardian operations — is the right call for v1. If we later run our own federation (with our own guardian seat among others), it will be additive, not a replacement.

Protocol-level shape — the descriptor schema, graduation envelope, M-of-N guardian threshold, OTS-anchored rotation — lives at docs.ochk.io/me/custody. That document is the spec contract; this page is the product expression of it, with status tags reflecting the current build.