Repository navigation
v0.1.0 — the rule is enforced by the network
First public release: milestone M1. A private company issues an equity token on Solana whose transfer restrictions are enforced by the token itself — a Token-2022 mint with a transfer hook — and a panel whose cap table and journal are read from the chain.
What's in
- Two programs on devnet —
caprail(state and actions: company, token, policy, registry, distribution) atAs8C4JwSGHd7HPvh5KD1FhhLsQphQ8veSdhipiSRWs7g, andcaprail-hook(the rule; reads only) at6EMZVfUkf2wrtwfnESLghWfdWyzDu71uJTJ7dCKG3YEi. The deployed bytecode is verified byte for byte against the build. - Admission enforced on every transfer. A transfer to a wallet that is not admitted, whose admission expired or was revoked is refused by the network — from the panel, from a script, from any wallet — with the reason in the logs (
NotAccredited,AccreditationExpired). Balances stay unchanged. - Roles separated in the program: admin (company, token, policy, distribution) and compliance officer (admission statuses) are two keys; the platform holds none.
- Company panel: create company → issue token → set policy → registry → distribute; live cap table and transfer journal over an event stream; a refused simulation is recorded in the journal next to on-chain refusals.
- Indexer: worker → Postgres (row-level security) → API → SSE.
- CLI demo (
pnpm demo:us1) that tells the whole story and measures it; the exit code is the verdict. - CI: Rust (fmt, clippy, SBPFv0 build, tests under mollusk, lock pinned), Node gate, secrets and trace sweep over the whole history.
- Panel on GitHub Pages: https://capcaprail.github.io/CapRail/ (sign-in needs the API host — see below).
Measured on devnet
| Budget | Measured | |
|---|---|---|
| Transfers to a non-admitted wallet refused | 100 of 100 | 100 of 100 |
| Transfers to an admitted wallet passed | ≥ 99 of 100 | 100 of 100 |
| Cap table updated after confirmation | ≤ 5 s p95 | 1.45 s |
| Refusal in the journal with the right reason | ≤ 5 s p95 | 1.14 s |
| End-to-end demo | ≤ 3 min | 18.7 s |
| Cost of a compliant transfer to the sender | ≤ 0.001 SOL | 0.000005 SOL |
| Status change applies to the next transfer | ≤ 10 s | ≤ 20 slots (≈ 4 s) |
Not in this release
- Secondary market and offers (v0.2), vesting (v0.3), right of first refusal (v0.4), compliance report (v0.5). The investor cabinet and market screens are prototypes on mock data and say so.
- Admission status is set by a person inside the product; there is no external KYC. The release proves the rule is enforced by the network, not where the status came from.
- The API and the worker are not hosted yet; the Pages panel connects once they are (v0.2).
- A wallet that does not attach the transfer hook's extra accounts fails before the rule runs — a property of the wallet, not of the token.
Running it
See the README: Node 22, pnpm 9.15, a Postgres (Supabase) and a devnet RPC endpoint — nothing to build on chain.
✅ No migration needed for a fresh database (pnpm --filter @caprail/db db:migrate creates the schema).