Skip to main content
A 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 registerCustomToken or deployCrossChainToken, and noted the tokenId. See Configure a custom token
  • Noted the CrossChainTokenService address 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 pause or unpause

Steps

1

Discover the TokenManager address

Every token has a separate TokenManager per domain. Resolve its address from the CrossChainTokenService before making any role change.
TypeScript
Role changes apply only to the local TokenManager. Repeat the operation independently on each domain where the token is deployed.
2

Initiate ownership transfer

The current owner calls transferOwnership to initiate. The TokenManager enters a pending state—ownership has not changed yet. Ownership remains with the current owner until the new owner accepts by calling acceptOwnership from their address.
Transferring ownership to an address you do not control is irreversible. If the new owner never calls acceptOwnership, the current owner retains control—but there is no cancel mechanism, and the pending transfer remains indefinitely. Verify the new address carefully before sending the transaction.
TypeScript
3

Accept ownership

The pending owner calls acceptOwnership. Ownership changes after this transaction confirms.
TypeScript
4

Replace the operator

Unlike ownership, operator replacement is a single-step operation. The current owner calls transferOperatorship and the change takes effect immediately. No additional acceptance step is required.
TypeScript
The operator can call setRateLimit, setMaxTransferAmount, and setRateLimitWindow on the TokenManager. For details on configuring those values, see Configure rate limits and caps.
5

Replace the pauser

The pauser role defaults to the operator address at deployment time. If you never call updatePauser, the operator is also the pauser. The current owner can replace the pauser by calling updatePauser.
TypeScript
6

Pause and unpause the token

The pauser can call pause() to block all crosschain transfers of this token on this domain, and unpause() to restore them.
TypeScript
7

Verify the final state

After all transactions confirm, verify that owner() returns the new owner, operator() returns the new operator, pauser() returns the new pauser, and paused() returns false after unpause().
TypeScript