> For the complete documentation index, see [llms.txt](https://docs.selcier.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.selcier.xyz/fundamentals/tokenized-share-classes.md).

# Tokenized share classes

What a Selcier Share Token is, which standards it follows, how a transfer gets validated, and the limits placed on supply, recovery, freezes, pauses and upgrades.

Each share class a company issues on Selcier lives in a contract of its own, called a Selcier Share Token. A company with Common, Series A Preferred and Series B Preferred shares therefore runs three tokens, and each of the three carries separate rules, a separate multiplier and a separate Reference Valuation.

## Three standards in one token

| Standard     | Job inside a Selcier Share Token                                                                                        |
| ------------ | ----------------------------------------------------------------------------------------------------------------------- |
| **ERC-20**   | The base layer: 18 decimals, plus the balances, transfers and allowances ordinary wallets and libraries already handle. |
| **ERC-3643** | The permissioning layer: nothing settles until holder identity and compliance rules have been checked.                  |
| **ERC-8056** | The scaling layer: `uiMultiplier()` adjusts how many shares a token stands for, and balances are never rebased.         |

At a multiplier of `1e18` (1.0), a token and a share are the same thing. Run a 2-for-1 split and it moves to `2e18`: nobody's raw balance changes, yet each balance now stands for double the shares. [Shareholder events](/fundamentals/shareholder-events.md) walks through the mechanics.

## Contract surface

```solidity
interface ISelcierShareToken is IERC20, IERC3643, IERC8056 {
    // Identity and transfer rules
    function identityRegistry() external view returns (IIdentityRegistry);
    function ruleEngine() external view returns (IRuleEngine);
    function canTransfer(address from, address to, uint256 amount)
        external view returns (bool ok, bytes32 reasonCode);

    // Corporate actions (ERC-8056)
    function uiMultiplier() external view returns (uint256); // 1e18 = 1.0

    function isAgent(address account) external view returns (bool);

    // Issuer controls (role-gated, timelocked where noted, all emit events)
    function mint(address to, uint256 amount, bytes32 ref) external;
    function burn(address from, uint256 amount, bytes32 ref) external;
    function approveRecovery(address lost, address replacement, bytes32 ref) external;
    function cancelRecovery(address lost) external;
    function recover(address lost, address replacement, bytes32 ref) external;
    function freezePartial(address holder, uint256 amount, bytes32 reason) external;
    function unfreezePartial(address holder, uint256 amount) external;
    function pause(bytes32 reason) external;
    function unpause() external;
    function scheduleMultiplier(uint256 newMultiplier, uint64 effectiveAt) external;
    function applyMultiplier() external;

    // Metadata
    function shareClass() external view returns (bytes32);
    function companyId() external view returns (bytes32);
    function documentsRoot() external view returns (bytes32);
    function unlockedBalanceOf(address holder) external view returns (uint256);

    // Snapshots
    function clock() external view returns (uint48);
    function balanceOfAt(address account, uint48 timepoint) external view returns (uint256);
    function totalSupplyAt(uint48 timepoint) external view returns (uint256);
}
```

Events and the remaining contract detail are documented in the [Smart contract map](/build-on-selcier/smart-contracts.md).

## The route every transfer takes

There is one route, and `transfer`, `transferFrom`, Liquidity Window settlement and RFQ fills all share it.

1. **Token checks.** A transfer stops here if the token is paused, if a recovery is scheduled against the sender's wallet, or if the sender's balance net of frozen tokens falls short. Anything sitting in a Liquidity Window order has already left the sender's balance, because it moved into the window's escrow when the order went in.
2. **Identity checks.** The [Identity Registry](/fundamentals/verified-holders.md) must find both parties linked to identities whose `IDENTITY_VERIFIED` and `SCREENED` claims are valid and unexpired. Agents are excused on their own side of the transfer. An agent is either the company's `LiquidityWindow` or a venue with a `VENUE` claim for the token, and the exemption exists so that the rules land on the people at either end of a trade instead of on the escrow between them.
3. **Rule checks.** The [Rule Engine](/fundamentals/compliance-modules.md) calls each module enabled for the class.
4. **Settlement.** With everything passed, balances update and modules refresh their state, such as holder counts and lot records.

A failure at any step reverts with `TransferNotAllowed(reasonCode)`. The view function `canTransfer` runs identical logic at no gas cost and answers `(false, reasonCode)`. Portfolio and the API consult it before requesting a signature, so people read an explanation like `HOLDING_PERIOD_ACTIVE` in place of a failed transaction. Every code is listed in [Transfer outcome codes](/build-on-selcier/transfer-outcomes.md).

## Limits built into the design

### Each class gets its own contract

Classes differ in rights, rules and valuation, so they cannot share a contract. Keeping them apart also follows the one-token-per-asset convention on Robinhood Chain, a convention that makes price feeds and multipliers easier for integrators.

### Supply moves through mint and burn alone

These two functions are the only way supply can change, and each one requires a `ref` that identifies a record anchored in the `DisclosureRegistry`, such as the offering or board resolution behind the change.

| Function | Who may call it                                                              | Extra check                               | Event                               |
| -------- | ---------------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------- |
| `mint`   | `REGISTRAR` or `MINTER` (the company's `OfferingVault` is the only `MINTER`) | The full rule check runs on the recipient | `SharesIssued(to, amount, ref)`     |
| `burn`   | `REGISTRAR`                                                                  | None                                      | `SharesRedeemed(from, amount, ref)` |

Those events let anyone reconcile total supply.

### Lost wallets are recovered, never held

Selcier does not take custody of holder tokens at any point. A holder who can no longer reach a wallet re-verifies their identity, and the tokens can then move to a replacement wallet in four stages.

1. Approval has to come from two parties out of `ISSUER_ADMIN`, `REGISTRAR` and `OPERATOR`. Each uses `approveRecovery(lost, replacement, ref)`, which emits `RecoveryApproved`. The replacement wallet has to be verified already.
2. The approval from the second, different party starts a delay of 72 hours by default, and never under 48. It also emits `RecoveryScheduled(lost, replacement, eta, ref)`, which makes the pending recovery public before anything moves.
3. Throughout the delay the lost wallet is blocked from transferring. The person holding the original wallet may still object, and any of the three parties may stop the process with `cancelRecovery`, which emits `RecoveryCancelled`.
4. When the delay ends, the registrar calls `recover`, which carries across the balance, the frozen amount and the lot history.

### Freezes target an amount and leave a record

`freezePartial` applies to a stated amount in a stated wallet, a dispute being the typical case, and emits `TokensFrozen(holder, amount, reason)`. The tokens remain in place and go on earning distributions. They become transferable again only through `unfreezePartial`.

### Pauses work instantly and state a reason

Either `PAUSER`, meaning the issuer or the registrar, can halt a share token on the spot, perhaps for a corporate action or an incident. `pause` requires a reason and emits `Paused(reason)`, after which all transfers fail with `TOKEN_PAUSED`. For as long as the pause lasts, the `ValuationOracle` keeps its last published value.

### Upgrades are narrow and slow

A UUPS proxy fronts the token logic. An upgrade has to pass through the `IssuerTimelock`, a multi-sig with the issuer among its signers, and wait out a delay of 7 days. Rule modules live in contracts of their own, which means a rule change leaves the token untouched.

## Reading token metadata

| Function                    | Answer it gives                                                                            |
| --------------------------- | ------------------------------------------------------------------------------------------ |
| `companyId()`               | Identifier of the company, identical across its share classes                              |
| `shareClass()`              | The `bytes32` class name, such as `SERIES_B_PREFERRED`                                     |
| `documentsRoot()`           | The `DisclosureRegistry`-anchored Merkle root covering whatever documents govern the class |
| `uiMultiplier()`            | The `1e18`-scaled count of shares behind each token                                        |
| `unlockedBalanceOf(holder)` | What the holder could move at this moment                                                  |

To arrive at `unlockedBalanceOf`, the token takes what the wallet holds and deducts two things: frozen tokens, and anything locked according to the Rule Engine's modules, such as holding periods or unvested shares. During a scheduled recovery it returns zero. Treat the figure as conservative, because checks such as region or holder cap still apply when the transfer happens. For a holder's complete position, call `GET /v1/holders/{id}/lots`.


---

# 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.selcier.xyz/fundamentals/tokenized-share-classes.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.
