> 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/reference/token-suite/token.md).

# Token

`Token` is the ERC-20 of an asset on the reference chain and the entry point of its cross-chain messages. It enforces the pause, the freezes, the eligibility of the recipient and the compliance rules on every transfer, and keeps the record of what is active on each satellite. The concepts are in [The permissioned token](/token-and-register/the-permissioned-token.md) and [The balance model](/token-and-register/the-balance-model.md).

### At a glance

|                   |                                                                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Source**        | `contracts/token/Token.sol`, on the standard base `contracts/ERC-3643/base/ERC3643Token.sol` and on `contracts/interop/TREXMessaging.sol` |
| **Interfaces**    | `IToken`, which extends `IERC3643`. ERC-20, ERC-20 metadata, ERC-2612 `permit`, `ITREXMessaging`, ERC-7786 recipient                      |
| **Deployed as**   | A beacon proxy, at a CREATE3 address derived from the salt of the suite. `version()` returns `5.0.0`                                      |
| **Access**        | The suite's `TREXAccessManager`. Roles are those of the asset's domain                                                                    |
| **Initial state** | Paused. An `AGENT_PAUSER` calls `unpause` to open transfers                                                                               |

### Information and wiring

| Function                                                                                                                                                         | Access                                  | Reverts with                                                                                                                                                                  |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `init(tokenName, tokenSymbol, tokenDecimals, identityRegistryAddress, complianceAddress, trustedGatewayRegistryAddress, onchainIdAddress, accessManagerAddress)` | Initializer, called once by the factory | `EmptyString` for an empty name or symbol, `DecimalsOutOfRange` above 18, `ZeroAddress`                                                                                       |
| `setName(_name)`, `setSymbol(_symbol)`                                                                                                                           | `TOKEN_MANAGER`                         | `EmptyString`. A new name changes the ERC-712 domain of `permit`: signatures made under the previous name stop being valid                                                    |
| `setOnchainID(_onchainID)`                                                                                                                                       | `IDENTITY_MANAGER`                      |                                                                                                                                                                               |
| `setIdentityRegistry(_identityRegistry)`                                                                                                                         | `IDENTITY_MANAGER`                      | `InvalidIdentityRegistry`. `TokenCirculating` when a registry is already set and the supply is not zero                                                                       |
| `setCompliance(_compliance)`                                                                                                                                     | `IDENTITY_MANAGER`                      | `InvalidCompliance`, `ComplianceAlreadyBoundToToken` when the compliance serves another token. `TokenCirculating` when a compliance is already set and the supply is not zero |
| `name()`, `symbol()`, `decimals()`, `version()`, `onchainID()`, `identityRegistry()`, `compliance()`, `paused()`                                                 | Anyone, read                            |                                                                                                                                                                               |

The first three setters emit `UpdatedTokenInformation`. The last two emit `IdentityRegistryAdded` and `ComplianceAdded`.

### Holder functions

| Function                                                                      | Access                                       | Reverts with                                                                                                                                                                                                      |
| ----------------------------------------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transfer(to, value)`                                                         | The holder of the sending address            | In this order: `EnforcedPause`, `FrozenWallet` for the sender then the recipient, `ERC20InsufficientBalance` above the free balance, `UnverifiedIdentity` for the recipient, `ComplianceNotFollowed`, `ZeroValue` |
| `transferFrom(from, to, value)`                                               | A spender with an allowance                  | `SpenderNotAllowed` when the spender policy refuses the caller, then `ERC20InsufficientAllowance`, then the checks of `transfer`                                                                                  |
| `approve(spender, value)`, `permit(owner, spender, value, deadline, v, r, s)` | The holder, or anyone carrying its signature | The standard ERC-20 and ERC-2612 errors. The spender policy is not asked                                                                                                                                          |
| `batchTransfer(_toList, _amounts)`                                            | The holder of the sending address            | `ArrayLengthMismatch`. Each entry is a `transfer`                                                                                                                                                                 |
| `identityTransfer(from, to, amount)`                                          | The ONCHAINID that `from` resolves to        | `NotLinkedIdentity`, then the checks of `transfer`. No allowance is read. Emits `IdentityTransfer` after `Transfer`                                                                                               |

The eligibility of the sender is not checked. See [10 Transfer between investors](/guides/positions/10.-transfer-between-investors.md) and [24 Transfer through the identity](/guides/identity/24.-transfer-through-the-identity.md).

### Agent functions

| Function                                                                                               | Access                   | Checks and reverts                                                                                                                                                                                                   |
| ------------------------------------------------------------------------------------------------------ | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mint(_to, _amount)`, `batchMint(_toList, _amounts)`                                                   | `AGENT_MINTER`           | `UnverifiedIdentity` for the recipient, `ComplianceNotFollowed`, `ZeroValue`, `ArrayLengthMismatch`. The pause and a freeze on the recipient do not stop a mint                                                      |
| `burn(_userAddress, _amount)`, `batchBurn(_userAddresses, _amounts)`                                   | `AGENT_BURNER`           | `ERC20InsufficientBalance`, `ZeroValue`, `ArrayLengthMismatch`. No eligibility check and no rule. Frozen tokens are released when the burn needs them (`TokensUnfrozen`). The pause does not stop a burn             |
| `setAddressFrozen(_userAddress, _freeze)`, `batchSetAddressFrozen(_userAddresses, _freeze)`            | `AGENT_ADDRESS_FREEZER`  | `ArrayLengthMismatch`. Emits `AddressFrozen`                                                                                                                                                                         |
| `freezePartialTokens(_userAddress, _amount)`, `batchFreezePartialTokens(_userAddresses, _amounts)`     | `AGENT_PARTIAL_FREEZER`  | `ERC20InsufficientBalance` when the amount exceeds what is not already frozen. Emits `TokensFrozen`                                                                                                                  |
| `unfreezePartialTokens(_userAddress, _amount)`, `batchUnfreezePartialTokens(_userAddresses, _amounts)` | `AGENT_PARTIAL_FREEZER`  | `AmountAboveFrozenTokens`. Emits `TokensUnfrozen`                                                                                                                                                                    |
| `forcedTransfer(_from, _to, _amount)`, `batchForcedTransfer(_fromList, _toList, _amounts)`             | `AGENT_FORCED_TRANSFER`  | `EnforcedPause`, `UnverifiedIdentity` for the recipient, `ERC20InsufficientBalance`, `ZeroValue`. Freezes and rules are not checked. Frozen tokens are released when needed. Emits `ForcedTransfer` after `Transfer` |
| `recoveryAddress(_lostWallet, _newWallet, _investorOnchainID)`                                         | `AGENT_RECOVERY_ADDRESS` | `EnforcedPause`, `SameWalletRecovery`, `NoTokenToRecover`, `RecoveryNotPossible` when neither address is known to the registry. Moves the whole balance, carries the freezes over, and emits `RecoverySuccess`       |
| `pause()`, `unpause()`                                                                                 | `AGENT_PAUSER`           | `EnforcedPause`, `ExpectedPause`. Emit `Paused`, `Unpaused`                                                                                                                                                          |

Guides: [08](/guides/positions/08.-mint-a-position-to-an-investor.md), [09](/guides/positions/09.-burn-a-position.md), [13](/guides/agents/13.-freeze-and-unfreeze-an-address-or-a-partial-balance.md), [14](/guides/agents/14.-execute-a-forced-transfer.md), [15](/guides/agents/15.-recover-a-position-from-a-lost-wallet.md), [16](/guides/agents/16.-pause-and-unpause-a-token.md).

### Balance views

| View                                                               | Returns                                                                                              |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| `balanceOf(address)`                                               | The tokens an address holds on the reference chain, frozen tokens included                           |
| `getFrozenTokens(_userAddress)`                                    | The amount frozen at the address                                                                     |
| `freeBalanceOf(wallet)`                                            | `balanceOf` less the frozen amount: what the address can send                                        |
| `isFrozen(_userAddress)`                                           | Whether the address is frozen as a whole                                                             |
| `allowance(owner, spender)`, `nonces(owner)`, `DOMAIN_SEPARATOR()` | The ERC-20 and ERC-2612 reads                                                                        |
| `bridgedBalanceOf(wallet)`                                         | The position recorded for a satellite wallet (`bytes`)                                               |
| `reservedOf(wallet)`                                               | The part of that position promised to open validations                                               |
| `availableOf(wallet)`                                              | `bridgedBalanceOf` less `reservedOf`: what a new validation can draw on                              |
| `totalBridged()`                                                   | The sum of every bridged position, amounts in transit included                                       |
| `inTransitOf(validationId)`, `totalInTransit()`                    | The amount burned on one satellite and awaiting its mint on another, for one validation and in total |
| `totalSupply()`                                                    | The whole issuance: the supply of the reference chain plus `totalBridged()`                          |

### Cross-chain messaging

| Function                                                                                                                                                                                             | Access                                            | Reverts with                                                                                                                                                      |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setRoute(chainType, chainReference, gateway)`                                                                                                                                                       | `IDENTITY_MANAGER`                                | `GatewayNotTrusted` unless the gateway is trusted or zero, `InvalidChainReference`. Zero closes the chain. Emits `ChainRegistered` the first time, and `RouteSet` |
| `setPeer(chainKey, peer)`                                                                                                                                                                            | `IDENTITY_MANAGER`                                | `ChainNotRegistered`, `InvalidPeer`, `PeerChainMismatch`. Emits `PeerSet`                                                                                         |
| `dispatchMintInstruction(chainKey, body)`, `dispatchRecallInstruction(chainKey, body)`                                                                                                               | `AGENT`                                           | `ChainNotOpen`. Returns the `sendId`. Emits `ProtocolMessageSent`                                                                                                 |
| `dispatchComplianceValidation(chainKey, validationId, body)`                                                                                                                                         | The bound compliance                              | `SenderNotCompliance`, `ChainNotOpen`, `ValidationAlreadyRouted`. Emits `ValidationRoutePinned` and `ProtocolMessageSent`                                         |
| `receiveMessage(receiveId, sender, payload)`                                                                                                                                                         | A gateway trusted by the `TrustedGatewayRegistry` | The checks of a delivery, listed in [Build an ERC-7786 gateway adapter](/build/build-an-erc-7786-gateway-adapter.md)                                              |
| `trustedGatewayRegistry()`, `routeFor(chainKey)`, `chainOf(chainKey)`, `peerFor(chainKey)`, `pinnedRouteFor(validationId, chainKey)`, `isChainOpen(chainKey)`, `messageReceived(gateway, receiveId)` | Anyone, read                                      |                                                                                                                                                                   |

### Functions reserved to the compliance

The compliance drives the bridged side of the ledger while it issues and settles validations. Each function reverts with `OnlyBoundCompliance` for any other caller.

| Function                                              | Called when                                                                                                   | Reverts with                                                                                                                        |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `reserveForValidation(wallet, amount)`                | A validation is issued. Emits `ReservedForValidation`                                                         |                                                                                                                                     |
| `releaseFromValidation(wallet, amount)`               | A reservation is given back, for example when a validation is discarded. Emits `ReleasedFromValidation`       |                                                                                                                                     |
| `holdInTransit(from, amount, validationId, reserved)` | The burn of a transfer between two satellites is reported before its mint. Emits `HeldInTransit`              | `EnforcedPause`, `TransitAlreadyHeld`, `InsufficientBridgedBalance`                                                                 |
| `returnHeldInTransit(to, validationId)`               | A stuck validation is resolved. Emits `ReturnedInTransit`                                                     | `EnforcedPause`, `NothingInTransit`                                                                                                 |
| `settleValidation(from, to, amount, validationId)`    | A settlement is applied. Emits `BridgedTransfer`, or `SettledToNative` for a recipient on the reference chain | `EnforcedPause`, `InsufficientBridgedBalance`, `TransitAmountMismatch`, `UnverifiedIdentity` for a recipient on the reference chain |

The two reservation functions are not stopped by the pause: a reservation moves no token.

### Events

| Event                                                                                                                                                                                        | Emitted when                                                    |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `Transfer(address indexed from, address indexed to, uint256 value)`                                                                                                                          | A balance of the reference chain changes                        |
| `Approval(address indexed owner, address indexed spender, uint256 value)`                                                                                                                    | `approve`, `permit`                                             |
| `Paused(address account)`, `Unpaused(address account)`                                                                                                                                       | Halt, resume                                                    |
| `UpdatedTokenInformation(string _newName, string _newSymbol, uint8 _newDecimals, string _newVersion, address indexed _newOnchainID)`                                                         | Deployment, change of name, symbol or ONCHAINID                 |
| `IdentityRegistryAdded(address indexed _identityRegistry)`, `ComplianceAdded(address indexed _compliance)`                                                                                   | The two setters                                                 |
| `AddressFrozen(address indexed _userAddress, bool indexed _isFrozen, address indexed _owner)`                                                                                                | An address is frozen or unfrozen. `_owner` is the caller        |
| `TokensFrozen(address indexed _userAddress, uint256 _amount)`, `TokensUnfrozen(address indexed _userAddress, uint256 _amount)`                                                               | An amount is frozen, released                                   |
| `RecoverySuccess(address indexed _lostWallet, address indexed _newWallet, address indexed _investorOnchainID)`                                                                               | End of a recovery                                               |
| `ForcedTransfer(address indexed agent)`                                                                                                                                                      | After the `Transfer` of a forced transfer                       |
| `IdentityTransfer(address indexed identity, address indexed from, address indexed to, uint256 amount)`                                                                                       | After the `Transfer` of an `identityTransfer`                   |
| `ReservedForValidation(bytes32 indexed walletKey, bytes wallet, uint256 amount)`, `ReleasedFromValidation` (same arguments)                                                                  | A validation reserves part of a satellite wallet, gives it back |
| `HeldInTransit(bytes32 indexed fromKey, uint256 indexed validationId, bytes fromWallet, uint256 amount)`                                                                                     | A burn is reported before its mint                              |
| `ReturnedInTransit(bytes32 indexed walletKey, uint256 indexed validationId, bytes wallet, uint256 amount)`                                                                                   | A held amount returns to its wallet                             |
| `BridgedTransfer(bytes32 indexed fromKey, bytes32 indexed toKey, uint256 indexed validationId, bytes from, bytes to, uint256 amount)`                                                        | Settlement between two satellite wallets                        |
| `SettledToNative(bytes32 indexed fromKey, address indexed to, uint256 indexed validationId, bytes fromWallet, uint256 amount)`                                                               | Settlement to an address of the reference chain                 |
| `ChainRegistered(bytes32 indexed chainKey, bytes2 chainType, bytes chainReference)`                                                                                                          | First route or peer for a chain                                 |
| `RouteSet(bytes32 indexed chainKey, address indexed gateway)`, `PeerSet(bytes32 indexed chainKey, bytes peer)`                                                                               | The gateway, the peer, of a chain                               |
| `TrustedGatewayRegistrySet(address trustedGatewayRegistry)`                                                                                                                                  | Once, at deployment                                             |
| `ValidationRoutePinned(uint256 indexed validationId, bytes32 indexed chainKey, address gateway)`                                                                                             | First dispatch of a validation to a chain                       |
| `ProtocolMessageSent(MessageTypesLib.Message indexed messageType, bytes32 indexed chainKey, bytes32 sendId)`                                                                                 | A message leaves for a satellite                                |
| `ProtocolMessageReceived(MessageTypesLib.Message indexed messageType, bytes32 indexed chainKey, bytes32 receiveId)`                                                                          | A message from a satellite was processed                        |
| `BurnProofReceived(bytes32 indexed originChainKey, bytes burnedWallet, address indexed nativeWallet, uint256 amount)`                                                                        | A burn proof arrives                                            |
| `DelegatedOut(address indexed holder, bytes32 indexed toKey, bytes toWallet, uint256 amount)`, `Recalled(bytes32 indexed fromKey, address indexed holder, bytes fromWallet, uint256 amount)` | A position leaves for a satellite, returns from one             |


---

# 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/reference/token-suite/token.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.
