> 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/under-the-hood/platform-design.md).

# Platform design

A tour of Selcier's two layers, the contracts on Robinhood Chain and the services around them, with a step-by-step trace of a share transfer and an offering close.

Two layers make up Selcier. Contracts deployed on Robinhood Chain form the **on-chain layer**, the place where balances are held, transfer rules are enforced and corporate actions are recorded, without exception. Selcier-run services form the **platform layer**, which makes those contracts practical through onboarding, transaction submission, indexing, the Explorer and webhooks.

This division is intentional, because ownership decisions belong on-chain. Preparing, submitting and displaying transactions is as far as the platform reaches. By itself it has no way to move tokens out of a holder's wallet or to set aside rules that a company has put in place.

```
┌────────────────────────────── Selcier platform ──────────────────────────────┐
│                                                                              │
│  Console      Portfolio      API / SDK            Explorer      Webhooks     │
│     │             │              │                    ▲             ▲        │
│     └─────────────┴──────┬───────┘                    │             │        │
│                          ▼                            │             │        │
│   Issuance · Rules · Offerings · Identity orchestration · Corporate actions  │
│                          │                            │             │        │
│                          ▼                            │             │        │
│              Transaction queue ──► Signing (HSM / MPC relayers)     │        │
│                          │                            │             │        │
│                          │               Indexer (archive RPC, failover)     │
└──────────────────────────┼────────────────────────────▲──────────────────────┘
                           │ signed transactions        │ blocks and events
                           ▼                            │
┌──────────────────────── Robinhood Chain (4663) ──────────────────────────────┐
│  SelcierFactory ─► per company: IdentityRegistry, TrustedVerifiers,          │
│  per share class: SelcierShareToken, RuleEngine + modules                    │
│  OfferingVault · LiquidityWindow · RFQSettlement · PoolGate                  │
│  DistributionVault · Governance · DisclosureRegistry · ValuationOracle       │
│  IssuerTimelock                                                              │
└───────────────────────────────────┬──────────────────────────────────────────┘
                                    ▼
                            Ethereum (settlement)
```

## Contracts on Robinhood Chain

All deployments trace back to one root address, `SelcierFactory`. Deploying a company creates its company-level contracts in a single transaction, and `CompanyDeployed` names each of them. Share classes are added afterwards through `deployShareClass`, and `ShareClassDeployed` names the class's token, `RuleEngine` and `ValuationOracle`. A class with pools enabled also produces `PoolGateDeployed`. Reading those events is enough to locate everything a company owns.

| Scope               | Contracts                                                                                  |
| ------------------- | ------------------------------------------------------------------------------------------ |
| One per company     | `IdentityRegistry`, `TrustedVerifiers`                                                     |
| One per share class | `SelcierShareToken`, plus a `RuleEngine` running whichever modules the company has enabled |

The surrounding work falls to a set of operational contracts:

| Work            | Contract                                       |
| --------------- | ---------------------------------------------- |
| Offerings       | `OfferingVault`                                |
| Liquidity       | `LiquidityWindow`, `RFQSettlement`, `PoolGate` |
| Payouts         | `DistributionVault`                            |
| Votes           | `Governance`                                   |
| Document hashes | `DisclosureRegistry`                           |
| Valuations      | `ValuationOracle`                              |

A company's `IssuerTimelock` stands in front of its sensitive changes.

Interfaces for each contract appear in the [Smart contract map](/build-on-selcier/smart-contracts.md), and the [Chain event catalog](/build-on-selcier/chain-events.md) covers what they emit.

## Services run by Selcier

| Service                    | What it handles                                                                                                                                                                                                                      |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Issuance**               | Converts cap table imports and Console actions into factory deployments, mints and conversions, then reconciles the balances on-chain with the registrar's records.                                                                  |
| **Rules**                  | Assembles module configurations from Console input, simulates `canTransfer` ahead of a user's signature, and puts any failure into plain language.                                                                                   |
| **Offerings**              | Runs the lifecycle of each offering and Liquidity Window from creation to close, along with the subscription and order records.                                                                                                      |
| **Identity orchestration** | Sends investors to verification providers and takes their results by webhook. A claim-signing service then writes the claims to the `IdentityRegistry`. Re-screening is scheduled here, and lapsed claims are revoked here too.      |
| **Corporate actions**      | Covers votes, document anchoring, distribution funding and the scheduling of multiplier changes.                                                                                                                                     |
| **Indexer**                | Decoded events land in Postgres after each block is fetched through an archive RPC endpoint. Alchemy is the primary provider and Chainstack the failover, and divergence between them shows up when their block hashes are compared. |
| **Explorer**               | Publishes the public record at [explorer.selcier.xyz](https://explorer.selcier.xyz), using indexed chain data and nothing else.                                                                                                      |
| **Webhooks**               | Companies and partners register endpoints, and this service sends them signed notifications of events. Details are in [Event delivery](/build-on-selcier/event-delivery.md).                                                         |

### Who signs what

Holder keys stay out of Selcier's hands. A holder signs from their own wallet, which may be external or an embedded wallet set up at onboarding.

The `OPERATOR` keys are a different matter: Selcier holds those, and uses them to submit transactions and sponsor gas. Every company has a separate operator signer, kept in hardware security modules or divided across an MPC cluster, which means a complete key never sits on one machine. That role has a tight scope. Relaying transactions, paying for them and co-signing recoveries all fall within it, while moving a holder's tokens unaided does not. A signer-by-signer breakdown is in [Access control](/under-the-hood/access-control.md).

### How writes reach the chain

An idempotent queue carries all writes. Because a job's key is deterministic, neither a repeated API call nor a worker restart can submit one action twice. Nonces are assigned per signer, gas is estimated, and the job then goes to the Robinhood Chain sequencer.

Ordered transactions appear on the sequencer feed ahead of being batched to Ethereum, and the workers subscribe to it. The soft confirmation this gives the platform arrives in well under a second, and the Console and Portfolio present it as "confirmed". Tracking continues until the batch holding the transaction lands on Ethereum, with both milestones recorded. Should the primary feed drop, workers move to the delayed feed, which has separate capacity and trails by about 500 ms. See [The network underneath](/under-the-hood/network-foundation.md) for more on the two confirmation levels.

## Trace: a share transfer

Suppose a holder uses Portfolio to send 1,000 shares of a company's Common class to a second verified holder.

1. As a first step, the rules service gets a request from Portfolio and evaluates `canTransfer(from, to, 1000e18)` against the most recent block. The answer is either `OK` or a reason code like `HOLDING_PERIOD_ACTIVE`, and Portfolio displays any such code before a signature is requested.
2. Next comes the signature from the holder's wallet. They need no ETH, since gas is sponsored.
3. Once the transaction is with the sequencer, `transfer` has the share token call on the `RuleEngine`, which repeats the check across all enabled modules. Only this on-chain run decides the outcome. The prior simulation's sole purpose was an early, readable message.
4. A single failing module reverts the transaction and leaves balances untouched. When all modules pass, balances update, the sender's oldest unlocked lots are used up first, and `Transfer` is emitted.
5. From there, the sequencer feed hands the event to the indexer. Registered webhook endpoints get `transfer.settled`, and the Explorer lists the transfer with the two wallet addresses but no identities.

## Trace: an offering close

Here the `closesAt` time of an offering has gone by, and subscriptions exceed its minimum raise.

1. `OfferingVault.close(offeringId)` is called, either by the company directly or by the offerings service acting for it.
2. The vault compares the total with the configured minimum and maximum. Oversubscription leads to a pro-rata allocation, with the surplus reserved for refunds.
3. Within that one transaction, shares are minted to each investor as a new lot and USDG goes to the company treasury, less the platform fee. Each mint emits `SharesIssued`, and the offering as a whole emits `OfferingClosed`.
4. The issuance service pairs every `SharesIssued` event with the registrar's records, keeping the chain and the cap table in agreement.
5. `offering.closed` reaches webhook endpoints, investors find the position in Portfolio, and the final figures become visible in the Explorer.

An offering that misses its minimum takes a different path: the vault emits `OfferingFailed`, and each investor is then able to call `refund`. [Raising primary capital](/markets-and-capital/primary-raises.md) walks through the whole lifecycle.


---

# 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/under-the-hood/platform-design.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.
