The Edge model
Most blockchain infrastructure providers hold your keys. That is what makes their API a single call — and it is also what makes them able to move your funds, and what makes a compromise of theirs a loss of yours.
ChainOS splits the problem instead. The consequence is a container you have to run. This page is about why that trade is worth it and what it costs you.
Two components
chainos-edge is a single static Go binary, in a scratch image, running in your
network. It is the only component that ever sees key material. It reads your BIP-39
mnemonic from a mounted secret, derives your extended public keys, registers them with
Cloud over a signed channel, terminates the full ChainOS API on port 8787, signs every
transaction, and relays webhooks to your endpoint.
chainos-server is one Java artifact that runs in five roles, operated by Ziklag.
It derives receive addresses from your extended public keys, watches
the chains for activity on those addresses, tracks confirmations, constructs unsigned
transactions, broadcasts what your Edge has signed, and delivers events.
What each side holds
| Your Edge | Cloud | |
|---|---|---|
| BIP-39 mnemonic | ✅ mlocked, zeroed after use | ❌ never |
| Child private keys | ✅ derived on demand, never persisted | ❌ never |
| Edge identity private key | ✅ derived at m/83696968'/0'/0' | ❌ never |
| Extended public keys | ✅ | ✅ encrypted at rest |
| Edge identity public key | ✅ | ✅ pinned on first sync |
| Address ledger, transactions | mirrored | ✅ authoritative |
| Chain RPC credentials | ❌ | ✅ |
That table is the whole architecture. Everything below is a consequence of it.
The request flows
Issuing an address needs only public data, so it does not need your Edge to be reachable at that instant — but it does need Cloud to have your extended public keys, which means the Edge must have synced at least once.

Issuing an address touches no private key at all.
Solana and Stellar are the exceptions and cannot work this way at all. Both are Ed25519, which has no public-key-only child derivation, so no extended public key exists to store and their addresses come from a pool the Edge fills. See HD derivation.

Watching for deposits is entirely Cloud-side. Chain event streams push into the
ingest role, which normalises them onto the event bus; processor matches them against the
address registry, writes the ledger and tracks confirmations; dispatcher delivers the
webhooks. Your Edge is not on this path except as the last relay hop.
Sending funds is the one flow that requires all three parties, in order:

Cloud can propose a transaction. Only your Edge can sign one. A compromised Cloud can therefore ask your Edge to send funds somewhere, which is why autonomous spend authority is capped Edge-side and defaults to zero — see Non-custodial.
Connection direction is an invariant
Every connection is dialled outbound by the Edge: the sync, the heartbeat, the gRPC stream, the lease calls. Cloud never initiates a connection to your infrastructure.
That means the Edge needs no inbound firewall rule, no public ingress, no load balancer and no DNS record. In a bank, those four things are each a change request with a different owner, and avoiding all of them is usually what gets this product approved.
The gRPC channel is bidirectional once open, so Cloud can ask the Edge for something — more pool addresses for Solana or Stellar, a signature — but only over a stream the Edge itself opened.
One artifact, five roles
chainos-server selects its behaviour at run time from CHAINOS_ROLES:
| Role | Responsibility |
|---|---|
api | REST, the console, the docs, the OpenAPI document |
gateway | Edge gRPC streams, leader leases |
ingest | Chain event stream receiver |
processor | Event-bus consumers, the ledger, confirmation tracking |
dispatcher | Webhook delivery and the retry ladder |

A module is a compile-time boundary. A role is a run-time selection. They are different axes.
Production runs five role-specialised replica sets that scale independently, from the
same image — ingest scales for provider bursts, processor for chain volume, api for
console traffic, and those three genuinely move apart. A development machine runs all
five in one process.
The reason it is one artifact rather than five services: one artifact has one version, one migration history and one thing to roll back. That is also why the console is a static bundle inside the JAR rather than an app needing a Node runtime, and why there is no Redis.
Internally the code is fourteen modules with boundaries verified in CI, which is a different axis from roles: a module is a compile-time boundary, a role is a runtime selection.
What it costs you
Stating the trade honestly, because the alternative genuinely is simpler:
- You run a container. One, with two required environment variables, but it is yours to deploy, monitor and upgrade.
- You own the mnemonic. Nobody can recover it. This is the real cost and it is a process cost, not a technical one — see Mnemonic management.
- Some operations need the Edge live. Signing, obviously. Solana and Stellar address allocation, because both pools come from the Edge. Everything else — address issuance on the other seven chains, balances, deposit monitoring, webhook delivery — survives an offline Edge, with webhooks arriving late rather than being lost.
- An offline Edge is visible, not silent. Liveness is polled and
edge_offlineis itself a webhook event.
What you get for it
- Ziklag cannot move your funds. Not by policy — by what it holds.
- A compromise of Ziklag is not a loss of your funds.
- Your application holds no Ziklag credential.
- No inbound network exposure.
- The
derivationPathon every address is absolute, so you can recover funds with any standard BIP-32 tool and no ChainOS at all.
Further reading
- What Ziklag can and cannot do — the guarantees and the residual risks, stated together.
- HD derivation — the paths, and why Solana and Stellar are different.
- Edge installation — actually running it.
- High availability — multiple replicas and the leader lease.