Authority Matrix (Stage 6/12)
Two layers must both agree before anything with financial effect happens:
- Application RBAC + four-eyes: who may request and approve, in the database.
- Stellar signatures: which keys can make the network accept it.
Neither layer trusts the other. The backend cannot issue alone (it holds no issuance-capable key), and human signers sign only proposals that reference an approved request (the signing tool shows the request ID and the decoded operations).
1. Stellar signer configuration
The number of human signers is configuration (ISSUER_SIGNERS, TREASURY_SIGNERS, 1–10 keys each); thresholds
follow from it (ceremony.Quorum): with n signers of weight 10, approving needs a = min(2, n) of them and a
signer change needs a + 1 when one lost key still leaves that reachable, else a.
| n | Approve (issue, burn, refill, clawback) | Change signers | Survives one lost key |
|---|---|---|---|
| 1 (launch, owner decision 2026-10-31) | 1 | 1 | No |
| 2 | 2 | 2 | No |
| 3 | 2 | 2 | Yes |
| 4 (reference design) | 2 | 3 | Yes |
At launch one person holds both the issuer key and the Treasury key (../decisions/OWNER_DECISIONS_20261031.md,
accepted risks). The table below is written for n signers H1…Hn and T1…Tn; the numbers in brackets are the launch
values.
| Account | Master | Signers (weight) | Low / Med / High | Notes |
|---|---|---|---|---|
ISSUER (one per asset) | 0 | H1…Hn (10 each), AUTH (1) | 1 / 10·a / 10·change (1 / 10 / 10) | Humans issue or claw back at the medium threshold; AUTH alone only SetTrustLineFlags |
TREASURY_COLD | 0 | T1…Tn (10 each) | 10 / 10·a / 10·change (10 / 10 / 10) | Refill and burn at the medium threshold |
TREASURY_HOT | 0 | HOT (10), T1…Tn (10 each) | 10 / 10 / 20 | HOT pays alone; a signer change needs HOT and one T, or two T |
RESERVE_SPONSOR | 0 | SPONSOR (10), T1…Tn (10) | 10 / 10 / 20 | Same shape as HOT |
FUNDER | 0 | FUNDER (10), T1…Tn (10) | 10 / 10 / 20 | Same shape |
CHANNEL_n, GOV_CHANNEL | 0 | CHANNEL (1) | 1 / 1 / 1 | Holds only fee XLM; worst case if lost: fees and sequence numbers |
| Customer accounts | 0 | CUSTODY (1) | 1 / 1 / 1 | Shared custody key; the app layer decides which account may be moved |
Every SetOptions that changes signers or thresholds goes through the signer-change procedure (../operations/ISSUER_OPERATIONS.md §2): a snapshot of the current configuration, the proposed one, a simulation proving every threshold stays reachable by the remaining signers if any one signer is lost (from three signers up), four-eyes in the app, the human signatures, then post-change verification by the authority watcher.
2. Online keys and blast radius
| Key | Can | Cannot | If compromised |
|---|---|---|---|
AUTH | Authorize or revoke trustlines | Issue, claw back, move tokens, change config | Freeze or unfreeze customers (DoS); authorize strangers (harmless, since only our accounts hold or send). Rotate at the issuer's high threshold |
HOT | Pay from TREASURY_HOT (to authorized holders only) | Touch COLD, issue, change signers | Loss ≤ float, and only to authorized accounts (all ours); recover with clawback; rotate via T |
CUSTODY | Move customer balances between authorized accounts, or to HOT/issuer | Issue, authorize | Customer balances can be shuffled among our accounts or burned to the issuer. Detected by the indexer (no matching intent memo); recover with clawback + re-issue |
SPONSOR | Sponsor new reserves | Move tokens | XLM loss ≤ its balance |
FUNDER / CHANNEL | Pay fees | Move tokens | XLM loss ≤ balance |
3. Application roles (RBAC)
Ported from the siblings' actor package, extended for Stellar.
| Role | Request | Approve | Read |
|---|---|---|---|
PLATFORM_ADMIN | Asset definitions, staff provisioning, trading suspend/resume, emergency gate close | Staff provisioning (other admin) | All |
RESERVE_MANAGER | Backing changes | — | Reserves |
RESERVE_APPROVER | — | Backing changes, issuance, burn, refill | Reserves, supply |
TREASURY_OPERATOR | Issuance, burn, refill; prices; cash entries | Cash entries made by others | Treasury |
COMPLIANCE_OFFICER | KYC approval, freeze, clawback requests | Unfreeze and clawback requested by others | Customers |
SECURITY_ADMIN | Signer-change requests, key rotation | Signer changes (with PLATFORM_ADMIN) | Security |
RECONCILIATION_OPERATOR | Run reconciliation; annotate findings | Close findings raised by others | Reconciliation |
AUDITOR | — | — | Everything, read-only |
SUPPORT | — | — | Customers and orders, read-only, no KYC documents |
Four-eyes (requester ≠ approver, enforced by a database CHECK and by the service): backing change, issuance, burn, Treasury refill, clawback, unfreeze, signer/threshold change, large price move, manual cash, staff provisioning.
High-risk request state machine: REQUESTED → APPROVED → AWAITING_SIGNATURES → EXECUTED, or REJECTED / EXPIRED / FAILED.
4. Signer proposal procedure (Stellar multisig without a hosted service)
- Approval creates a
signing_proposalsrow: the unsigned envelope XDR (sourceGOV_CHANNEL, op sourceISSUER/TREASURY_COLD,MEMO_HASHof the intent,maxTime= now + 24 h), its transaction hash, the network passphrase and the decoded operations. - Each human signer reviews the decoded proposal in the admin console (environment, network, asset, issuer, destination, amount, request ID, approvals: brief §71), then signs the hash on a hardware key offline. They upload the decorated signature (or the signed XDR).
- The backend verifies each signature against the transaction hash and the signer's public key, sums the weights, and moves the operation to
SIGNEDat the threshold. It never holds the human keys. - The submitter sends the envelope like any other (§7 of
../stellar/STELLAR_ARCHITECTURE.md).
At launch the signer signs with the Stellar CLI and a software key on a dedicated laptop (KEY_MANAGEMENT.md §1a); a hardware wallet (Ledger with the Stellar app) works the same way through the CLI. The dev stand-in signs with local keys on Quickstart only.