06. Register an investor for an asset
Registering an investor attributes an address to an identity for one asset. It is a local registration, made by an agent of the Issuer in the asset's own registry. Most holders do not need it: an investor that links its wallets to its ONCHAINID, or holds in the ONCHAINID itself, is recognized by every asset without any registration. An agent registers an address that cannot link itself and has to hold the asset: a custody account, a contract that cannot sign, an omnibus wallet.
At a glance
Triggered by
Registry Agent
Actors
Registry Agent, Issuer, Investor, Platform
Contracts
TREXRegistry, IdentityRegistryStorage, IdentityFactory (read only)
Preconditions
Result
For this asset, and for every asset that shares its identity storage, the address resolves to the Investor's identity
Actors and roles
Registry Agent
Submits the registration. Typically the same operator as the Token Agent.
AGENT on the TREXRegistry
Issuer
Decides that the address is to be attributed to the Investor for its asset. Does not transact in this flow.
Its own verification of who controls the address
Investor
Is the subject of the registration. Does not transact.
An ONCHAINID
Platform
Runs the reads and submits with the Registry Agent's key.
The Registry Agent's signing key, or a key authorized for it
Sequence
Step by step
Step 1. Check the address
Who: Platform, on behalf of the Registry Agent
Call: Off-chain, using read calls
Before the call: The Issuer has established that the address belongs to the Investor.
What happens: The Platform reads TREXRegistry.isLocallyRegistered(address), which must be false. It reads TREXRegistry.identity(address) to see what the address resolves to before the registration. If it already returns the Investor's identity, the address is linked globally and no registration is needed. If it returns another identity, the registration overrides the global link for this asset: the Platform reports it to the Issuer before going further. It reads IdentityFactory.identityTypeOf(identity), which is not zero for an identity the factory created. It also reads Token.balanceOf(address): registering an address that already holds tokens changes the identity those tokens are attributed to.
What changes: Nothing on-chain.
Step 2. Register the address
Who: Registry Agent (AGENT)
Call: TREXRegistry.registerIdentity(userAddress, identity, country)
Before the call: Step 1 passed. The country argument is required by the standard interface and is ignored. Pass zero.
What the contract checks:
The caller holds
AGENTin the asset's domain. Otherwise the call reverts withAccessManagedUnauthorized.The identity storage accepts the registry as a writer: the registry holds
IRS_WRITERin the storage's domain, which commissioning grants. OtherwiseAccessManagedUnauthorized, naming the registry.Neither the address nor the identity is zero. Otherwise
ZeroAddress.The address has no local registration in the storage. Otherwise
AddressAlreadyStored.
The contract does not check that the identity was created by the IdentityFactory, that it holds any claim, or that the address is controlled by its owner. Those are the Issuer's responsibility. The recommendation is to register only identities created by the IdentityFactory: an identity from another source is unlikely to be accepted elsewhere in the ecosystem.
What changes: The storage records the address under the identity and emits IdentityStored(address, identity). When the address is linked globally to a different identity, it also emits IdentityOverridden(address, globalIdentity, localIdentity). The registry emits IdentityRegistered(address, identity). From now on, for this asset, the address resolves to the registered identity.
Step 3. Confirm the effect
Who: Platform
Call: Off-chain, using read calls
Before the call: Step 2 is confirmed.
What happens: The Platform reads TREXRegistry.identity(address), which returns the registered identity, and TREXRegistry.isVerified(address), which is true only if that identity holds a valid claim from a trusted Claim Issuer for every required topic.
What changes: Nothing on-chain.
State after the flow
TREXRegistry.isLocallyRegistered(address)is true, andTREXRegistry.contains(address)is true.TREXRegistry.identity(address)returns the registered identity, whatever the global identity registry says for that address.The registration applies to every asset whose registry is bound to the same
IdentityRegistryStorage.TREXRegistry.isVerified(address)reflects the claims of the registered identity. The registration has given no eligibility by itself.Nothing changed in the
IdentityFactory. The address is not linked to the identity for any other Issuer's asset.If the address held tokens, the compliance attributes them to the registered identity from the next movement through that address.
Failure modes
Reverts with AccessManagedUnauthorized
The caller does not hold AGENT in the asset's domain (step 2, check 1)
Grant the role: 25
Reverts with AccessManagedUnauthorized, naming the registry
The registry does not hold IRS_WRITER on the identity storage: the suite is not commissioned, or the storage is shared and sits in another domain (step 2, check 2)
Commission the suite: 25
Reverts with ZeroAddress
The address or the identity is zero (step 2, check 3)
Pass both
Reverts with AddressAlreadyStored
The address already has a local registration (step 2, check 4)
To change it, use 17
The address is registered and still cannot receive
The registered identity lacks a valid claim for a required topic
Registration is attribution. Eligibility comes from claims: 05
The address is registered and still cannot receive, with valid claims
The address is a wallet its owner revoked in the global identity registry. A local registration does not reinstate it
Use another address
A registration made for one asset appears on another
Both registries are bound to the same identity storage
Intended for an Issuer's assets that share a storage. Use separate storages to separate them
The registration succeeded and the address is not recognized by another Issuer's asset
A local registration is local to one storage
The other Issuer's agent registers the address in its own storage. An address that can link itself is linked globally by its owner instead: 07
An IdentityOverridden event was emitted
The address is linked globally to a different identity than the one registered
Check that the override is intended. If not, remove it: 18
Common misunderstandings
Wrong: "Every investor has to be registered before it can hold the asset."
Right: No registration is needed for an address that is an ONCHAINID or a wallet its owner linked to one. The registry resolves it through the global identity registry. Registration by an agent is for addresses that cannot link themselves.
Wrong: "An omnibus wallet is registered to the investors behind it."
Right: An omnibus wallet, for example at a centralized exchange, is registered to the identity of the entity that operates it. The register records that entity as the holder. The individual owners behind the omnibus position are in the operator's own books.
Wrong: "Registering the investor whitelists the wallet."
Right: Registration says whose the address is, for this asset. Whether that identity may hold the asset is decided from its claims, at each transfer. A registered address whose identity has no valid claims is not verified.
Wrong: "The agent registers the investor's country."
Right: The registry stores no country. The
countryargument is ignored. Where an investor resides is attested by a claim on its identity, and any rule about it is a compliance module.
Wrong: "A local registration and a global link are the same record."
Right: They are two records in two contracts. The global link is made by the owner, in the
IdentityFactory, for every asset. The local registration is made by an agent, in the asset's identity storage, for the assets that share it. When both exist, the local one takes precedence for those assets.
Integration notes
Read
identity(address)before registering. If it already returns the right identity, do nothing.Use
TREXRegistry.batchRegisterIdentity(addresses, identities, countries)for many addresses. It is gated by the same role and reverts as a whole if one entry fails. The three lists have the same length.Index
IdentityStoredtogether withIdentityOverridden. An override logs both, in that order, and the second is what tells an indexer that the asset departs from the global link.The token registers an address itself in one case: the recovery of a lost wallet registers the new address when it resolves nowhere.
Do not register an address to give it eligibility. It has no such effect.
Keep the Issuer's evidence that the address belongs to the identity. The contract takes the agent's word.
An address that can sign, or that can send a message from its own chain, links itself in the global identity registry. Registration by an agent is not the path for it.
Related flows
07 Link a wallet to an ONCHAINID : the owner's global link, which usually makes this flow unnecessary
17 Update an investor's registration : changing the registered identity
18 Remove an investor's registration : deleting the local registration
05 Issue a claim to an investor : what makes the identity eligible
15 Recover a position from a lost wallet : registers a new address as part of a recovery
Last updated