oc · me
§ custody · honest current state

OC never holds keys. Three custody paths — BIP-322 + federation custody both live.

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 — oc-me-1 has completed its DKG ceremony, its invite is bound, and email-OTP users provision a federation-custodied wallet against it. Federations are OC-provisioned (operators hold the keys, OC holds zero shares). The one remaining gated piece is the federation's Lightning gateway that routes ecash↔Lightning cash-out. This page is honest about all of it.

§ what works today

State (01) — BIP-322 self-custody — is fully live. State (02) — federation custody — is now live too: oc-me-1 completed DKG and its invite is bound, so the wallet provisions. State (03) (sweep to your own federation) and the graduation flow are unblocked. The one remaining piece is the federation's Lightning gateway that routes cash-out.

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 waiting on NEXT_PUBLIC_FEDIMINT_FEDERATION_INVITE to land OR a federation in the registry with status: 'live' — oc-me-1 is now that federation; the wallet client binds to its invite and provisions in the user's browser on next visit. Federation provisioning is shipped — OC provisions federations; operators hold the keys, OC holds zero shares — and oc-me-1 has completed DKG. The one remaining piece is the federation's Lightning gateway that routes ecash↔Lightning cash-out.
[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 are live too now that oc-me-1 has finished its DKG ceremony — federations are OC-provisioned (operators hold the 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

LIVE · oc-me-1 bound; the wallet provisions. Lightning cash-out gated on the federation gateway.

signing_method:
fedimint_threshold

The architecture: 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 OC has zero shares, cannot reach the threshold by itself, cannot move funds unilaterally. Recovery is between the user and the federation, not OC. Current state: the Fedimint web client is shipped (provider, panels, mnemonic-stays-in-IndexedDB, /me/graduate uses real `withdrawOnchain`); federation provisioning is shipped; oc-me-1 has completed its DKG ceremony and is `live` with its invite bound — email-OTP users provision a federation-custodied wallet against it and earn sats under their did. The remaining gated piece is the federation's Lightning gateway that routes ecash↔Lightning cash-out. OC provisions federations — four guardian seats on Fly.io infrastructure controlled by distinct hardware-backed operator keys, operators hold the keys, OC holds zero shares (see FEDERATION-DEPLOYMENT.md §1A · operational independence is enforced by operator-key diversity, not vendor diversity · the cryptographic invariant survives even when all daemons share a vendor since Fedimint threshold-signing prevents the vendor from moving funds).

§ 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 (DKG is done, invite bound)
[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

OC provisions federations: four guardian seats, 3-of-4 threshold, distinct hardware-backed operator keys, jurisdiction + hosting diversity preferred. OC the company is not a guardian on any of them. The first federation to finish its DKG ceremony binds as the email-OTP default; subsequent federations register as alternate invites in the registry overlay so users can pick whichever guardian set they prefer at signup.

§ 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 FEDERATION-DEPLOYMENT.md. 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.