# Acknowledgements (https://docs.tsamara.xyz/docs/acknowledgements)

What Tsamara is built with.

* [Solana](https://solana.com) and its Token-2022 program: frozen-by-default accounts, the
  transfer hook, metadata on the mint and the permanent delegate.
* [Anchor](https://www.anchor-lang.com) for the compliance program, and
  [LiteSVM](https://github.com/LiteSVM/litesvm) for testing it in-process.
* [Carbon](https://github.com/sevenlabs-hq/carbon) for the indexer.
* [Sumsub](https://sumsub.com) for identity verification, in sandbox mode.
* [Bun](https://bun.sh), [Hono](https://hono.dev), [Next.js](https://nextjs.org),
  [TanStack](https://tanstack.com) Query and Table, [Astro](https://astro.build) and
  [Biome](https://biomejs.dev) for the rest.

These docs are [Fumadocs](https://fumadocs.dev) on Next.js, starting from the
[tailwind-variants-docs](https://github.com/heroui-inc/tailwind-variants-docs) template by
HeroUI, MIT. The content, the branding and the deployment are Tsamara's.

Tsamara is a submission to the [Colosseum](https://colosseum.com) Crypto World's Fair hackathon.

# Operator API (https://docs.tsamara.xyz/docs/api)

The HTTP service that holds the operator's keys.

`apps/api` is a Hono service on Bun, at `https://api.tsamara.xyz` in the deployment. It holds
the issuer and compliance keys. Devnet keys only.

## Public routes
| Route                    | Body              | Returns                                                                                 |
| ------------------------ | ----------------- | --------------------------------------------------------------------------------------- |
| `GET /series`            |                   | Mint addresses, payment decimals, issuer, program id, the KYC mode and the terms        |
| `GET /holders`           |                   | Holders, from the indexer                                                               |
| `GET /investors/:wallet` |                   | `registered` and `units`                                                                |
| `POST /faucet`           | `wallet`          | Opens the wallet's token accounts, sends $1,000 of test dollars and a little devnet SOL |
| `POST /subscribe`        | `wallet`, `units` | A base64 transaction signed by the issuer, for the investor to sign and send            |
| `POST /kyc/token`        | `wallet`          | A Sumsub access token for the verification widget                                       |
| `POST /kyc/complete`     | `wallet`          | Reads the verdict from Sumsub and, if approved, registers the investor onchain          |

`POST /subscribe` checks the holding cap before the issuer signs, because the hook does not run
on mint.

`POST /kyc/complete` trusts nothing the browser says. The verdict and the country come from
Sumsub's record of the applicant.

## Admin routes
These require the `x-admin-token` header.

| Route                            | Body                                         | Does                                                             |
| -------------------------------- | -------------------------------------------- | ---------------------------------------------------------------- |
| `POST /admin/kyc`                | `wallet`, `jurisdiction`                     | Approves an investor by hand, when no KYC provider is configured |
| `POST /admin/kyc/sandbox-review` | `wallet`, optional `answer`                  | Stands in for Sumsub's reviewer in the sandbox                   |
| `POST /admin/distribute`         | `period`                                     | Pays a period in batches and skips batches already paid          |
| `POST /admin/forced-transfer`    | `from`, `to`, `units`, `reason`, `orderedBy` | Moves units with the permanent delegate and records why          |

`period` is 1 to 16 letters, digits or dashes, for example `2026-H2`.

## Errors
Failures return a JSON body with an `error` message and a 4xx or 5xx status.

## Limits
The admin token is one shared secret and the keys are files or environment variables. The
Sumsub client refuses any token that is not a sandbox token. A webhook from Sumsub would replace
the `kyc/complete` call; it is not built.

# For builders (https://docs.tsamara.xyz/docs/builders)

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

Everything is in one repository, [tsamara-xyz/tsamara](https://github.com/tsamara-xyz/tsamara).

## The parts
| Path               | What it is                                                                              |
| ------------------ | --------------------------------------------------------------------------------------- |
| `contracts`        | Anchor program: the transfer hook, the series rules, the investor registry              |
| `packages/sukuk`   | TypeScript instruction builders: issuance, approval, settlement, distribution, recovery |
| `apps/indexer`     | Rust indexer on the Carbon framework: holders and events in SQLite, served over HTTP    |
| `apps/api`         | Operator API on Hono: co-signs subscriptions, approves investors, pays distributions    |
| `apps/app`         | The web app, Next.js with TanStack Query and Table                                      |
| `apps/landing`     | The landing page, Astro                                                                 |
| `apps/docs`        | These docs, Fumadocs on Next.js                                                         |
| `apps/devnet-demo` | The 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](https://docs.tsamara.xyz/docs/compliance-program) is the transfer hook. The
[library](https://docs.tsamara.xyz/docs/sukuk-library) builds every instruction, and the [API](https://docs.tsamara.xyz/docs/api) holds the
operator's keys and uses the library. The [indexer](https://docs.tsamara.xyz/docs/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](https://docs.tsamara.xyz/docs/compliance-mapping) says which is which.

## Run it
Requires [Bun](https://bun.sh). The indexer requires [Rust](https://rustup.rs) 1.91 or newer.

```sh
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](https://faucet.solana.com) and run it again.

To run the stack locally:

```sh
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.

# Compliance mapping (https://docs.tsamara.xyz/docs/compliance-mapping)

What a regulated sukuk offering needs, what Tsamara does about each item today, and what code cannot solve.

This is an engineering document, not legal advice. The legal and sharia position behind it is in [Regulatory and sharia notes](https://docs.tsamara.xyz/docs/regulation). Tsamara is a devnet prototype with a mock series: it holds no licence, has no regulatory approval and no sharia certification. The requirements below are the ones we designed against and must be validated with counsel and a sharia board for any real issuance.

## Status key
| Status   | Meaning                                                              |
| -------- | -------------------------------------------------------------------- |
| Onchain  | Enforced by a program; the operator cannot bypass it                 |
| Tooling  | Enforced by the operator API; depends on the operator behaving       |
| Designed | Decided and tracked as an issue, not built                           |
| External | Needs a licence, a contract or a third party; not a software problem |

## Investor eligibility and transfer restrictions
| Requirement                                                | Control                                                                                                                                                                                                                            | Status   |
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| Only identified investors hold the instrument              | Token accounts are frozen by default; only the compliance authority can thaw one                                                                                                                                                   | Onchain  |
| A recipient must be a known investor                       | Transfer hook requires an investor record for the recipient on every transfer                                                                                                                                                      | Onchain  |
| Offering restrictions by jurisdiction                      | Restricted jurisdictions are stored in the series config; registration and every transfer check them                                                                                                                               | Onchain  |
| Per-investor holding limit on transfers                    | Transfer hook checks the recipient's balance after the transfer                                                                                                                                                                    | Onchain  |
| Per-investor holding limit on primary subscription         | The API checks the limit before the issuer co-signs; the hook does not run on mint ([#21](https://github.com/tsamara-xyz/tsamara/issues/21))                                                                                       | Tooling  |
| Offboarding an investor                                    | The compliance authority freezes the account                                                                                                                                                                                       | Onchain  |
| Identity verification (KYC)                                | Sumsub WebSDK level with identity document and liveness; the API reads the verdict and country server-side and only then registers the investor. Sandbox credentials only, and the country is the document's, not proven residence | Tooling  |
| Sanctions and AML screening                                | Not configured on the verification level                                                                                                                                                                                           | External |
| Investor classification (retail, professional, accredited) | Not modelled                                                                                                                                                                                                                       | Designed |

## Issuer controls and governance
| Requirement                                          | Control                                                                                                                                                                                                                                                                                                                                                                                                                               | Status   |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| Separation of duties                                 | Minting and investor approval are different keys; the demo asserts the issuer key cannot approve investors                                                                                                                                                                                                                                                                                                                            | Onchain  |
| No single key can act alone                          | Authorities held in a multisig ([#19](https://github.com/tsamara-xyz/tsamara/issues/19))                                                                                                                                                                                                                                                                                                                                              | Designed |
| Recovery for lost keys, inheritance and court orders | The compliance authority is the mint's permanent delegate and can move units without the holder's signature. The library refuses to build the transfer without a reason and an ordering authority, and writes both onchain as a memo; the transfer hook still applies. Nothing onchain stops the authority using the delegate directly, so this rests on who holds that key ([#19](https://github.com/tsamara-xyz/tsamara/issues/19)) | Tooling  |
| Changing series rules after issuance                 | No instruction to update the config; rules are fixed at initialization                                                                                                                                                                                                                                                                                                                                                                | Designed |
| Operator access control                              | Admin routes require a shared token; keys are files on disk                                                                                                                                                                                                                                                                                                                                                                           | Tooling  |

## Settlement, payments and records
| Requirement                         | Control                                                                                                                                                                                                                                                                                                                      | Status                        |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| Delivery versus payment             | Payment and delivery are instructions in one transaction                                                                                                                                                                                                                                                                     | Onchain                       |
| Public, tamper-evident terms        | Akad, maturity, currency, profit rate, unit size, restrictions and holding cap are stored in the token's metadata                                                                                                                                                                                                            | Onchain                       |
| Audit trail                         | Every approval, subscription, transfer and distribution is a confirmed transaction; the indexer derives a per-wallet history from them                                                                                                                                                                                       | Onchain, read through tooling |
| Accurate pro rata distributions     | Integer math, rounded down, unit-tested; holders are read from the indexer                                                                                                                                                                                                                                                   | Tooling                       |
| A distribution cannot be paid twice | Each batch is written onchain with a memo naming the series, the period and the batch; the API skips a batch whose memo is already on the treasury's history. If holdings change between a failed run and its retry, batch boundaries can move, so a record-date snapshot is still needed for a series larger than one batch | Tooling                       |
| Settlement asset                    | A mock dollar token on devnet; a real stablecoin on the same token program works without code changes. Stablecoin settlement is not permitted everywhere: in Indonesia the rupiah is mandatory for domestic transactions                                                                                                     | External                      |
| Registry of record                  | The chain is the registry in this design; whether that is legally sufficient depends on the jurisdiction                                                                                                                                                                                                                     | External                      |

## Sharia
| Requirement                                                                   | Control                                                                                                                                                              | Status   |
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| The underlying sukuk is sharia-compliant                                      | Inherited from the real instrument; the demo series is a mock                                                                                                        | External |
| The series may trade at a negotiated price                                    | Only defensible while the underlying is majority tangible assets. The ratio and its as-of date are published in the series terms; nothing updates or enforces it yet | Designed |
| The tokenized structure preserves the holder's rights in the underlying asset | Depends on the legal wrapper between the token and the sukuk, which does not exist yet                                                                               | External |
| Sharia board review of the structure and of secondary trading                 | None                                                                                                                                                                 | External |
| Returns are profit distributions, not interest                                | The series models an expected periodic distribution set by the akad; we deliberately do not use Token-2022's interest-bearing extension                              | Onchain  |

## Issuance and distribution
| Requirement                                             | Control                                                                                                                                                      | Status   |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
| Authority to issue or tokenize the instrument           | None. Only a sovereign's own issuer can issue its sukuk; anyone else issues a new instrument that holds it                                                   | External |
| The token carries a real claim                          | The prototype token represents nothing. A real one needs a trust or wakalah arrangement giving holders a beneficial share, a trustee and a default waterfall | External |
| Licence to distribute to investors in each jurisdiction | None                                                                                                                                                         | External |
| Custody of the underlying sukuk                         | None                                                                                                                                                         | External |
| Disclosure documents and risk warnings                  | A prototype notice on every surface; no offering document                                                                                                    | External |
| Data protection                                         | The chain stores a wallet address and a country code per investor, and no other personal data                                                                | Onchain  |
| Security review                                         | The compliance program is unaudited ([#23](https://github.com/tsamara-xyz/tsamara/issues/23))                                                                | External |

## What this adds up to
The parts of compliance that are rules about who may hold and transfer the instrument are enforced by programs. The parts that are about who the issuer is, whether investors are who they claim to be, and whether the structure is lawful and sharia-compliant are not software, and none of them are in place.

# Compliance program (https://docs.tsamara.xyz/docs/compliance-program)

The Anchor program Token-2022 calls on every transfer of the sukuk.

`tsamara-compliance` is deployed on devnet at
[`EjYxuJE4QE8P37scBxgWRHGigZ8hP6j3ysnSQ95MWXXG`](https://explorer.solana.com/address/EjYxuJE4QE8P37scBxgWRHGigZ8hP6j3ysnSQ95MWXXG?cluster=devnet).
The source is in `contracts/programs/tsamara-compliance`. It is unaudited.

## Instructions
| Instruction         | Who may call it               | What it does                                                                        |
| ------------------- | ----------------------------- | ----------------------------------------------------------------------------------- |
| `initialize_series` | The mint's freeze authority   | Writes the series config and the list of extra accounts the hook needs              |
| `register_investor` | The compliance authority      | Writes an investor record with a country code; refused if the country is restricted |
| `transfer_hook`     | Token-2022, during a transfer | Checks the recipient and the holding cap                                            |

## Accounts
| Account             | Seeds                       | Holds                                                                        |
| ------------------- | --------------------------- | ---------------------------------------------------------------------------- |
| `SeriesConfig`      | `config`, mint              | The compliance authority, the holding cap, up to 16 restricted jurisdictions |
| `InvestorRecord`    | `investor`, mint, wallet    | The wallet and its two-letter country code                                   |
| Extra account metas | `extra-account-metas`, mint | The accounts Token-2022 must pass to the hook                                |

## What the hook checks
1. It is running inside a token transfer. The source account's `transferring` flag must be set,
   so the hook cannot be called directly to fake a check.
2. The recipient has an investor record for this mint. The record is a derived address, so a
   record for another wallet or another series does not pass.
3. The recipient's country is not restricted.
4. The recipient's balance after the transfer does not exceed the holding cap.

## Errors
| Error                                                       | Meaning                                                                     |
| ----------------------------------------------------------- | --------------------------------------------------------------------------- |
| Signer is not the mint's freeze authority                   | Someone other than the compliance authority tried to initialize or register |
| Too many restricted jurisdictions                           | More than 16                                                                |
| The series is not offered to residents of this jurisdiction | Restricted country, at registration or on transfer                          |
| Transfer would exceed the per-investor holding cap          | The recipient would hold more than the cap                                  |
| The hook may only run during a token transfer               | The hook was called outside a transfer                                      |

## Known limits
* The hook does not run on mint, so the cap is not enforced by the program on a primary
  subscription ([issue 21](https://github.com/tsamara-xyz/tsamara/issues/21)).
* There is no instruction to change a series' rules after it is initialized.
* The compliance authority is the mint's permanent delegate. The program does not constrain how
  that key is used.

## Build
Install the Solana CLI and Anchor, then:

```sh
cd contracts
anchor build
bun run build     # also refreshes the binary the tests load
```

# Contributing (https://docs.tsamara.xyz/docs/contributing)

How changes are made in this repository.

## The flow
Every change starts as an issue and lands as a pull request with labels, in small commits, with
CI green. Pull requests are rebased onto `main`.

## Before you push
```sh
bun run lint        # Biome
bun run typecheck
bun test
```

Husky runs the lint on commit and the typecheck and tests on push. If you changed the program,
rebuild the test binary with `bun run --cwd contracts build`. The docs are a separate pnpm
project: run `pnpm lint` and `pnpm build` in `apps/docs`.

## Style
* The least code that does the job. A shortcut taken on purpose is marked with a `ponytail:`
  comment naming its ceiling and the upgrade path.
* A fix goes where every caller passes through, with one test that fails without it.

## Wording
What the product says matters as much as what it does. Never write that Tsamara is compliant,
regulated, sharia-compliant, halal or guaranteed, and never call the return a coupon or
interest. The table of what to say instead is in
[Regulatory and sharia notes](https://docs.tsamara.xyz/docs/regulation#what-we-must-not-say). No invented market data in
the interface.

# Deployment (https://docs.tsamara.xyz/docs/deployment)

Five containers, one per service, each configured from the environment.

| Service | Dockerfile                | Build context   | Port | Public URL            |
| ------- | ------------------------- | --------------- | ---- | --------------------- |
| Landing | `apps/landing/Dockerfile` | repository root | 80   | `tsamara.xyz`         |
| App     | `apps/app/Dockerfile`     | repository root | 3000 | `app.tsamara.xyz`     |
| API     | `apps/api/Dockerfile`     | repository root | 8788 | `api.tsamara.xyz`     |
| Indexer | `apps/indexer/Dockerfile` | `apps/indexer`  | 8787 | `indexer.tsamara.xyz` |
| Docs    | `apps/docs/Dockerfile`    | `apps/docs`     | 3000 | `docs.tsamara.xyz`    |

## Configuration
| Service            | Variable                                 | Meaning                                                 |
| ------------------ | ---------------------------------------- | ------------------------------------------------------- |
| App, at build time | `NEXT_PUBLIC_API`, `NEXT_PUBLIC_INDEXER` | Public URLs of the API and the indexer                  |
| App, at build time | `NEXT_PUBLIC_RPC`                        | Optional Solana RPC endpoint; defaults to public devnet |
| API                | `ISSUER_KEY`, `COMPLIANCE_KEY`           | Operator keys as JSON byte arrays. Devnet keys only     |
| API                | `SUKUK_MINT`, `PAYMENT_MINT`             | The live series to serve                                |
| API                | `ADMIN_TOKEN`                            | Required by the admin routes                            |
| API                | `INDEXER`                                | URL of the indexer, for the holder list                 |
| API                | `SUMSUB_TOKEN`, `SUMSUB_SECRET`          | Optional sandbox credentials                            |
| API, Indexer       | `RPC`                                    | Optional Solana RPC endpoint                            |
| Indexer            | `SUKUK_MINT`, `PAYMENT_MINT`, `ISSUER`   | The series to index                                     |
| Docs               | `NEXT_PUBLIC_SITE_URL`                   | Optional canonical origin                               |

## The current deployment
The services run on one server under [Coolify](https://coolify.io), built from `main` with the
Dockerfiles above. The server's nginx proxies each hostname to a port published on the host.

Things that are easy to get wrong:

* **The API reaches the indexer over the Docker network**, by a network alias. An alias takes
  effect on a full deploy, not a restart.
* **The app's public URLs are build variables.** Changing them means rebuilding it.
* **The indexer answers only after it has caught up**, a little after its container starts.
* **The app waits.** If the API is unreachable, pages say so and retry every few seconds, so a
  restart of the server needs no reload from visitors.

The repository's `docs/DEPLOY.md` has the rest.

# Distributions (https://docs.tsamara.xyz/docs/distributions)

How the periodic distribution is calculated, paid, and kept from being paid twice.

## What a distribution is
A sukuk does not pay interest. The series has an **expected profit rate**, set by its structure,
and pays an expected periodic distribution out of what the underlying assets earn. It is an
expectation, not a guarantee.

## The amount
For the demo series: $10 a unit, 5.20% a year, paid twice a year. One unit receives $0.26 per
period, and 20 units receive $5.20. The math is done in whole base units of the payment token
and rounded down, so the treasury can never pay more than the total owed.

## How it is paid
The operator names the period, for example `2026-H2`. The API reads the holders from the
indexer and pays them from the issuer's treasury in batches of eight payments per transaction.

Each batch carries a memo naming the series, the period and the batch number:

```
tsamara:distribution:GSD31:2026-H2:0
```

Before sending a batch, the API looks for its memo on the treasury's history and skips the
batch if it is there. Paying the same period again therefore pays nobody twice, and a run that
failed halfway can simply be repeated.

> **info:** If holdings change between a failed run and its retry, the batch boundaries can move. A series
larger than one batch still needs a record-date snapshot, which is not built.

# Eligibility and transfers (https://docs.tsamara.xyz/docs/eligibility)

Who may hold units, what every transfer is checked against, and what the compliance authority can do.

## Who may hold units
An investor holds units only after two things have happened onchain: the compliance authority
has written an investor record for their wallet, with a country code, and it has opened their
sukuk account, which starts frozen.

Registration is refused if the country is on the series' restricted list. The demo series is not
offered to residents of the United States or Indonesia. Indonesia is on the list because the
series settles in a stablecoin, and the rupiah is mandatory for domestic transactions there.

## How identity is checked
Verification runs through Sumsub, with an identity document and a liveness check. The widget in
the browser is only the interface. The decision is taken by the operator's API, which reads
Sumsub's own record of the verdict and the document's country, and registers the investor only
then.

> **warn:** The prototype uses Sumsub's sandbox, and the API refuses production credentials. The country is
the document's country, not proven residence. Sanctions and AML screening are not configured.
Identity checks and an allow-list are necessary for a real offering. They are not sufficient.

## What every transfer is checked against
On each transfer of units, the compliance program refuses unless:

* the recipient has an investor record for this series,
* the recipient's country is not restricted,
* the recipient's balance after the transfer is within the holding cap.

A revoked investor's account is frozen, so they can neither send nor receive.

## What the compliance authority can do
It can freeze an account. It can also move units without the holder's signature, for lost keys,
inheritance, or an order from a court or regulator. The library refuses to build such a transfer
without a reason and the authority that ordered it, and writes both onchain with the transfer.
The recipient must still be a registered investor within the holding cap.

Nothing onchain stops whoever holds that key from using it directly, so this control rests on
who holds the key. Holding it in a multisig is designed and not built
([issue 19](https://github.com/tsamara-xyz/tsamara/issues/19)).

## What is stored about you
The chain stores a wallet address and a two-letter country code per investor, and no other
personal data.

# FAQ (https://docs.tsamara.xyz/docs/faq)

Short answers, with the caveats kept.

## What is Tsamara, in plain words?
A prototype that represents a sukuk series as a token with a $10 unit on Solana. Approved
investors can subscribe with stablecoins, transfer units to each other and receive
distributions, and the rules about who may hold units are enforced by programs onchain.

## Can I invest real money?
No. It runs on devnet with a mock series and test dollars that have no value. Nothing here is an
offer of securities.

## Is this a real sovereign sukuk?
No. The demo series is a mock, and Tsamara is not affiliated with any sovereign issuer. Only a
sovereign's own issuer can issue its sukuk. A real Tsamara would issue units representing a
beneficial share in sukuk held on trust.

## Is it certified by a sharia board?
No. It is designed with sharia principles in mind: the return is an expected profit
distribution, not interest, and the share of tangible assets is published. It has not been
reviewed or certified by any sharia board.

## Is the return fixed?
No. The series has an expected profit rate set by its structure. It is an expectation.

## Who can hold units?
Only wallets the compliance authority has registered, in a jurisdiction the series is offered
in. See [Eligibility and transfers](https://docs.tsamara.xyz/docs/eligibility).

## Why is the demo series not offered in the United States or Indonesia?
A public offer in the United States needs registration. In Indonesia the rupiah is mandatory for
domestic transactions, and this series settles in a stablecoin.

## Can someone take my units?
The compliance authority can move units without the holder's signature, for lost keys,
inheritance, or an order from a court or regulator. Each such transfer is recorded onchain with
its reason and the authority that ordered it. In the prototype that authority is a single key.

## Why Solana?
Token-2022 provides the pieces as standard features: accounts frozen by default, a hook on every
transfer, metadata on the mint, and atomic transactions for delivery versus payment.

## Is it audited?
No.

# How it works (https://docs.tsamara.xyz/docs/how-it-works)

From a published series to a distribution, in five steps.

## 1. A series is published
The issuer creates a token for the series. Its terms are stored on the token itself, where
anyone can read them: the structure (akad), maturity, currency, expected profit rate, unit size,
the jurisdictions it is not offered in, the holding cap, and the share of tangible assets with
its as-of date.

## 2. An investor is approved
Every sukuk account starts frozen. An investor verifies their identity, the operator's API reads
the result and the document's country, and only then does the compliance authority register the
investor onchain and open their account. The issuer's key cannot do this: minting and approval
are separate keys.

## 3. The investor subscribes
Payment and delivery are two instructions in one transaction, signed by the investor and the
issuer. Either both happen or neither does. A subscription cannot half-settle.

## 4. Units move between approved investors
A holder can send units to another wallet. On every transfer, Token-2022 calls Tsamara's
compliance program, which refuses the transfer unless the recipient is a registered investor, in
a jurisdiction the series is offered in, and still within the holding cap afterwards.

## 5. The distribution is paid
The issuer pays the periodic distribution in stablecoins, pro rata to holdings. Each batch of
payments is marked onchain with the series and the period, so paying the same period again skips
what is already paid.

## The rule and what enforces it
| Rule                                                                 | Mechanism                                                           |
| -------------------------------------------------------------------- | ------------------------------------------------------------------- |
| The terms are public                                                 | Token metadata stored on the mint                                   |
| Only approved investors can hold units                               | Accounts are frozen by default; the compliance authority opens them |
| The issuer cannot decide who holds                                   | Mint authority and freeze authority are separate keys               |
| A recipient must be a registered investor in an allowed jurisdiction | The transfer hook checks the recipient's investor record            |
| No investor can receive more than the holding cap                    | The transfer hook checks the recipient's balance after the transfer |
| A subscription cannot half-settle                                    | Payment and delivery are in one transaction                         |
| Distributions are pro rata and not paid twice                        | Integer math from indexed holdings; period-marked batches           |

> **info:** The hook does not run when units are minted, so on a primary subscription the holding cap is
checked by the operator's API rather than by the program. That gap is tracked as
[issue 21](https://github.com/tsamara-xyz/tsamara/issues/21).

# Indexer (https://docs.tsamara.xyz/docs/indexer)

A Rust service that turns the series' transactions into holders and events.

`apps/indexer` is built on the [Carbon](https://github.com/sevenlabs-hq/carbon) framework. It
crawls the transactions of one series over RPC, classifies each one, stores the result in
SQLite, and serves it over HTTP. It only reads the chain.

## Endpoints
| Route                          | Returns                                            |
| ------------------------------ | -------------------------------------------------- |
| `GET /series`                  | The mints and issuer being indexed                 |
| `GET /holders`                 | Each wallet, its units, and whether it is approved |
| `GET /events`                  | The latest 200 events, newest first                |
| `GET /events?wallet=<address>` | One wallet's history                               |

## Events
| Kind           | Meaning                                 |
| -------------- | --------------------------------------- |
| `approved`     | An investor's account was opened        |
| `revoked`      | An investor's account was frozen        |
| `subscription` | Units minted against a payment          |
| `trade`        | Units moved between investors           |
| `distribution` | A payment from the treasury to a holder |

Each event carries the transaction signature, its time, the wallet, a counterparty where there
is one, the units and the amount paid. An event is stored once, however often its transaction
is seen.

## Run
```sh
bun run indexer --once   # index what exists, print holders and the event count, exit
bun run indexer          # keep indexing and serve on PORT, default 8787
```

It follows the series from the last `bun run demo`, or the one named by `SUKUK_MINT`,
`PAYMENT_MINT` and `ISSUER`. It reads from `RPC`, by default public devnet, and stores to
`.data/indexer-<SUKUK_MINT>.db`. Without a persistent disk it rebuilds from the chain on start.

## Why the API needs it
Public RPC endpoints refuse the queries that would list a Token-2022 mint's holders, so the API
reads the holder list from the indexer when it pays a distribution.

# Introduction (https://docs.tsamara.xyz/docs/introduction)

Sovereign sukuk in $10 units on Solana, with every transfer rule enforced onchain.

## What Tsamara does
Sukuk are certificates of ownership in underlying assets: holders receive a share of what the
assets earn, not interest on a loan. Sovereign dollar sukuk are sold to institutions in large
minimum denominations and trade over the counter, so someone who wants that exposure in small
amounts cannot buy one directly.

Tsamara represents a sukuk series as a token with a $10 unit. An approved investor, in a
jurisdiction where the series is offered, can subscribe with stablecoins, hold units, transfer
them to another approved investor, and receive the periodic distribution onchain.

The rules about who may hold and receive units are not a policy document. They are enforced by
Solana's Token-2022 program and by a small program that runs on every transfer.

## What is true today
> **warn:** Tsamara is an unlicensed prototype on Solana devnet, built for the Colosseum Crypto World's Fair
hackathon. The sukuk series is a mock and the dollars are test tokens with no value. Nothing here
is an offer of securities, and no investment can be made. Tsamara has no regulatory approval and
no sharia certification, is not affiliated with any sovereign issuer, and its program is
unaudited. The [Status](https://docs.tsamara.xyz/docs/status) page keeps this honest.

## What a real version would be
Tsamara could not issue a sovereign sukuk. Only a sovereign's own issuer can. A real Tsamara
would hold sukuk in a vehicle and issue units against it, and each unit would have to be a
beneficial share in sukuk held on trust. A first offering would be limited to eligible investors
in one jurisdiction. The $10 unit and broad access are the design target, not something any
regime permits an unlicensed issuer today. [Regulatory and sharia notes](https://docs.tsamara.xyz/docs/regulation) sets
this out.

## Where to go next
* [How it works](https://docs.tsamara.xyz/docs/how-it-works), in five steps.
* [Try the demo](https://docs.tsamara.xyz/docs/try-the-demo) on devnet, with a test wallet.
* [Eligibility and transfers](https://docs.tsamara.xyz/docs/eligibility), what the chain checks.
* [FAQ](https://docs.tsamara.xyz/docs/faq).

If you build things, start at [For builders](https://docs.tsamara.xyz/docs/builders).

# llms.txt (https://docs.tsamara.xyz/docs/llms-txt)

These docs as Markdown, for AI agents.

|                        |                                                                     |
| ---------------------- | ------------------------------------------------------------------- |
| Index                  | [`/llms.txt`](https://docs.tsamara.xyz/llms.txt)                    |
| Everything in one file | [`/llms-full.txt`](https://docs.tsamara.xyz/llms-full.txt)          |
| Any page               | append `.md` to its URL, or request it with `Accept: text/markdown` |

The **Copy** and **Open in** actions at the top of each page hand the Markdown to an agent.

> **info:** Keep the caveats when quoting, and keep them exact. Tsamara is an unlicensed prototype on Solana
devnet with a mock series. It is not regulated, not certified by any sharia board, not audited,
and not affiliated with any sovereign issuer. The return is an expected profit rate, never a
coupon, interest or a guarantee.

# MCP server (https://docs.tsamara.xyz/docs/mcp-server)

Live access to these docs for an AI agent.

A Streamable HTTP MCP server at `https://docs.tsamara.xyz/api/mcp` with three tools:
`list_pages`, `search_docs`, and `get_page`.

**Cursor**, in `.cursor/mcp.json` under `mcpServers`:

```json
"tsamara": { "url": "https://docs.tsamara.xyz/api/mcp" }
```

**VS Code**, in `.vscode/mcp.json` under `servers`:

```json
"tsamara": { "type": "http", "url": "https://docs.tsamara.xyz/api/mcp" }
```

**Claude and other HTTP MCP clients**: point them at the URL above. The **Copy** menu on any
page carries a ready-made prompt with these steps.

# Regulatory and sharia notes (https://docs.tsamara.xyz/docs/regulation)

What a real version of Tsamara would have to satisfy, and what follows for the design and for what we may say.

What a real version of Tsamara would have to satisfy, and what follows for the design and for what we are allowed to say. Written in October 2026 from desk research, mostly through law-firm and press summaries rather than primary texts.

> **warn:** This is not legal advice and not a fatwa. Items marked *unverified* were not confirmed against a
primary source. Everything here needs review by counsel and a sharia board before it is relied
on.

## The short version
* No regime today lets an unlicensed team sell a $10 repackaged sovereign-sukuk token to retail investors "globally". A realistic first issuance is for professional investors, from one licensed venue or sandbox.
* Tsamara cannot issue a sovereign sukuk. It could only issue its own instrument that holds one, so a holder's claim would be on that vehicle, not on the sovereign.
* For the token to be a sukuk in the sharia sense, it must represent an undivided beneficial share in the underlying sukuk held on trust, not a debt claim on a vehicle.
* Trading at a negotiated price is only defensible while the underlying is majority tangible assets.

## Legal characterisation
A tokenized claim on a sovereign sukuk is a security or debt instrument in every regime surveyed. It is not e-money, and it is outside the EU's MiCA regime, which excludes financial instruments. US securities staff said in January 2026 that tokenized securities are treated like traditional ones.

| Structure                                                | Holder's claim                                       | Used by                                                                                      |
| -------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Native issuance by the sovereign's own issuer            | Direct                                               | Hong Kong tokenized green bonds; Khazanah's tokenized sukuk pilot (Malaysia, 2026)           |
| Note from a special-purpose vehicle that holds the asset | Indirect, with vehicle and custodian insolvency risk | Ondo USDY (non-US investors only), Backed                                                    |
| Fund units                                               | Indirect                                             | BlackRock BUIDL (qualified purchasers), Franklin BENJI (a registered US fund open to retail) |

Indonesia: under Law 19/2008 only the Government or a state sukuk issuing company may issue SBSN, and unauthorised issuance is a criminal offence. Indonesia's global sukuk are issued as Reg S / 144A trust certificates by Perusahaan Penerbit SBSN Indonesia III. Pricing supplements from 2013 and 2018 set denominations of US$200,000 and multiples of US$1,000; the current programme's terms are *unverified*.

## What an offer requires
| Jurisdiction   | Retail possible?                                 | Notes                                                                                                                                                                                                                       |
| -------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| United States  | Only with registration                           | Otherwise accredited investors (Reg D) or non-US persons (Reg S). The holding vehicle risks being an investment company. The September 2026 "innovation exemption" covers secondary trading of tokenized listed stocks only |
| European Union | Only with a prospectus                           | MiFID II and the Prospectus Regulation apply. Exempt below €12m per 12 months from June 2026; member states may set €5m                                                                                                     |
| United Kingdom | Only through an approved financial promotion     | Digital Securities Sandbox open to admitted firms                                                                                                                                                                           |
| Singapore      | Only with a prospectus                           | Exemptions for small offers, private placements, institutional and accredited investors                                                                                                                                     |
| Hong Kong      | Only through authorised products or a prospectus | 2026 circulars allow secondary trading on licensed platforms                                                                                                                                                                |
| UAE            | Not established                                  | A tokenized sukuk is a security; DFSA and ADGM run sandboxes                                                                                                                                                                |
| Malaysia       | Not yet                                          | Pilot-led; retail fractional sukuk is an aspiration                                                                                                                                                                         |
| Indonesia      | Not yet                                          | Offering tokenized assets is covered by a draft rule, still a draft in October 2026. A public offer needs a registration with OJK. Sandbox pilots exist                                                                     |

## Consequences for the mechanics
| Mechanic                                              | Position                                                                                                                                                                              |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Jurisdiction list, freeze until approved, holding cap | The same controls live products use. They are evidence of compliance, not a licence                                                                                                   |
| Transfers between approved wallets                    | A bilateral transfer is not a trading venue. An order book or matching service would be, and needs a licence                                                                          |
| Register of holders                                   | A registrar is required, with personal data kept offchain                                                                                                                             |
| Stablecoin settlement                                 | Depends on the jurisdiction. In Indonesia the rupiah is mandatory for domestic transactions, so stablecoin subscriptions and distributions for Indonesian residents are not permitted |
| Travel Rule, sanctions, tax                           | FATF Recommendation 16 applies between service providers. Sanctions screening is expected. Withholding and FATCA/CRS treatment are *unverified*                                       |

## Sharia position
| Topic                              | Position                                                                                                                                                                                   | Status                                              |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- |
| What a sukuk is                    | Certificates of equal value representing undivided shares in assets, usufruct or services; not a debt claim (AAOIFI Sharia Standard 17)                                                    | Settled                                             |
| Asset-based or asset-backed        | Most sovereign sukuk are asset-based: holders have a beneficial interest and recourse to the obligor, not a true sale                                                                      | Market practice, criticised                         |
| Tradability                        | Ijarah, or wakalah with majority tangible assets, may trade at any agreed price. Debt-dominant pools trade at par only                                                                     | Settled across AAOIFI, OIC Fiqh Academy and DSN-MUI |
| Tangibility                        | Above 50% throughout the tenor; below 33% the sukuk trades under debt rules (AAOIFI Standard 59). DSN-MUI Fatwa 95/2014 requires at least 51% tangible assets for a tradable SBSN wakalah  | Settled                                             |
| A fixed distribution               | In ijarah it is rental. In wakalah it is an expected profit rate, with any excess paid to the agent as an incentive; a shortfall may be covered by a reserve, not by the agent's guarantee | Settled in principle                                |
| Purchase undertaking at face value | Prohibited for an agent by AAOIFI's 2008 resolution, widespread in practice through the lessee route                                                                                       | Contested                                           |
| Draft AAOIFI Standard 62           | Would require actual legal transfer of the assets to holders. Put on hold in November 2025; no adoption found                                                                              | Unsettled                                           |
| Tokenization                       | No AAOIFI or IFSB standard found. Malaysia's Shariah Advisory Council treats a token's status as following the rights attached to it. No DSN-MUI fatwa on sukuk tokenization found         | Open                                                |
| Stablecoin settlement              | No authoritative ruling found. Paying for an asset-majority sukuk is a sale, not a currency exchange                                                                                       | Open                                                |
| Freezing and forced transfer       | Freezing is defensible as a disclosed condition. A forced transfer without due process or compensation risks being usurpation                                                              | Our analysis                                        |

Indonesia's 2021 Ijtima Ulama ruled crypto impermissible as currency, and valid as an asset only with a clear underlying and benefit. A general DSN-MUI fatwa on crypto assets was still pending in August 2026.

## What this changes in the design
Tracked as issues. Built so far: the tangibility ratio and its as-of date are published in the series terms, and the demo dollar series excludes Indonesian residents because it settles in a stablecoin. Forced transfers carry a reason code and the ordering authority onchain. The rest is not built.

1. Model a series on ijarah, or on wakalah with at least 51% tangible assets. Never murabaha.
2. Publish onchain: the structure, the tangibility ratio with its as-of date, the purchase-undertaking terms, the record date, the fee schedule, the trustee, and the hash of the sharia pronouncement.
3. Restrict transfers to par when tangibility falls below the threshold.
4. Make the token a beneficial-ownership unit under a trust or wakalah arrangement, not a note.
5. Give freezes and forced transfers a reason code and the authority that ordered them.
6. Add a purification account for any non-compliant income.
7. Keep avoiding the token standard's interest-bearing feature.

## What we must not say
| Do not say                                        | Say instead                                                                                                      |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Compliant, regulated                              | Unlicensed devnet prototype; the controls are designed to support compliance                                     |
| Available globally, retail anywhere               | A design target; a real launch would be for eligible investors in one jurisdiction                               |
| Tokenized sovereign sukuk, backed by a government | A token that would represent a beneficial share in sovereign sukuk held on trust; no affiliation with any issuer |
| Sharia-compliant, halal                           | Designed with sharia principles in mind; not reviewed or certified by any sharia board                           |
| Coupon, interest, guaranteed or fixed return      | Expected periodic distribution                                                                                   |
| Asset-backed                                      | Asset-based, unless there is a true sale                                                                         |
| Islamic bonds                                     | Certificates of ownership in underlying assets                                                                   |
| Freely tradable at any price                      | Transferable at agreed prices while the underlying is majority tangible                                          |
| KYC makes transfers legal                         | KYC and whitelisting are necessary, not sufficient                                                               |
| MiCA-compliant                                    | Outside MiCA; securities law applies                                                                             |

## A realistic path
Start with professional or accredited investors outside the United States, through a bankruptcy-remote vehicle in a jurisdiction with a tokenization sandbox (ADGM, DIFC or Singapore), with a licensed custodian, registrar and placement agent. Pursue Indonesia's regulatory sandbox in parallel for a rupiah-settled domestic version. Retail access at small unit sizes needs an approved prospectus, an authorised fund, or native issuance by a sovereign.

## Sources
* Indonesia Law 19/2008 on SBSN: [https://jdih.kemenkeu.go.id/fulltext/2008/19TAHUN2008UU.htm](https://jdih.kemenkeu.go.id/fulltext/2008/19TAHUN2008UU.htm)
* DSN-MUI Fatwa 95/2014, SBSN Wakalah: [https://tafsirq.com/konten/dsn/surat-berharga-syariah-negara-sbsn-wakalah](https://tafsirq.com/konten/dsn/surat-berharga-syariah-negara-sbsn-wakalah)
* AAOIFI on draft Standard 62: [https://aaoifi.com/announcement/press-release-from-the-accounting-and-auditing-organisation-for-islamic-financial-institutions-aaoifi-regarding-draft-shariah-standard-no-62/?lang=en](https://aaoifi.com/announcement/press-release-from-the-accounting-and-auditing-organisation-for-islamic-financial-institutions-aaoifi-regarding-draft-shariah-standard-no-62/?lang=en)
* OIC Fiqh Academy resolution 178: [https://iifa-aifi.org/en/32984.html](https://iifa-aifi.org/en/32984.html)
* SEC staff on tokenized securities: [https://www.clearygottlieb.com/news-and-insights/publication-listing/sec-staff-issues-guidance-on-tokenized-security-taxonomies](https://www.clearygottlieb.com/news-and-insights/publication-listing/sec-staff-issues-guidance-on-tokenized-security-taxonomies)
* SEC innovation exemption: [https://www.sidley.com/en/insights/newsupdates/2026/09/sec-issues-innovation-exemption-for-onchain-trading-of-tokenized-us-listed-stocks](https://www.sidley.com/en/insights/newsupdates/2026/09/sec-issues-innovation-exemption-for-onchain-trading-of-tokenized-us-listed-stocks)
* EU prospectus threshold: [https://www.fsma.be/en/news/new-prospectus-threshold-offers-securities-public](https://www.fsma.be/en/news/new-prospectus-threshold-offers-securities-public)
* MAS tokenisation guide: [https://www.clydeco.com/es/insights/2025/12/guide-on-the-tokenisation-of-capital-market-produc](https://www.clydeco.com/es/insights/2025/12/guide-on-the-tokenisation-of-capital-market-produc)
* Hong Kong SFC 2026 framework: [https://www.charlesrussellspeechlys.com/en/insights/expert-insights/financial-services/2026/hong-kong-sfc-launches-new-framework-for-secondary-trading-of-tokenised-investment-products/](https://www.charlesrussellspeechlys.com/en/insights/expert-insights/financial-services/2026/hong-kong-sfc-launches-new-framework-for-secondary-trading-of-tokenised-investment-products/)
* OJK draft rule on tokenized assets: [https://bcasekuritas.co.id/latest-news/news/ojk-rpojk-penawaran-aset-ditokenisasi-masa-depan-keuangan-digital](https://bcasekuritas.co.id/latest-news/news/ojk-rpojk-penawaran-aset-ditokenisasi-masa-depan-keuangan-digital)
* Khazanah tokenized sukuk pilot: [https://www.ledgerinsights.com/malaysian-sovereign-fund-pilots-tokenized-sukuk-with-25m-issuance/](https://www.ledgerinsights.com/malaysian-sovereign-fund-pilots-tokenized-sukuk-with-25m-issuance/)
* Indonesia global sukuk, 2021 pricing: [https://www.bi.go.id/en/iru/highlight-news/Documents/Republic%20of%20Indonesia%20priced%20a%20US$%203%20billion%20Global%20Sukuk.pdf](https://www.bi.go.id/en/iru/highlight-news/Documents/Republic%20of%20Indonesia%20priced%20a%20US$%203%20billion%20Global%20Sukuk.pdf)

# Status (https://docs.tsamara.xyz/docs/status)

What is deployed, what has been proven, and what is not true yet.

## Deployed, on Solana devnet
|                    |                                                                                                                    |
| ------------------ | ------------------------------------------------------------------------------------------------------------------ |
| Compliance program | [`EjYxuJE4…WXXG`](https://explorer.solana.com/address/EjYxuJE4QE8P37scBxgWRHGigZ8hP6j3ysnSQ95MWXXG?cluster=devnet) |
| App                | [app.tsamara.xyz](https://app.tsamara.xyz)                                                                         |
| Operator API       | `api.tsamara.xyz`                                                                                                  |
| Indexer            | `indexer.tsamara.xyz`                                                                                              |
| Landing            | [tsamara.xyz](https://tsamara.xyz)                                                                                 |

The addresses of the live demo series (sukuk token, payment token, issuer) are on its
[asset page](https://app.tsamara.xyz/assets/gsd31), each linked to Solana Explorer.

## Proven
* **The whole lifecycle, on devnet.** Issue a series, approve investors, subscribe, transfer,
  pay a distribution, with assertions on the balances after each step.
* **The rules hold against attempts to break them.** Tests run the compiled program and try a
  transfer to an unregistered wallet, a forged recipient, a transfer over the cap, a revoked
  investor, and the hook called outside a transfer. Each is refused.
* **A real browser can do it.** A script drives Chrome through connect, fund, approval,
  subscribe, portfolio, transfer and a refused transfer, against devnet.
* **Identity verification end to end, in the sandbox.** A German test applicant is approved
  onchain; applicants from the United States and Indonesia are refused.
* **A distribution repeated is paid once.**

See [Testing](https://docs.tsamara.xyz/docs/testing) for how to run each of these.

## Not true yet
* **No licence, no regulatory approval, no sharia certification.** No sharia board has reviewed
  the structure.
* **The token represents nothing.** There is no underlying sukuk, no custodian, no trust or
  wakalah arrangement, and no affiliation with any sovereign issuer.
* **Not audited.** The compliance program has had no professional security review.
* **Single keys.** The issuer and compliance authorities are single keys held by the operator's
  API, not a multisig.
* **The holding cap is not enforced by the program on a primary subscription**, only by the API.
* **Tangibility is published, not enforced.** Nothing updates the ratio or restricts transfers
  to par when it falls.
* **Sandbox identity checks only**, with no sanctions or AML screening.
* **Devnet only.**

The gaps are tracked as issues labelled
[`compliance`](https://github.com/tsamara-xyz/tsamara/labels/compliance) and
[`production`](https://github.com/tsamara-xyz/tsamara/labels/production), and mapped in
[Compliance mapping](https://docs.tsamara.xyz/docs/compliance-mapping).

# The sukuk library (https://docs.tsamara.xyz/docs/sukuk-library)

packages/sukuk builds every instruction Tsamara sends.

`@tsamara/sukuk` is a TypeScript package of pure instruction builders on `@solana/web3.js` and
`@solana/spl-token`. It signs nothing and sends nothing: the caller decides who signs.

## A series
`SeriesTerms` describes a series: name, symbol, akad, maturity, currency,
`expectedProfitRateBps`, `paymentsPerYear`, `unitValue`, `restrictedJurisdictions`,
`maxHolding`, `tangibleAssetsBps` and `tangibilityAsOf`. `DEMO_SERIES` is the one the demo uses.

| Function                  | Use                                                                   |
| ------------------------- | --------------------------------------------------------------------- |
| `issueSeriesIxs`          | Create the mint with its extensions and publish the terms as metadata |
| `publishTermsIxs`         | Write or update the metadata fields                                   |
| `initializeComplianceIx`  | Create the series config for the transfer hook                        |
| `isEligible`              | Whether a country may hold the series                                 |
| `isTradableAtAgreedPrice` | Whether tangible assets are at least 51%                              |

## Investors
| Function             | Use                                                                                       |
| -------------------- | ----------------------------------------------------------------------------------------- |
| `approveInvestorIxs` | Register the investor and thaw their token account; throws early for a restricted country |
| `registerInvestorIx` | Only the investor record                                                                  |
| `revokeInvestorIx`   | Freeze the account                                                                        |

## Settlement
| Function       | Use                                                                             |
| -------------- | ------------------------------------------------------------------------------- |
| `subscribeIxs` | Payment to the issuer and minting to the investor, for one transaction          |
| `transferIx`   | A transfer with the hook's extra accounts resolved                              |
| `tradeIxs`     | Payment one way and units the other, between two investors, for one transaction |
| `payIx`        | A payment-token transfer                                                        |

The payment token is a `PaymentToken`: mint, decimals and token program. Any token on either
token program works.

## Distributions
| Function               | Use                                                               |
| ---------------------- | ----------------------------------------------------------------- |
| `periodicDistribution` | What a holding earns in one period, rounded down                  |
| `distributionBatches`  | Payments grouped eight to a transaction, each batch with its memo |
| `distributionMemo`     | `tsamara:distribution:<symbol>:<period>:<batch>`                  |

## Recovery
`forcedTransferIxs` moves units using the permanent delegate. It refuses to build the transfer
without a `reason` and an `orderedBy`, and adds a memo carrying both.

## Example
```ts
import { DEMO_SERIES, subscribeIxs } from '@tsamara/sukuk';

const ixs = subscribeIxs({
  sukukMint,
  payment,              // { mint, decimals, programId }
  issuer: issuer.publicKey,
  investor: wallet,
  units: 10n,
  terms: DEMO_SERIES
});
// One transaction, signed by the investor and the issuer.
```

# Testing (https://docs.tsamara.xyz/docs/testing)

What each layer of tests covers and how to run it.

| Layer                            | What it covers                                                                                                                                                | Run                                                  |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| Program, unit (Rust)             | Jurisdiction matching and account sizing                                                                                                                      | `cargo test --lib` in `contracts/`                   |
| Program, integration             | The compiled program with the TypeScript library, in-process on LiteSVM: who may initialize and register, transfers through the hook, the cap at its boundary | `bun test contracts`                                 |
| Program, regression and security | The hook refuses to run outside a transfer, a forged recipient is rejected, revoked investors cannot move units, and the known minting gap is pinned          | `bun test contracts`                                 |
| Library, unit                    | Distribution math, settlement amounts and token programs, instruction encoding, eligibility                                                                   | `bun test packages`                                  |
| Indexer, unit (Rust)             | Event classification and exactly-once storage                                                                                                                 | `cargo test --manifest-path apps/indexer/Cargo.toml` |
| App, unit and regression         | Derived figures, error explanations, request shape                                                                                                            | `bun test apps/app`                                  |
| End to end, devnet               | The full lifecycle with assertions; the API flow including Sumsub                                                                                             | `bun run demo`, `bun apps/api/smoke.ts`              |
| End to end, browser              | Chrome drives the app against devnet: connect, fund, approval, subscribe, portfolio, transfer, and a refused transfer                                         | `bun apps/app/e2e/investor-flow.ts`                  |

`bun test` runs every TypeScript suite and needs no network.

The program tests load `contracts/tests/fixtures/tsamara_compliance.so`. Run
`bun run --cwd contracts build` after changing the program, so they do not test a stale binary.

## Against a deployment
```sh
API=https://api.tsamara.xyz INDEXER=https://indexer.tsamara.xyz ADMIN_TOKEN=... bun apps/api/smoke.ts
```

## Continuous integration
Every pull request runs three jobs: lint, typecheck and the TypeScript suites; the indexer's
Rust tests; and the program's tests.

# Try the demo (https://docs.tsamara.xyz/docs/try-the-demo)

Subscribe to the demo series on devnet with a test wallet, in a few minutes.

The app is at [app.tsamara.xyz](https://app.tsamara.xyz). Everything in it runs on Solana
devnet with test dollars that have no value.

## Steps
1. **Connect.** Choose **Connect test wallet**. The app creates a devnet-only key in your
   browser, so you need no wallet extension. Phantom works too if it is switched to devnet.
2. **Open the series.** On Explore, choose **Invest now**, or open
   [GSD31](https://app.tsamara.xyz/assets/gsd31), the Global Sukuk Demo 2031.
3. **Get test dollars.** The panel offers $1,000 of test dollars.
4. **Verify your identity.** Verification runs in Sumsub's sandbox, so use Sumsub's test
   documents, never real ones. Your sukuk account stays frozen until you are registered.
5. **Subscribe.** Enter a number of units. You pay $10 a unit, and payment and delivery settle
   in one transaction.
6. **Look at your portfolio.** Holdings, distributions received and your history are built from
   indexed transactions.
7. **Send units.** Use the **Send** tab. A transfer to a wallet that is not a registered
   investor is refused by the chain, and the app says why.

Every result links to the transaction on Solana Explorer.

## The demo series
|                      |                                        |
| -------------------- | -------------------------------------- |
| Name                 | Global Sukuk Demo 2031 (GSD31)         |
| Structure            | Wakalah                                |
| Expected profit rate | 5.20% a year, distributed semiannually |
| Unit                 | $10                                    |
| Maturity             | 2031                                   |
| Holding cap          | 100 units per investor                 |
| Not offered in       | United States, Indonesia               |
| Tangible assets      | 51%, with an as-of date in the terms   |

The series is a mock. The other series in the catalogue are marked Preview: they are
illustrations, not issued, not onchain, and cannot be bought.

## The operator's side
The **Operator** page is the issuer's and the compliance officer's desk: completing a sandbox
review, paying a period's distribution, and ordering a forced transfer. It needs the operator's
admin token, which is not public.
