> 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/guides/identity/02.-deploy-an-onchainid.md).

# 02. Deploy an ONCHAINID

Deploying an ONCHAINID creates the on-chain identity of a participant: a smart account that holds its keys, carries its claims, can hold tokens and has its first wallet linked. A participant creates its own identity, or an operator creates it on the participant's behalf: typically the agent that onboards investors for an Issuer, or a Claim Issuer, when it meets a wallet that has no identity. The identity is then created with that wallet as its only manager. It happens once per participant, before any claim can be issued to it and before it can hold any asset.

## At a glance

|                   |                                                                                                                                                                                                                                                                      |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Triggered by**  | Identity Owner, or a Deployer acting for it                                                                                                                                                                                                                          |
| **Actors**        | Identity Owner, Deployer, Platform                                                                                                                                                                                                                                   |
| **Contracts**     | `IdentityFactory`, ONCHAINID, `ERC734Validator`                                                                                                                                                                                                                      |
| **Preconditions** | The identity type is registered in the `IdentityFactory`; to create for oneself, the type is self-deployable; to create for another account, the caller holds the creation role of that type; the account to link is not bound to any identity and was never revoked |
| **Result**        | An ONCHAINID exists at a deterministic address, with its type recorded, its keys registered, the modules of its type installed, and its first account linked                                                                                                         |

## Actors and roles

| Actor          | Role in this flow                                                                                                                                              | What they hold                                                                     |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Identity Owner | Creates its own identity, or receives one created for it. Controls it from then on.                                                                            | The account that becomes the first linked wallet, and the signers that become keys |
| Deployer       | Creates an identity for another account, when the Identity Owner does not do it itself. For an investor, it is an Issuer's onboarding agent or a Claim Issuer. | The creation role of the identity type, in the AccessManager of the network        |
| Platform       | Assembles the keys, submits the transaction and records the address.                                                                                           | The key of the party it acts for                                                   |

## Sequence

```mermaid
sequenceDiagram
    participant Platform
    participant Caller as Identity Owner or Deployer
    participant Factory as IdentityFactory
    participant Identity as ONCHAINID
    participant Validator as ERC734Validator

    Platform->>Factory: getIdentityTypePolicy(identityType) (read)
    Platform->>Factory: getIdentity(account) (read)
    Platform->>Caller: inputs ready, submit
    alt the owner creates its own identity
        Caller->>Factory: createIdentity(identityType, salt, keys)
    else a Deployer creates it for an account
        Caller->>Factory: createIdentityFor(account, identityType, salt, keys)
    end
    Factory->>Factory: type registered, caller allowed, inputs valid
    Factory->>Identity: deploy at the deterministic address, initialize
    Identity->>Validator: register the keys
    Factory->>Validator: at least one MANAGEMENT key that can sign
    Factory->>Factory: record the type, link the first account
    Factory-->>Platform: IdentityTypeRecorded, AccountLinked, IdentityDeployed
```

## Step by step

### Step 1. Prepare the inputs

**Who:** Platform, on behalf of the caller

**Call:** Off-chain, using read calls

**Before the call:** The participant has the signer it will control the identity with.

**What happens:** The Platform assembles three inputs.

`identityType` is the type of the participant: `INDIVIDUAL` (2), `CORPORATE` (3), `CLAIM_ISSUER` (5) and so on. The Platform reads `IdentityFactory.getIdentityTypePolicy(identityType)` to learn whether the type is self-deployable and which role creates it for others.

`salt` is a string, not empty, chosen freely.

`keys` is the list of keys the identity starts with. Each key has:

| Field        | Meaning                                                                                                                 |
| ------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `signerData` | The signer: the 20 bytes of an address, or a verifier address followed by a public key for a passkey or another scheme. |
| `keyHash`    | `keccak256` of `signerData`.                                                                                            |
| `purpose`    | `MANAGEMENT` (1), `ACTION` (2), `CLAIM_SIGNER` (3), `ENCRYPTION` (4), `CLAIM_ADDER` (5) or `PROPOSER` (6).              |
| `keyType`    | A label for the scheme: ECDSA (1), RSA (2), WebAuthn (3).                                                               |
| `clientData` | Data a client needs to use the key, for example a WebAuthn credential identifier. Can be empty.                         |

At least one key holds `MANAGEMENT`. The Platform reads `IdentityFactory.getIdentity(account)` for the account to link and expects zero.

**What changes:** Nothing on-chain.

### Step 2. Create the identity

**Who:** Identity Owner, from the account that becomes its first wallet. Or a Deployer holding the creation role of the type.

**Call:** `IdentityFactory.createIdentity(identityType, salt, keys)` by the owner. `IdentityFactory.createIdentityFor(account, identityType, salt, keys)` by a Deployer.

**Before the call:** Step 1 is done.

**What the contract checks:**

1. The type is registered. Otherwise the call reverts with `UnknownIdentityType`.
2. For `createIdentity`: the type is self-deployable. Otherwise `IdentityTypeNotSelfDeployable`.
3. For `createIdentityFor`: `account` is not zero, and the caller holds the creation role of the type, without an execution delay. Otherwise `ZeroAddress`, `NotAuthorizedForIdentityType` or `DelayedRoleNotSupported`.
4. For `createIdentityFor` on a type whose owner can sign: every key belongs to `account`. Otherwise `KeyNotForAccount`.
5. The salt is not empty and there is at least one key. Otherwise `EmptyString` or `EmptyListOfKeys`.
6. No key is of the module type. Otherwise `CallerKeyCannotBeModule`.
7. Each key is well-formed: its hash matches its signer data, the signer data has a valid length, the purpose is one of the six. Otherwise `InvalidSignerData`, `InvalidSignerLength` or `InvalidPurpose`.
8. The identity ends up with at least one `MANAGEMENT` key that can sign. Otherwise `NoManagementKeyInKeys`.
9. The first account is not an identity, was never revoked and is not bound to another identity. Otherwise `CannotLinkFactoryIdentity`, `WalletAlreadyRevoked` or `WalletBoundToAnotherIdentity`.
10. For `createIdentityFor` on a type whose owner can sign: `account` is the only `MANAGEMENT` key. Otherwise `AccountNotSoleManagementKey`.

**What changes:** The factory deploys the identity as a beacon proxy, at an address derived from the type, the salt, the first account and the keys. The identity records its type, installs the modules registered for that type and registers its keys. The factory records the type, makes the identity resolve to itself, and links the first account: the caller for `createIdentity`, `account` for `createIdentityFor`. The call returns the address of the identity.

Events: `KeyAdded` for each key, `IdentityTypeRecorded(identity, identityType)`, `AccountLinked(account, identity, caller)` and `IdentityDeployed(identity, account, identityType, deployer)`.

### Step 3. Record and verify

**Who:** Platform

**Call:** Off-chain, using read calls

**Before the call:** The transaction of step 2 is confirmed.

**What happens:** The Platform reads the address from `IdentityDeployed`. It confirms `IdentityFactory.identityTypeOf(identity)`, `IdentityFactory.getIdentity(account)`, which returns the identity, and `Identity.getKeysByPurpose(1)`, which returns the `MANAGEMENT` keys.

**What changes:** Nothing on-chain.

## State after the flow

* The identity exists, and `IdentityFactory.isFactoryIdentity(identity)` is true.
* `IdentityFactory.identityTypeOf(identity)` returns its type, which never changes.
* `IdentityFactory.getIdentity` returns the identity for its first account, and for the identity's own address.
* The identity holds the keys given at creation, and at least one `MANAGEMENT` key that can sign.
* The modules of its type are installed.
* The identity holds no claim. It is not eligible for any asset that requires one.
* The party that deployed an identity for another account holds no key on it.

## Failure modes

| Symptom                                                                     | Cause                                                                                    | Fix                                                                                                                                    |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Reverts with `UnknownIdentityType`                                          | The type is not registered in the factory (check 1)                                      | Use a registered type                                                                                                                  |
| Reverts with `IdentityTypeNotSelfDeployable`                                | The type cannot be created by its own owner, for example `CLAIM_ISSUER` (check 2)        | Have a party with the creation role use `createIdentityFor`                                                                            |
| Reverts with `NotAuthorizedForIdentityType`                                 | The caller does not hold the creation role of the type (check 3)                         | Use an account that holds the role                                                                                                     |
| Reverts with `DelayedRoleNotSupported`                                      | The caller holds the role with an execution delay (check 3)                              | Use a holder with no delay on this role                                                                                                |
| Reverts with `KeyNotForAccount` or `AccountNotSoleManagementKey`            | A Deployer passed a key that is not the account's, or a second manager (checks 4 and 10) | Pass keys of the account only. The owner adds other keys afterward ([22](/guides/identity/22.-add-and-remove-keys-on-an-onchainid.md)) |
| Reverts with `EmptyString` or `EmptyListOfKeys`                             | Empty salt, or no key (check 5)                                                          | Provide both                                                                                                                           |
| Reverts with `InvalidSignerData`, `InvalidSignerLength` or `InvalidPurpose` | A key is malformed (check 7)                                                             | Compute `keyHash` as `keccak256(signerData)` and use a purpose from 1 to 6                                                             |
| Reverts with `NoManagementKeyInKeys`                                        | No key holds `MANAGEMENT` (check 8)                                                      | Add a `MANAGEMENT` key                                                                                                                 |
| Reverts with `WalletBoundToAnotherIdentity`                                 | The first account is already linked to an identity (check 9)                             | The participant already has an identity. Use it, or use another account                                                                |
| Reverts with `WalletAlreadyRevoked`                                         | The first account was revoked from an identity (check 9)                                 | Use another account. A revoked wallet is never linked again                                                                            |
| Reverts in the deployment itself                                            | An identity already exists for the same type, salt, account and keys                     | Use that identity, or another salt                                                                                                     |

## Common misunderstandings

> **Wrong:** "The Issuer creates the investor's identity for its token."
>
> **Right:** An identity belongs to its owner and serves every asset. No Issuer owns it. A party can create one on a participant's behalf, and the factory guarantees that the participant's account is then its only manager. The party that paid for the deployment holds no key.

> **Wrong:** "Having an ONCHAINID makes an investor eligible."
>
> **Right:** A new identity holds no claim. Eligibility comes from claims signed by Claim Issuers that an asset trusts, for the topics the asset requires.

> **Wrong:** "The identity only stores keys and claims. Tokens stay in the wallet."
>
> **Right:** An ONCHAINID is a smart account. It holds tokens at its own address and transacts through its keys. The wallet linked at creation is one address of the identity, not the only place where it can hold a position.

> **Wrong:** "The same person can have one identity per chain."
>
> **Right:** The identity lives on the reference chain and links wallets on any chain. The same inputs also give the same identity address on every EVM chain where the factory sits at the same address.

## Integration notes

* Store the salt with the participant. With the type, the first account and the keys, it determines the address.
* For an investor without a gas token, a party with the creation role deploys the identity with `createIdentityFor`. The investor's account is the sole manager from the first block.
* An onboarding agent or a Claim Issuer that meets a wallet reads `IdentityFactory.getIdentityIncludingRevoked(account)` first. It creates an identity only when the wallet was never bound to one.
* With `createIdentityFor`, pass only keys of the named account. A passkey or a second device is added by the owner afterward.
* With `createIdentity`, the owner can register a passkey at creation. The calling account is still linked as the first wallet.
* Index `IdentityDeployed` and `IdentityTypeRecorded` to maintain the list of identities and their types.
* Read the type from `IdentityFactory.identityTypeOf(identity)`, never from the identity.

## Related flows

* [07 Link a wallet to an ONCHAINID](/guides/identity/07.-link-a-wallet-to-an-onchainid.md) : add other addresses
* [22 Add and remove keys on an ONCHAINID](/guides/identity/22.-add-and-remove-keys-on-an-onchainid.md) : add a passkey or a second device
* [28 Install the recovery module and manage guardians](/guides/identity/28.-install-the-recovery-module-and-manage-guardians.md) : install guardians early
* [21 Recover access to an ONCHAINID](/guides/identity/21.-recover-access-to-an-onchainid.md) : what the guardians do when the keys are lost
* [05 Issue a claim to an investor](/guides/claim-issuer/05.-issue-a-claim-to-an-investor.md) : what makes the identity eligible
* [01 Deploy a token suite](/guides/issuer/01.-deploy-a-token-suite.md) : creates the identity of a token


---

# 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/guides/identity/02.-deploy-an-onchainid.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.
