CCIP v2.0.0 TokenPool API Reference

Summary

TokenPool is the abstract base contract for all CCIP EVM token pool implementations.

It centralizes:

  • Router-based ramp gating
  • RMN curse enforcement
  • Remote chain and remote pool validation
  • Rate limiting
  • Optional advanced hooks
  • Optional pool-level fee overrides
  • Decimal normalization logic

Concrete pool variants implement token custody semantics.


Contract

chains/evm/contracts/pools/TokenPool.sol


Import

import {TokenPool} from "chainlink-ccip/chains/evm/contracts/pools/TokenPool.sol";

Inheritance

abstract contract TokenPool
  is IPoolV1V2,
     Ownable2StepMsgSender,
     IERC165

Implements:

  • IPoolV1
  • IPoolV2

Purpose in system

TokenPool defines the canonical CCIP token flow:

  • Source chain → lockOrBurn
  • Destination chain → releaseOrMint

It guarantees:

  • Only authorized OnRamp may initiate outbound transfers.
  • Only authorized OffRamp may finalize inbound transfers.
  • RMN curse state halts operations.
  • Per-chain rate limits are enforced.
  • Remote pool addresses are allowlisted.
  • Optional hooks may extend validation.

Concrete pools implement:

  • _lockOrBurn
  • _releaseOrMint

State

Immutables

IERC20 internal immutable i_token;
uint8 internal immutable i_tokenDecimals;
IRMNRemote internal immutable i_rmnProxy;

Storage (selected)

IRouter internal s_router;

mapping(uint64 => ChainConfig) internal s_chainConfigs;

IAdvancedPoolHooks internal s_advancedPoolHooks;

address internal s_rateLimitAdmin;
address internal s_feeAdmin;

Additional mappings store:

  • Remote pools per chain
  • Rate limiter buckets
  • Token transfer fee overrides

Extension points

Concrete pools must override:

function _lockOrBurn(
  uint64 remoteChainSelector,
  uint256 amount
) internal virtual;

function _releaseOrMint(
  address receiver,
  uint256 amount,
  uint64 remoteChainSelector
) internal virtual;

These define custody logic:

  • Burn/mint
  • Lock/release
  • Bridge delegation (Lombard, CCTP, etc.)

Key internal flow / invariants

Outbound: lockOrBurn

  1. _validateLockOrBurn(...)
  2. Deduct pool-level fee (if configured)
  3. Enforce rate limits
  4. Call _lockOrBurn
  5. Emit LockedOrBurned

Inbound: releaseOrMint

  1. _validateReleaseOrMint(...)
  2. Convert remote amount to local decimals
  3. Enforce rate limits
  4. Call _releaseOrMint
  5. Emit ReleasedOrMinted

Validation guarantees

Outbound:

  • Caller must equal router.getOnRamp(remoteChainSelector)
  • Chain must be supported
  • RMN not cursed
  • Token supported
  • Hooks (if configured) must pass

Inbound:

  • Caller must equal router.isOffRamp(...)
  • Source pool must be allowlisted
  • RMN not cursed
  • Chain supported
  • Hooks (if configured) must pass

Decimal normalization

Functions:

function _encodeLocalDecimals() internal view returns (bytes memory);

function _parseRemoteDecimals(bytes memory sourcePoolData)
  internal
  view
  returns (uint8);

function _calculateLocalAmount(
  uint256 remoteAmount,
  uint8 remoteDecimals
)
  internal
  view
  returns (uint256);
  • Rounds down when remoteDecimals > localDecimals.
  • Ensures consistent cross-chain denomination.

Rate limiting

Separate buckets for:

  • Default finality
  • Custom block confirmations

Uses RateLimiter library.


Fee overrides

Optional pool-level fee configuration:

  • applyTokenTransferFeeConfigUpdates
  • getFee

Fee capped by:

uint16 internal constant BPS_DIVIDER = 10_000;

Events (selected)

event LockedOrBurned(
  uint64 indexed remoteChainSelector,
  address indexed sender,
  uint256 amount
);

event ReleasedOrMinted(
  uint64 indexed remoteChainSelector,
  address indexed receiver,
  uint256 amount
);

event ChainAdded(uint64 remoteChainSelector);
event ChainRemoved(uint64 remoteChainSelector);
event RemotePoolAdded(uint64 remoteChainSelector, bytes remotePoolAddress);
event RemotePoolRemoved(uint64 remoteChainSelector, bytes remotePoolAddress);

Additional events exist for:

  • Rate limit consumption
  • Fee configuration updates

Security model

  • Router is the only ingress/egress authority.
  • RMN curse halts flows.
  • Remote pools strictly allowlisted.
  • Rate limiting prevents draining.
  • Fee logic isolated from custody logic.
  • Hooks cannot bypass base validation.

Get the latest Chainlink content straight to your inbox.