> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/apps-on-rome/bloom/compliance.md).

# Compliance model

Bloom runs Plume's Arc framework unmodified. Compliance is **enforced by the token contract itself** — not by any off-chain screen, sequencer filter, or venue policy. That is the property that makes it portable: the rules travel with the token to any execution path, on both wallet lanes.

## Enforcement architecture

```
ArcToken._update (every transfer/mint/burn)
   └─ RestrictionsRouter (one per chain, module-type registry)
        ├─ TRANSFER_RESTRICTION → WhitelistRestrictions (per token)
        ├─ YIELD_RESTRICTION    → YieldBlacklistRestrictions (per token)
        └─ GLOBAL_SANCTIONS     → (slot exists; no global module deployed)
```

* **WhitelistRestrictions** — the allowlist. While `transfersAllowed` is false (gated mode), a transfer where either side is off the list reverts with the typed error `TransferRestricted()` (`0xe827105e`). The check runs inside the token on every balance movement — an EVM-wallet transfer, a Solana-signed transfer, a storefront sale, and the initial liquidity move all pass through the same gate. There is no path around it short of the issuer's own admin powers.
* **YieldBlacklistRestrictions** — excludes addresses from yield distributions; their pro-rata share stays in the token contract.
* **GLOBAL\_SANCTIONS** — the router supports chain-wide modules applied to every token (e.g. a sanctions list). None is deployed today; the slot is the natural home for one operated at the chain level.

## The trust model, stated honestly

**The allowlist flag is the issuer's off-chain decision.** KYC/AML happens in the issuer's process (their vendors, their rules); the chain records and enforces the *outcome* — `isWhitelisted(addr)`. [Onboarding and review](/apps-on-rome/bloom.md) is the mechanism around that decision — how an investor applies, how the issuer decides, and the audit trail it leaves — and it does not change this model: still the issuer's call, still only a boolean on-chain, and no documents anywhere. This is the Arc framework's own model as used on Plume. It is deliberately *not* an on-chain identity system: there are no identity claims, no on-chain attestations, no cryptographic proof of who an address belongs to. Standards that carry verifiable on-chain identity (e.g. ERC-3643) trade significantly heavier transfers for that property; Arc trades lighter mechanics for issuer-held trust. Bloom surfaces this honestly rather than implying more.

## Issuer powers (transfer-agent shaped)

`ArcToken.initialize` grants the wizard driver every role:

| Role                                            | Power                                                                                    |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `ADMIN_ROLE` / `DEFAULT_ADMIN_ROLE`             | link/replace restriction modules, manage roles                                           |
| `MINTER_ROLE` / `BURNER_ROLE`                   | supply management                                                                        |
| `YIELD_MANAGER_ROLE` / `YIELD_DISTRIBUTOR_ROLE` | set the yield token, run distributions                                                   |
| `UPGRADER_ROLE`                                 | UUPS-upgrade the token (issuer-held; grant to the factory for factory-mediated upgrades) |
| Whitelist module `WHITELIST_ADMIN_ROLE`         | add/remove addresses, toggle gated mode                                                  |

Consequences worth knowing: a **lost investor wallet** is recoverable only via issuer action (whitelist a replacement address and, if needed, use mint/burn/upgrade powers per their legal process — Arc has no built-in forced-transfer primitive). The issuer's key custody is therefore part of the compliance posture; the app's role viewer makes the holders of each power visible.

## What Rome adds — and what registerToken preserves

Solana-wallet users appear as **synthetic EVM addresses** (derived from their Solana public key). To the compliance layer they are ordinary addresses: the issuer whitelists them, the gate checks them, yield reaches them — one allowlist spans both wallet worlds. Custody implications are in [LANES.md](/apps-on-rome/bloom/lanes.md).

Because Rome caps accounts per transaction, tokens deploy piecewise and gain factory status via `ArcTokenFactoryV2.registerToken` instead of the one-shot `createToken`. The guards preserve the upstream security model exactly: the token must be a canonical proxy (codehash), its implementation must be factory-whitelisted (codehash), the caller must hold the token's `ADMIN_ROLE`, and registration is once-only. Nothing about the compliance surface is weakened by the piecewise path.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.rome.builders/apps-on-rome/bloom/compliance.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
