TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/circlefin/evm-cctp-contracts/llms.txt
Use this file to discover all available pages before exploring further.
TokenController contract provides token configuration management for CCTP, including mapping local tokens to remote tokens across domains and setting per-message burn limits.
Contract: src/roles/TokenController.sol
Key Concepts
- Token Pairs: Links between local tokens and their corresponding remote domain tokens
- Burn Limits: Maximum amount of each token that can be burned per message
- Token Controller Role: Authorized address that manages token configuration
State Variables
burnLimitsPerMessage
Value: Maximum burn amount per message (in token’s smallest unit) Usage: A burn limit of 0 means the token is not supported for burning.
remoteTokensToLocalTokens
keccak256(abi.encodePacked(remoteDomain, remoteToken))Value: Local token address Usage: Enables validation and minting when receiving messages from remote domains.
_tokenController
Functions
linkTokenPair
localToken: Address of the local tokenremoteDomain: Domain ID of the remote chainremoteToken: Address of the token on the remote domain (as bytes32)
- Caller must be the token controller
- Remote token must not already be linked to a local token
TokenPairLinked(address localToken, uint32 remoteDomain, bytes32 remoteToken)
Source: TokenController.sol:126
Note:
- A remote token can only map to one local token
- Multiple remote tokens can map to the same local token
- Linking does not enable deposits (must also call
setMaxBurnAmountPerMessage)
unlinkTokenPair
localToken: Address of the local tokenremoteDomain: Domain ID of the remote chainremoteToken: Address of the token on the remote domain (as bytes32)
- Caller must be the token controller
- Token pair must currently be linked
TokenPairUnlinked(address localToken, uint32 remoteDomain, bytes32 remoteToken)
Source: TokenController.sol:157
Note: Unlinking does not disable burning the local token (must separately call setMaxBurnAmountPerMessage with 0)
setMaxBurnAmountPerMessage
localToken: Address of the local tokenburnLimitPerMessage: Maximum burn amount per message (0 to disable burning)
- Caller must be the token controller
SetBurnLimitPerMessage(address indexed token, uint256 burnLimitPerMessage)
Source: TokenController.sol:186
Important:
- Burns exceeding this limit will revert
- Mints do not respect this limit
- Reducing the limit does not affect previously burned tokens (they can still be minted)
- Setting to 0 disables burning for that token
tokenController
Internal Functions
_setTokenController
newTokenController: Address of the new token controller
- New token controller must be non-zero address
SetTokenController(address tokenController)
Source: TokenController.sol:202
_getLocalToken
remoteDomain: Domain ID of the remote chainremoteToken: Address of the token on the remote domain (as bytes32)
_hashRemoteDomainAndToken
remoteDomain: Domain ID of the remote chainremoteToken: Address of the token on the remote domain (as bytes32)
Modifiers
onlyTokenController
onlyWithinBurnLimit
token: Address of the token to burnamount: Amount to burn
- “Burn token not supported” if burn limit is 0
- “Burn amount exceeds per tx limit” if amount exceeds limit
Events
TokenPairLinked
localToken: Local token addressremoteDomain: Remote domain IDremoteToken: Remote token address as bytes32
TokenPairUnlinked
SetBurnLimitPerMessage
token: Local token addressburnLimitPerMessage: New burn limit per message
SetTokenController
tokenController: New token controller address
Usage Examples
Setting Up a New Token
Updating Configuration
Checking Configuration
Security Considerations
- Token controller should be a trusted address (e.g., multisig or DAO)
- Burn limits should be set based on liquidity and risk assessment
- A token pair can only be linked once (prevents conflicting mappings)
- Minting is not limited by burn limits (asymmetric by design)
- Setting burn limit to 0 effectively disables deposits for that token
- Unlinking a token pair does not automatically disable burning
- Remote tokens are stored as bytes32 to support non-EVM chains
- Multiple remote tokens can map to the same local token (useful for wrapped tokens)
Integration with TokenMinter
TheTokenMinter contract inherits from TokenController and uses these functions in:
- depositForBurn(): Checks burn limit via
onlyWithinBurnLimitmodifier - handleReceiveMessage(): Uses
_getLocalToken()to determine which token to mint - Administrative setup: Owner uses inherited functions to configure supported tokens
Remote Token Address Format
Remote tokens are represented asbytes32 to support both EVM and non-EVM chains: