> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# CCTP for non-USDC contract reference

> CCTP for non-USDC contracts, types, errors, and non-obvious behaviors integrators need.

The following tables index contracts, types, errors, and sentinels, and document
behaviors that aren't obvious from reading the source.

For contract addresses, see
[Contract Addresses](/cctp/expanded-assets/references/contract-addresses).

## Contracts

| Contract | Purpose |
| - | - |
| `CrossChainTokenService` | Singleton entry point on each domain. Configures tokens, deploys remote token contracts, and routes crosschain transfers. |
| `TokenManager` | Deployed per token on each domain. Moves tokens during transfers; enforces rate limit, max transfer amount, and pause. |
| `CrossChainToken` | ERC-20 with `ERC20Permit` deployed for natively crosschain tokens. Holders call `crossChainTransfer` directly. |
| `CrossChainTokenExecutable` | Optional abstract helper for destination-domain hook receivers. Integrators can implement `executeWithCrossChainToken` directly. |
| `IDenylistProvider` | Interface for service-level and per-token denylist providers. One view: `isDenylisted(address)`. |

## Types

### `QuoteClaim`

Passed to every payable entrypoint to attach a signed fee quote and a refund
address.

```solidity Solidity theme={null}
struct QuoteClaim {
    bytes signedQuote;
    address payable refundAddress;
}
```

* `signedQuote`: version-prefixed, ABI-encoded fee quote returned by the Iris
  fee-quote endpoint
  (`POST /v2/quote/cctpx/{tokenId}/{sourceDomain}/{destinationDomain}`). Pass
  the bytes value verbatim.
* `refundAddress`: receives fee refunds. Set to `address(0)` to opt out of
  refund attribution. Non-zero values are screened against the USDC denylist on
  collection; the call reverts if denied.

### `DeploymentParams`

Passed when configuring or deploying a token.

```solidity Solidity theme={null}
struct DeploymentParams {
    TokenManagerType tokenManagerType;
    bytes tokenManagerOwner;
    bytes tokenManagerOperator;
    bytes tokenOwner;
    bytes tokenMinter;
    uint256 initialSupply;
    TokenManagerSettings tokenManagerSettings;
}

struct TokenManagerSettings {
    uint256 rateLimit;
    uint256 maxTransferAmount;
}
```

Address fields are `bytes` rather than `address` so the struct can carry non-EVM
addresses for non-EVM domains.

Some deployments omit `initialSupply` from the onchain ABI (for example current
sandbox `registerCustomToken`). Encoding a field the contract does not expect
produces an empty revert. Always verify the live ABI or function selector before
copying struct layouts from docs.

### `TokenManagerType`

```solidity Solidity theme={null}
enum TokenManagerType {
    NATIVE_CROSSCHAIN_TOKEN,  // 0
    BURN_MINT,                // 1
    LOCK_UNLOCK               // 2
}
```

See
[Token manager types](/cctp/expanded-assets/concepts/architecture#token-manager-types)
for when each applies.

### `ConnectionType`

```solidity Solidity theme={null}
enum ConnectionType {
    OWNERLESS,
    CUSTOM
}
```

Distinguishes the two integration models. See
[Ownerless and custom tokens](/cctp/expanded-assets/concepts/ownerless-vs-custom-tokens).

## Errors

Integrators should monitor for these reverts:

| Error | Source | Meaning |
| - | - | - |
| `TokenNotRegistered(bytes32 tokenId)` | `CrossChainTokenService` | `resolveTokenManager` or `resolveTokenAddress` called with a `tokenId` that has no deployment. |
| `HookDataExecutionFailed(bytes32 tokenId, address recipient, bytes reason)` | `CrossChainTokenService` | Recipient's hook reverted, or returned a value other than the `EXECUTE_SUCCESS` sentinel. |
| `DenylistedAddress(address account)` | `CrossChainTokenService` | Service-level denylist rejected `msg.sender`, `tx.origin`, or the inbound recipient. |
| `AccountDenylisted(address account)` | `CrossChainToken` | Per-token denylist rejected `from`, `to`, or the spender on an ERC-20 movement. |

## Sentinels

### `EXECUTE_SUCCESS`

```solidity Solidity theme={null}
bytes32 constant EXECUTE_SUCCESS = keccak256("circle-cctpx-execute-success");
```

The value that `executeWithCrossChainToken` must return. The service verifies
this on every hook call. Implement the public entrypoint on your receiver,
restrict `msg.sender` to the local `CrossChainTokenService`, and return this
sentinel. See
[Build a hook receiver](/cctp/expanded-assets/howtos/build-hook-receiver).

When the contracts are open-sourced, an optional `CrossChainTokenExecutable`
base can wrap the same pattern (external entrypoint returns the sentinel;
subclasses override an internal hook). Until then, implement the write ABI
directly.

## Non-obvious behaviors

These behaviors aren't apparent from reading the source but commonly trip up
integrators.

### `approve` goes to the `TokenManager`, not the service

For `BURN_MINT` and `LOCK_UNLOCK` transfers, the source token is moved by the
per-token `TokenManager`. ERC-20 approvals must target the `TokenManager`
address (returned by `resolveTokenManager(tokenId)`), not the
`CrossChainTokenService`.

### `destinationAddress` is packed address bytes, not ABI-encoded

`crossChainTransfer` takes `destinationAddress` as `bytes`. On EVM, pass the raw
20-byte address (`abi.encodePacked(recipient)` /
`encodePacked(["address"], [recipient])`). Do **not** use `abi.encode` /
`encodeAbiParameters([{ type: "address" }], …)`, which produces a 32-byte
left-padded word and breaks destination delivery. This is separate from
application `hookData`, which may still be ABI-encoded.

### Custom `tokenId` uses `customTokenDeploySalt`

For custom tokens, the `tokenId` is
`crossChainTokenId(deployer, customTokenDeploySalt(deployer, salt))`. Calling
`crossChainTokenId(deployer, salt)` alone yields a different id. Native
crosschain tokens use `crossChainTokenId(deployer, salt)` directly.

### `resolveTokenManager` and `resolveTokenAddress` revert on miss

Both revert with `TokenNotRegistered(tokenId)` when the predicted address has no
deployed code. They do not return `address(0)`. To probe for existence without
throwing, wrap the call in `try`/`catch` or check `extcodesize` on the
deterministic CREATE3-predicted address.

### `CrossChainToken` denylist provider replaces, it does not chain

`CrossChainToken` holds a single denylist provider slot. Calling
`updateDenylistProvider` overwrites the previous value rather than adding to it.
To combine multiple lists, deploy a composite provider that internally calls
each upstream. The service-level denylist still runs in addition to the
per-token layer.

### Ownerless deploys inherit Circle's denylist provider

When `deployRemoteOwnerlessToken` lands on a remote domain, the new
`CrossChainToken`'s `denylistProvider` is initialized to the service's provider.

### `tokenManagerOwner`, `tokenManagerOperator`, and related fields are `bytes`

The fields are typed `bytes` instead of `address` so the same struct works for
non-EVM domains in the future. On EVM, pack the address with
`abi.encodePacked(addr)` / `encodePacked(["address"], [addr])` (20 bytes). Do
not use `encodeAbiParameters([{ type: "address" }], [addr])`, which ABI-pads to
32 bytes and is not equivalent.

For an **existing** ERC-20 configured with `registerCustomToken`, pass empty
bytes (`0x`) for `tokenOwner` and `tokenMinter`; grant the `TokenManager` minter
role on the token in a separate step.

### `sourceAddress` in hook callbacks is `bytes`

Same reason as the deployment params: the hook signature carries the source
address as `bytes` so receivers can decode senders from non-EVM blockchains.

### Hook execution can be reorged on fast transfers

When a hook executes with `finalityThresholdExecuted < 2000`, the source
blockchain transaction is still pre-finality and could be reorged. Receivers
that opt into fast hook execution must design their logic to tolerate rollback
by deferring irreversible side-effects until finality is confirmed.

## Function index

### `CrossChainTokenService`

| Group | Functions |
| - | - |
| Crosschain transfer | `crossChainTransfer`, `transmitCrossChainTransfer` |
| Resolve and inspect | `resolveTokenManager`, `resolveTokenAddress`, `getOwnerlessTokenId`, `crossChainTokenId`, `customTokenDeploySalt`, `ownerlessTokenDeploySalt`, `isTrustedDomain` |
| Trust and limits | `addTrustedDomain`, `removeTrustedDomain`, `setRateLimits` |
| Denylist | `denylistProvider`, `setDenylistProvider`, `initializeDenylistProvider` |
| Roles and upgrade | `feeService`, `messageTransmitter`, `operator`, `transferOwnership`, `acceptOwnership`, `pause`, `unpause`, `upgradeToAndCall` |

### `TokenManager`

| Group | Functions |
| - | - |
| Transfer limits | `setRateLimit`, `setMaxTransferAmount`, `setRateLimitWindow` |
| Pause | `pause`, `unpause`, `updatePauser` |
| Implementation | `upgradeToCustomImplementation`, `resetToDefaultImplementation` |
| Ownership | `transferOwnership`, `acceptOwnership`, `transferOperatorship` |
| Circle assignment | `assignOwnership`, `assignOperatorship` (only callable on ownerless `TokenManager`s) |
| Service-only | `takeToken`, `giveToken` (called by `CrossChainTokenService`; not callable by integrators) |

### `CrossChainToken`

| Group | Functions |
| - | - |
| Crosschain | `crossChainTransfer`, `crossChainTransferFrom` |
| Mint and burn | `mint`, `burn`, `burnFrom`, `addMinter`, `removeMinter`, `transferMintership` |
| Denylist | `denylistProvider`, `isDenylisted`, `updateDenylistProvider` |
| Implementation | `upgradeToCustomImplementation`, `resetToDefaultImplementation` |
| Ownership | `transferOwnership`, `acceptOwnership` |
| Circle assignment | `assignOwnership`, `assignOperatorship` (only callable on ownerless `CrossChainToken`s) |
| ERC-20 surface | Standard ERC-20 (`transfer`, `transferFrom`, `approve`, `allowance`, `balanceOf`, `totalSupply`) plus `ERC20Permit` |

### `CrossChainTokenExecutable`

Optional helper (when published). Integrators may instead implement the public
entrypoint directly.

| Group | Functions |
| - | - |
| Hook entry point | `executeWithCrossChainToken` (returns `EXECUTE_SUCCESS`) |
| Hook implementation | `_executeWithCrossChainToken` (override when using the abstract base) |
