For builders

The parts of Tsamara, what each one is responsible for, and how to run them.

Everything is in one repository, tsamara-xyz/tsamara.

The parts

PathWhat it is
contractsAnchor program: the transfer hook, the series rules, the investor registry
packages/sukukTypeScript instruction builders: issuance, approval, settlement, distribution, recovery
apps/indexerRust indexer on the Carbon framework: holders and events in SQLite, served over HTTP
apps/apiOperator API on Hono: co-signs subscriptions, approves investors, pays distributions
apps/appThe web app, Next.js with TanStack Query and Table
apps/landingThe landing page, Astro
apps/docsThese docs, Fumadocs on Next.js
apps/devnet-demoThe whole lifecycle on devnet as one script, also the integration check

Who enforces what

The token is a Token-2022 mint with four extensions: metadata on the mint, accounts frozen by default, a transfer hook, and a permanent delegate. The compliance program is the transfer hook. The library builds every instruction, and the API holds the operator's keys and uses the library. The indexer reads the chain and never writes to it. The app talks to the API, the indexer and the chain.

A rule enforced by a program holds even if the API misbehaves. A rule enforced only by the API does not. Compliance mapping says which is which.

Run it

Requires Bun. The indexer requires Rust 1.91 or newer.

bun install
bun test          # every TypeScript suite, no network needed
bun run demo      # the full lifecycle on devnet, prints explorer links

The first bun run demo prints an issuer address. Fund it with devnet SOL from faucet.solana.com and run it again.

To run the stack locally:

bun run indexer                       # terminal 1, serves on 8787
ADMIN_TOKEN=change-me bun run api     # terminal 2, serves on 8788
bun run app                           # terminal 3, http://localhost:3000

The API creates a live series on first start and writes its addresses to .keys/series.json. Identity checks go through Sumsub when SUMSUB_TOKEN and SUMSUB_SECRET are set to sandbox credentials. Without them the operator approves investors by hand from the Operator page.

On this page