TokenManager is a per-token, per-domain contract that controls crosschain
transfers for a custom token registered on CCTP for non-USDC. Each domain where
your token is active has its own independent TokenManager, and three roles
govern it: the owner (highest privilege, can change all roles), the operator
(sets rate limits and transfer caps), and the pauser (can pause and unpause
the token on this domain). You need to manage these roles when rotating keys,
delegating operator duties to a separate address, or responding to a security
incident.
Prerequisites
Before you begin, ensure that you’ve:- Registered a custom token using
registerCustomTokenordeployCrossChainToken, and noted thetokenId. See Configure a custom token - Noted the
CrossChainTokenServiceaddress for each domain where you want to change roles. See Contract addresses - Verified access to the wallet that currently holds the role you want to
change: the owner wallet for ownership, operator, or pauser changes; the
pauser wallet to call
pauseorunpause
Steps
Step 1: Find the TokenManager address
Every token has a separateTokenManager per domain. Resolve its address from
the CrossChainTokenService before making any role change.
TypeScript
TokenManager is an independent contract with its own role state.
Step 2: Transfer ownership
Ownership transfer is a two-step operation. The current owner callstransferOwnership to initiate. The TokenManager enters a pending
state—ownership has not changed yet. The new owner must then call
acceptOwnership from their address to complete the transfer.
Both transactions require a private key. Keep keys out of version control—load
them from environment variables or a secrets manager.
Initiate the transfer (current owner):
TypeScript
TypeScript
TokenManager independently.
Step 3: Replace the operator
Unlike ownership, operator replacement is a single-step operation. The current owner callstransferOperatorship and the change takes effect immediately—no
acceptance step is required.
TypeScript
setRateLimit, setMaxTransferAmount, and
setRateLimitWindow on the TokenManager. For details on configuring those
values, see
Configure rate limits and caps.
Step 4: Replace the pauser
The pauser role defaults to the operator address at deployment time. If you never callupdatePauser, the operator is also the pauser. The current owner
can replace the pauser by calling updatePauser.
TypeScript
pause() to block all crosschain transfers of this token on
this domain, and unpause() to restore them. These calls affect only this token
on this domain—they are not protocol-wide.
TypeScript