For the complete documentation index, see llms.txt. This page is also available as Markdown.

The permissioned token

A T-REX token is, at its interface, an ERC-20 token: it has a name, a symbol, a supply and the standard transfer functions, so wallets, venues and tooling work with it without special knowledge. What distinguishes it is that its transfers are conditional. A position moves only if the recipient is eligible to hold the asset and the movement complies with the asset's rules. The token does not detect a bad transfer and unwind it. It declines to record one.

This page describes the Token contract on the reference chain: its surface, what it is wired to, its operations, and the rules that govern its configuration.

What the token is wired to

Link
Read with
What it is

Eligibility registry

identityRegistry()

The TREXRegistry the token asks whether a recipient may hold the asset.

Compliance

compliance()

The ModularCompliance the token asks whether a movement is allowed, and tells when one has happened.

Token identity

onchainID()

The ONCHAINID of the token, of type ASSET.

Authority

authority(), owner()

The TREXAccessManager that holds the roles. owner() returns the same address, for tooling that expects an owner.

Trusted gateway registry

trustedGatewayRegistry()

The network's list of vetted cross-chain gateways. It is set at deployment and cannot be changed afterward by any role.

The ERC-20 surface

Function
Behavior

name, symbol

Set at deployment. Changeable by the TOKEN_MANAGER role. Neither can be empty.

decimals

Set at deployment, between 0 and 18. Fixed afterward.

totalSupply

The whole issuance, including positions active on satellite chains.

balanceOf

What an address holds on the reference chain: free plus frozen.

transfer, transferFrom

Conditional. See below.

approve, allowance

Standard.

permit

ERC-2612: an approval given by signature.

batchTransfer

Several transfers from the caller in one transaction. Each one passes the same checks.

A conditional transfer

transfer(to, amount) runs these checks in order, and reverts at the first that fails.

  1. The token is not paused.

  2. Neither the sender's address nor the recipient's address is frozen.

  3. The sender's free balance covers the amount.

  4. The recipient is verified by the eligibility registry.

  5. The compliance allows the movement.

Then the balances move and the compliance is told, so that it updates the positions of both identities.

transferFrom adds one check before the allowance is spent: the compliance is asked whether the caller, as spender, may execute this transfer.

What each gate verifies is described in Eligibility and compliance: the two gates.

Operations

By holders

Function
What it does

transfer, batchTransfer

Moves tokens the caller holds.

approve, permit

Authorizes a spender.

transferFrom

A spender moves tokens within its allowance.

identityTransfer(from, to, amount)

An identity moves tokens held in a wallet linked to it. The caller must be the identity the from wallet resolves to. No allowance is involved.

No role is needed. An ONCHAINID that holds tokens itself uses transfer like any holder.

By agents

Agent operations are the servicing operations of the register. Each is gated by its own role.

Function
Role
What it does

mint(to, amount)

AGENT_MINTER

Creates tokens for an eligible recipient, within the rules. Issuance.

burn(from, amount)

AGENT_BURNER

Destroys tokens held by an address. Redemption. Frozen tokens are released as needed.

freezePartialTokens(address, amount), unfreezePartialTokens

AGENT_PARTIAL_FREEZER

Immobilizes, or releases, part of what an address holds.

setAddressFrozen(address, frozen)

AGENT_ADDRESS_FREEZER

Blocks, or unblocks, an address entirely: it neither sends nor receives.

forcedTransfer(from, to, amount)

AGENT_FORCED_TRANSFER

Moves tokens without the holder, to an eligible recipient. Overrides freezes.

recoveryAddress(lostWallet, newWallet, identity)

AGENT_RECOVERY_ADDRESS

Moves the whole balance of a lost wallet, with its freezes, to a new wallet of the same identity.

pause, unpause

AGENT_PAUSER

Halts, or resumes, every movement between holders.

Every function except recoveryAddress, pause and unpause has a batch variant, gated by the same role.

Configuration

Function
Role
Rule

setName, setSymbol

TOKEN_MANAGER

Not empty. Changing the name invalidates permit signatures that have not been used yet.

setOnchainID

IDENTITY_MANAGER

Sets the identity of the token.

setIdentityRegistry

IDENTITY_MANAGER

Only while the token has no supply.

setCompliance

IDENTITY_MANAGER

Only while the token has no supply.

setRoute, setPeer

IDENTITY_MANAGER

Opens the asset on a satellite chain.

Roles are described in Actors and roles.

Two kinds of freeze

Freezing an address
Freezing an amount

Effect

The address cannot send and cannot receive.

The amount cannot be sent. The rest of the balance moves normally, and the address still receives.

Read with

isFrozen(address)

getFrozenTokens(address)

Limit

The frozen amount never exceeds the balance.

Frozen tokens are still owned by their holder and still counted in balanceOf and in the identity's position. A burn, a forced transfer or a recovery releases exactly the frozen amount it needs, so an agent never has to unfreeze before acting.

The pause

A paused token records no movement between holders: no transfer, no forced transfer, no recovery, no settlement of a transfer executed on a satellite. Mints and burns remain possible.

  • A token is deployed paused. The Issuer configures it, mints the initial positions if it wants to, and lifts the pause when the asset opens.

  • The pause is also the incident halt. Because it stops agent movements too, an incident under investigation settles nothing. If the cross-chain layer delivers something the register cannot account for, the token pauses itself.

The registry and the compliance follow the token

Once a token has supply, its eligibility registry and its compliance cannot be replaced. Both setters revert.

  • The compliance has counted every movement since the first mint. It holds the position of every identity. A new compliance would start every holder at zero, and every rule that reads positions would be wrong from the first transfer.

  • The registry attributes every position. A registry that resolved addresses differently would leave positions under identities that no address resolves to.

A circulating token changes through what it has: its compliance is upgraded in place or reconfigured through its modules, and its registry is reconfigured through its topics, its trusted issuers and its registrations.

Before the first mint, a replacement must implement the expected interface, be governed by the same AccessManager as the token, and, for a compliance, not be bound to another token.

Supply and decimals

totalSupply counts the whole issuance of the asset, wherever it is active. It changes on a mint or a burn and on nothing else. Moving a position to a satellite chain or back does not change it. The part that sits on the reference chain is totalSupply() - totalBridged(). The balance model is described under The balance model.

Events

The token emits the ERC-20 and ERC-3643 events: Transfer, Approval, Paused, Unpaused, AddressFrozen, TokensFrozen, TokensUnfrozen, RecoverySuccess, UpdatedTokenInformation, IdentityRegistryAdded, ComplianceAdded.

Two T-REX events let an indexer tell a holder's transfer from the other kinds:

Event

Follows the Transfer of

ForcedTransfer(agent)

Every forced transfer, naming the agent that executed it.

IdentityTransfer(identity, from, to, amount)

Every transfer ordered by an identity from one of its wallets.

Last updated