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 and The balance model.
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
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
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 and 24 Transfer through the identity.
Agent functions
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, 09, 13, 14, 15, 16.
Balance views
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
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
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.
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
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
Last updated