> For the complete documentation index, see [llms.txt](https://docs.t-rex.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.t-rex.network/the-primary-register/eligibility-and-compliance-the-two-gates.md).

# Eligibility and compliance: the two gates

Every change of ownership passes two gates before the register records it. The two gates ask different questions, live in different contracts and are configured by different means. These docs never merge them into "compliance checks".

|                     | Eligibility                                                                                    | Compliance                                                               |
| ------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| **Question**        | May this identity hold this asset?                                                             | May this movement happen now?                                            |
| **About**           | The holder                                                                                     | The movement, and the distribution that results from it                  |
| **Evaluated on**    | The recipient's identity                                                                       | The sender's identity, the recipient's identity, the amount, the spender |
| **Configured with** | Required claim topics and trusted Claim Issuers                                                | Compliance modules and their settings                                    |
| **Lives in**        | `TREXRegistry`                                                                                 | `ModularCompliance` and its modules                                      |
| **Entry point**     | `isVerified(address)`                                                                          | `canTransfer(from, to, amount)`                                          |
| **Changes when**    | A claim is added, expires or is revoked. The Issuer changes the topics or the trusted issuers. | Positions change. The Issuer changes the rules.                          |
| **Configured by**   | The `OWNER` role on the registry                                                               | The `OWNER` role on the compliance                                       |

"Adding an eligibility rule" means changing claim topics or trusted issuers. "Adding a compliance rule" means binding or configuring a module.

## Gate 1: eligibility

### What the Issuer configures

* **The required claim topics.** A claim topic is a number that stands for a fact about a holder: identity verified, accredited, resident of a permitted jurisdiction. The Issuer lists the topics its asset requires with `addClaimTopic`.
* **A different set per identity type, where needed.** With `addClaimTopicForIdentityType`, the Issuer defines the topics for one type of identity, for example `CORPORATE`. A set defined for a type replaces the default set for identities of that type. It does not add to it.
* **The trusted Claim Issuers.** With `addTrustedIssuer(trustedIssuer, claimTopics)`, the Issuer names a Claim Issuer and the topics it trusts that issuer for.

### How `isVerified` decides

```mermaid
flowchart TB
    S["isVerified(address)"] --> R{"Does the address<br/>resolve to an identity?"}
    R -- "no" --> N["Not verified"]
    R -- "yes" --> V{"Is it a wallet whose<br/>link was revoked?"}
    V -- "yes" --> N
    V -- "no" --> T["Read the identity's type<br/>Take the topics required for that type,<br/>or the default topics"]
    T --> Z{"Any topic required?"}
    Z -- "no" --> Y["Verified"]
    Z -- "yes" --> C{"For every required topic:<br/>a valid claim from a Claim Issuer<br/>trusted for that topic?"}
    C -- "yes" --> Y
    C -- "no" --> N
```

1. **Resolve the address to an identity.** A wallet registered for this asset by a Registry Agent resolves to the identity it was registered with. Any other wallet resolves through the global identity registry, to the identity its owner linked it to. An ONCHAINID resolves to itself. An address that resolves to no identity is not verified.
2. **Refuse a revoked wallet.** A wallet whose link the Identity Owner has revoked is not verified, even though it still resolves to its identity.
3. **Select the required topics.** The registry reads the type of the identity from the `IdentityFactory`, never from the identity itself. It takes the topics defined for that type if there are any, and the default topics otherwise. If no topic is required, the address is verified.
4. **Look for a valid claim per topic.** For each required topic, the registry goes through the Claim Issuers trusted for that topic. For each one it reads the claim that issuer made on the identity for that topic, and asks the issuer whether the claim is valid, with `isClaimValid`.
5. **Conclude.** The address is verified if and only if every required topic has at least one valid claim from a trusted Claim Issuer.

A claim is valid when it is inside its validity window, its digest has not been revoked, the key that signed it holds the `CLAIM_SIGNER` purpose on the issuer's identity, and the signature verifies.

### What follows

* **Eligibility belongs to the identity.** Every address of an identity shares it: the identity's own address and every wallet linked to it. An investor is verified once, not once per wallet or per chain.
* **A wallet with no claims behind it is not verified.** Linking or registering a wallet proves nothing about eligibility. The claims on the identity do.
* **A claim from an issuer the asset does not trust does not count,** however valid it is.
* **Revocation is immediate.** When a Claim Issuer revokes a claim, the identity stops being eligible at the next check. Nothing changes in the registry.
* **Expiry is automatic.** A claim past its `validUntil` stops counting without any transaction.
* **Configuration changes apply to everyone at once.** Adding a required topic makes every identity without a valid claim for it ineligible. Removing a trusted issuer does the same for every identity that relied on that issuer alone.
* **Losing eligibility does not remove a position, and does not lock it.** The gate is checked on the recipient. A holder that becomes ineligible keeps what it holds, can no longer receive, and can still transfer to an eligible recipient. This is by design: the holder was eligible when it received the tokens and is still identified, so it can liquidate its position. An Issuer that wants to block such a holder freezes its tokens or its address. A forced transfer and a redemption remain available too.

> **Not an allowlist.** The registry does not keep a list of approved addresses. It evaluates claims on the identity behind the address, at the moment of each transfer. No address is ever put on a list.

> **No personal data on-chain.** A claim carries a topic, an issuer, a signature, a validity window and a payload. The payload is a hash or an encoded value, not raw personal data.

### The eligibility switch

The `OWNER` of the registry can turn eligibility checks off with `disableEligibilityChecks`, and back on with `enableEligibilityChecks`. While they are off, `isVerified` returns true for every address. This exists for assets that do not restrict their holders. The compliance gate is unaffected, and as long as a rule module is bound, the compliance still refuses a recipient that resolves to no identity.

## Gate 2: compliance

### What the Issuer configures

The rules of the asset are compliance modules, bound to the `ModularCompliance` with `addModule`, or with `addAndSetModule` to configure a module in the same transaction. A module declares what it is, and the compliance calls it only for that.

| Type      | The question it answers                                                       | When it is asked                                                                               |
| --------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `RULE`    | What is the largest amount you allow for this movement? (`allowedAmount`)     | Before a transfer or a mint. When a cross-chain validation is issued.                          |
| `SPENDER` | May this spender execute this movement for the sender? (`moduleCheckSpender`) | Before an allowance is spent in `transferFrom`. When a cross-chain validation names a spender. |
| `TRACKER` | Nothing. It is told that a movement happened. (`afterTransfer`)               | After every movement the register records.                                                     |

### How `canTransfer` decides

1. **No rule, no limit.** If no `RULE` module is bound, the answer is true.
2. **Build the context once.** The compliance resolves the identity of the sender and of the recipient and puts them, with the addresses, the amount and the spender, in one `TransferContext`. Every module receives the same context. A module never resolves an address itself.
3. **Require an identity on each side.** A sender or a recipient that resolves to no identity is refused. A rule about distribution is keyed on identities and could not count a holder it cannot name.
4. **Ask every rule for its maximum.** Each `RULE` module returns the largest amount it allows. No limit is the maximum value, a refusal is zero.
5. **Keep the smallest answer.** The movement is allowed if its amount does not exceed the smallest answer.

Rules read the state of the asset from the **compliance ledger**, which the compliance keeps itself: the total position of each identity (`positionOf`), and what open cross-chain validations promise to it (`pendingInOf`) and from it (`pendingOutOf`). A rule therefore reasons about the investor, across all its addresses and all chains, and not about one wallet on one chain.

After the balances move, the compliance updates the positions and calls every `TRACKER` module.

A movement between two addresses of the same identity changes no position. Rules about distribution do not limit it.

### The spender

On `transferFrom`, a third party moves a holder's tokens. The compliance checks that third party as well. Before the allowance is spent, the token asks the compliance whether the caller may execute this transfer, and every `SPENDER` module must agree. If one refuses, the call reverts with `SpenderNotAllowed` and the allowance is untouched.

This closes the gap that would let an intermediary route a transfer in a way the rules are meant to prevent. A direct `transfer` has no spender and skips this check. When no `SPENDER` module is bound, every spender is accepted.

## Which operations pass which gate

| Operation              | Pause                             | Freeze                        | Eligibility of the recipient                                                                                                                     | Rules                                             | Spender policy                             | Authorized by                               |
| ---------------------- | --------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | ------------------------------------------ | ------------------------------------------- |
| `transfer`             | Blocks                            | Blocks                        | Checked                                                                                                                                          | Checked                                           | No spender                                 | The holder                                  |
| `transferFrom`         | Blocks                            | Blocks                        | Checked                                                                                                                                          | Checked                                           | Checked                                    | An allowance from the holder                |
| `identityTransfer`     | Blocks                            | Blocks                        | Checked                                                                                                                                          | Checked                                           | No spender                                 | The identity the `from` wallet is linked to |
| `mint`                 | Does not block                    | Not checked                   | Checked                                                                                                                                          | Checked                                           | No spender                                 | `AGENT_MINTER`                              |
| `burn`                 | Does not block                    | Unfreezes what the burn needs | Not applicable                                                                                                                                   | Not applicable                                    | No spender                                 | `AGENT_BURNER`                              |
| `forcedTransfer`       | Blocks                            | Overridden                    | Checked                                                                                                                                          | Not checked. The compliance is notified.          | No spender                                 | `AGENT_FORCED_TRANSFER`                     |
| `recoveryAddress`      | Blocks                            | Carried to the new wallet     | Not checked. The position stays with the same identity when the identity of the lost wallet is named, and moves to the named identity otherwise. | Not checked. The compliance is notified.          | No spender                                 | `AGENT_RECOVERY_ADDRESS`                    |
| Cross-chain validation | A per-chain issuance pause blocks | Not applicable                | Checked at issuance                                                                                                                              | Checked at issuance: they narrow the amount range | Checked at issuance, if a spender is named | The sender's identity, or `AGENT`           |

How to read it:

* **Holder operations pass both gates.** There is no path by which a holder moves tokens to an ineligible recipient or past a rule.
* **Agent operations are the servicing operations of the register.** A forced transfer executes a decision that overrides the holder: a court order, the correction of an error. It bypasses freezes and rules by design, and it is gated by a dedicated role. It still requires an eligible recipient, and it still tells the compliance, so positions stay correct.
* **The pause halts every movement between holders,** including forced transfers and recovery. Mints and burns stay possible while the token is paused.

## On a satellite chain

Neither gate runs on a satellite. T-REX Lite has no registry and no rules of its own. The compliance contract linked to it stores the validations it receives and decides nothing. Both gates run on the reference chain when the validation for a movement is issued: the recipient's eligibility, the rules against the global position set, the spender if one is named. T-REX Lite then executes against that validation and nothing else. A movement the gates would refuse receives no validation and never executes.

## Statements to avoid

| Statement                                        | What is true                                                                                              |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| "The wallet is whitelisted."                     | The identity behind the address holds valid claims from trusted Claim Issuers for the required topics.    |
| "The investor has the KYC flag."                 | Eligibility is not a boolean stored somewhere. It is evaluated from claims, per topic, at each transfer.  |
| "The protocol issued the KYC."                   | Claim Issuers sign claims. The protocol keeps the registries and checks the claims.                       |
| "The transfer passed the compliance checks."     | It passed two gates: eligibility, then compliance. Say which one is meant.                                |
| "Compliance checks the sender and the receiver." | Rules can depend on the complete distribution of the asset, and the spender is checked on `transferFrom`. |


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.t-rex.network/the-primary-register/eligibility-and-compliance-the-two-gates.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
