orangecheck · Custody contract
Status: this is the design, not today. No federation is bound.
/api/federationsis the machine-readable answer and it currently serves a single entry with no invite, so no client can join one. While it is in testing, OrangeCheck holds every user's accrued balance and is the party that moves it. That is a stage, deliberately: OrangeCheck operates every role until independent operators take them. Read the descriptor schema, graduation envelope and rotation rules below as the contract that comes into force when a federation binds, and ochk.app/custody as the present tense.
ochk.app is designed to be federation-custodied by default, with a move to
your own keys 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).
Two questions get conflated here, and this page used to conflate them.
Self-custody of your signing key is live and real on the BIP-322 path — that
key never reaches OC. Self-custody of your sats is not live for anyone. The
rest of this page is about the second one. The in-tree audit at
NON_CUSTODIAL_AUDIT.md
walks the gap with file paths.
What "federation-custodied" will mean
Once a federation is bound, your orangecheck account is backed by 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. The guardians threshold-sign on your behalf when you sign in; you don't see it and never need to.
None of that is in force. The guardians that once ran this were torn down in
July 2026, and the browser-side Fedimint client that would have joined a
federation was removed from oc-me-web in September 2026 — it could only ever
reach its own error path.
The three options at threshold
| signing_method | how it works | live today? | |
|---|---|---|---|
| federation custody (the destination) | fedimint_threshold | guardians collectively hold the key. recovery by re-proving email. | no. no federation is bound, so no client can join one — /api/federations publishes that state. |
| fedimint client | fedimint_threshold (different federation) | sweep to a fedimint federation you trust more (your community's, your country's, your own). | opens once (1) binds; depends on the graduation envelope. |
| self-custody | bip-322 | sweep 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) and the signing key is yours. the sat sweep is not — there is no federation balance to sweep. |
The protocol accommodates the round-trip back to federation custody 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" }
]
}
| Field | Rule |
|---|---|
from_federation | Content hash of the federation custody descriptor releasing the address. |
to | "single-key" (graduating to BIP-322) or "federation" (re-binding to a new descriptor). |
proof | M signatures from M of N declared guardians PLUS one self-key signature. |
graduated_at | ISO-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/balance UI, which states today
what it can and cannot do. The producing path — collecting a quorum signature
from a real federation — opens when a federation binds.
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 move to your own keys
| Stays the same | Changes |
|---|---|
| Your bitcoin address (the canonical identifier) | The signing method (fedimint_threshold → bip-322) |
| Your backing, if you backed your account with a coin | Who holds the private key (you, instead of the federation) |
| Your /me/earn history, connected sites, agent delegations | How recovery works (you own backup; lose the key, lose the funds) |
| Your sat-earning rate | The 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
oc-attest-protocol/FEDERATION-CUSTODY.md— full v1.2-draft-1 specoc-agent-protocol/FEDERATION.md— sibling federation principal extension for delegationsoc-me-web/NON_CUSTODIAL_AUDIT.md— the in-tree audit · what's actually wired today vs the contract above- ochk.app/custody — product expression of this contract with live status pills per state
- ochk.app/security — the OC_STORES table, disappearance scenarios, recovery matrix per signin path
- ochk.app/me/balance — the move to your own keys