Circle starts cutting CCTP V1 burn limits on 31 October 2026 and pauses the V1 contracts on 1 December. From then on, any integration still calling V1 stops moving USDC between chains. Some explainers that still rank give a July date, and one of the most complete third-party guides has the finality thresholds the wrong way round.
CCTP V2 is the replacement, and it changes more than contract addresses. Nonces are assigned off-chain, a transfer can settle before finality if you pay for it, and the burn message can carry hook data that CCTP never executes. On 27 October 2026 I pulled every route's fee from Circle's API and decoded three hours of live burns on Base. The numbers below come from that, followed by a comparison with USDT0, Chainlink CCIP and Wormhole NTT.
What Is CCTP V2 and How Is It Different From V1?
CCTP (Cross-Chain Transfer Protocol) burns native USDC on the source chain and mints it on the destination. There is no liquidity pool in the middle and no wrapped token at the end. Circle's attestation service, Iris, signs a message once the source chain reaches the finality you asked for, and the destination contract mints against that signature.
It is less a bridge than Circle's own mint authority behind an API. The only party you trust is the one you already trust by holding USDC.
| CCTP V1 | CCTP V2 | |
|---|---|---|
| Nonce | uint64, in the source-chain event | bytes32, assigned off-chain by Circle |
| Finality | Hard finality only | Confirmed (Fast) or finalised (Standard) |
| Protocol fee | None | Fast 0–13 bps, Standard free |
| Hooks | None | depositForBurnWithHook carries hookData |
| Expiry | None | Fast messages get an expirationBlock about 24h out |
| Status | Limits cut from 31 Oct 2026, paused 1 Dec 2026 | Current, about 30 domains |
The nonce change is the one that breaks indexers. On the source chain, V2 emits zeros where the nonce, finalityThresholdExecuted, feeExecuted and expirationBlock will go, and Circle fills them in when it signs. The V2 DepositForBurn event has no nonce at all. If your V1 reconciliation keyed transfers on a nonce read from the burn event, there is nothing left to key on. Key on source domain plus transaction hash, which is what the attestation API takes anyway, and store eventNonce once Iris returns it.
How Does a CCTP V2 Transfer Work?
It takes three steps:
1. Approve TokenMessengerV2 to spend your USDC, then call depositForBurn.
2. Poll Iris with the source domain and transaction hash until status is complete.
3. Call receiveMessage(message, attestation) on MessageTransmitterV2 on the destination chain.
On EVM chains, Circle's docs list TokenMessengerV2 at 0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d and MessageTransmitterV2 at 0x81D40F21F12A8F0E3252Bccb954D722d4c464B64. The burn function has seven parameters:
function depositForBurn(
uint256 amount,
uint32 destinationDomain,
bytes32 mintRecipient,
address burnToken,
bytes32 destinationCaller,
uint256 maxFee,
uint32 minFinalityThreshold
) external;
These are the parameters that cause trouble:
mintRecipientisbytes32. On EVM it is a 20-byte address left-padded with zeros. On Solana it is the recipient's USDC associated token account, not their wallet, and that account must exist before the mint orreceiveMessagefails.destinationCallerofbytes32(0)lets anyone submit the mint. Set it when you need the mint to go through your own contract (see hooks below).maxFeemust be strictly less thanamount, or the burn reverts.- There is a $10 million cap per burn. Above that, the transaction reverts.
@circle-fin/bridge-kit package (now part of Arc App Kit) wraps the burn, the polling and the mint.
CCTP Fast Transfer vs Standard Transfer: Which Should You Use?
minFinalityThreshold decides when Iris signs. At 1000 ("confirmed") it signs after a block or two. At 2000 ("finalised") it waits for hard finality. Values below 1000 are treated as 1000 and values above 1000 as 2000, so the only two real settings are Fast and Standard. Circle's figures:
| Source chain | Fast | Standard |
|---|---|---|
| Ethereum | ~20 seconds | 15–19 minutes |
| Base, OP, Arbitrum, Unichain, World Chain | ~8 seconds | 15–19 minutes |
| Solana | under 1 second | ~17 seconds |
| Starknet | ~20 seconds | 2–4 hours |
| Linea | ~8 seconds | 6–32 hours |
| Avalanche, Polygon PoS, Sonic | Not offered | ~8 seconds |
| Arc, Sui, Aptos | Not offered | ~0.5 seconds |
Chains whose Standard Transfer already takes seconds do not offer Fast as a source.
Fast is backed by a single global Fast Transfer Allowance. Each Fast burn debits it, and the amount is credited back once that burn reaches hard finality. If the pool hits zero, Fast stops for everyone until it refills. Circle's docs use 10 million USDC as an example. GET /v2/fastBurn/USDC/allowance returned 54,248,082 USDC at 08:11 UTC on 27 October.
What happens when you ask for Fast and can't have it? Circle's fees page contradicts itself. One paragraph says a maxFee below the Fast price reverts on the source chain, while a warning box on the same page says the transfer may be "degraded to Standard". The contract has no on-chain check of the Fast fee and the API's delayReason enum includes insufficient_fee, so the downgrade reading matches the code. The exception is chains with the newer on-chain minimum-fee switch (Circle lists only Sei), where a low maxFee reverts.
That matters for product copy. A transfer you sold as instant can turn into a 15-minute wait without any error.
How Much Does CCTP Cost in 2026?
Standard Transfers are free. Fast Transfers are charged in basis points and the fee is taken at mint, so the recipient gets amount - feeExecuted. These are the minimum Fast fees by source chain, from Circle's API on 27 October (they match its fees page), for destinations other than Arc:
| Source chain | Fast fee | On a $10,000 transfer |
|---|---|---|
| Ethereum, Solana | 1 bps | $1.00 |
| Base, OP, World Chain, X Layer | 1.3 bps | $1.30 |
| Arbitrum | 1.4 bps | $1.40 |
| Codex, EDGE | 1.5 bps | $1.50 |
| Unichain, Ink, Plume | 2 bps | $2.00 |
| Morph | 4 bps | $4.00 |
| Starknet | 12 bps | $12.00 |
| Linea | 13 bps | $13.00 |
Circle's docs price Fast by source chain only. The API also prices by destination. Into Arc, Circle's own chain, Fast costs a quarter of the usual rate: 0.25 bps from Ethereum and 0.325 bps from Base. That discount is not in the documentation, which is a good reason to call GET /v2/burn/USDC/fees/{source}/{destination} per route at quote time and never hard-code the table:
const res = await fetch("https://iris-api.circle.com/v2/burn/USDC/fees/6/3");
const fees: { finalityThreshold: number; minimumFee: number }[] = await res.json();
const fast = fees.find((f) => f.finalityThreshold === 1000)!; // minimumFee: 1.3 (bps)
// amount is in USDC base units (6 decimals); add 20% headroom
const maxFee = (amount BigInt(Math.round(fast.minimumFee 100)) * 12n) / 10_000_000n;
The 20% headroom is common practice. In my Base sample, the median Fast burn set maxFee at about 1.56 bps, which is 1.3 × 1.2.
Two optional extras cost more. With the Forwarding Service, Circle submits the destination mint for you, for destination gas plus a $0.05 service fee on most routes (more for HyperCore). With ?forward=true, the API's median quotes were $0.055 into Base, $0.074 into Arbitrum, $0.12 into Solana and $0.97 into Ethereum. Upfront fees, released in August 2026, let the sender pay on the source chain through depositForBurnWithFees, using a signed quote from POST /v2/quote/burn/usdc/{src}/{dst} that expires in about two minutes. That way the recipient receives the full amount.
How to Poll the CCTP Attestation API Without a 429
The endpoint is GET https://iris-api.circle.com/v2/messages/{sourceDomain}?transactionHash=0x…. Here is a trimmed response for a real Base-to-Arbitrum Standard transfer from this morning:
{
"messages": [{
"status": "complete",
"cctpVersion": 2,
"eventNonce": "0x3db81757cd04f69350ddfcababe1816e19571729a353ee20152da4719e12d870",
"attestation": "0x134df930…",
"message": "0x00000001000000060000000…",
"decodedMessage": {
"sourceDomain": "6",
"destinationDomain": "3",
"minFinalityThreshold": "2000",
"finalityThresholdExecuted": "2000",
"decodedMessageBody": {
"amount": "1169789962",
"maxFee": "0",
"feeExecuted": "0",
"expirationBlock": "0",
"hookData": null
}
},
"delayReason": null,
"destinationMintTxHash": "0xf584dd25…"
}],
"sourceTxHash": "0x1d662cf5…"
}
The rules that keep a poller healthy:
- A 404 means Iris has not indexed the burn yet. It does not mean the transfer failed. Keep polling.
- Stay well under the rate limit. Circle's technical guide says 40 requests per second and its troubleshooting page says 35. Both say that going over blocks all your requests for five minutes with HTTP 429. Run one poller, budget for 35 and back off exponentially. For a Standard burn from an Ethereum L2, polling before the 15-minute mark is wasted effort.
- Treat
delayReasonas an alert. Its values areinsufficient_fee,insufficient_allowance_availableandamount_above_max, and any of them means your Fast transfer is now waiting for finality. ComparingfinalityThresholdExecutedwithminFinalityThresholdtells you the same after the fact. - Watch
expirationBlock. Iris sets it about 24 hours ahead on Fast messages. Into Arbitrum, EDGE and Plume it is an Ethereum L1 block number, not a destination block. After that block,receiveMessagereverts with "Message expired and must be re-signed".POST /v2/reattest/{nonce}returns a fresh attestation, with no deadline as long as the burn transaction exists.
How Do CCTP V2 Hooks Work?
depositForBurnWithHook takes the same seven parameters plus bytes hookData, and reverts if hookData is empty. In Circle's words, "CCTP does not implement hook execution in the core protocol." The bytes ride along in the burn message, and whoever calls receiveMessage on the destination decides what to do with them.
So a hook is only as reliable as the contract that submits the mint. If you want a swap or a deposit to happen in the same transaction as the mint, deploy a wrapper that calls receiveMessage and then acts on hookData, and set destinationCaller to that wrapper. If you leave destinationCaller empty, anyone can relay the message through the plain MessageTransmitterV2. The USDC lands at mintRecipient, and your hook never runs.
Circle's Forwarding Service is itself a hook. Burns whose hookData starts with the ASCII bytes cctp-forward tell Circle to submit the mint. In my Base sample, 32 of 205 burns used it, 65 carried some kind of hook data, and 71 set a destinationCaller.
If you send your own payloads through MessageTransmitterV2's generic sendMessage, your receiver implements handleReceiveFinalizedMessage and handleReceiveUnfinalizedMessage, and decides for itself whether to act before finality.
When Does CCTP V1 Stop Working?
According to Circle's migration guide and its 27 August 2026 announcement:
- 31 October 2026: V1 burn limits start falling, and performance degrades over about a month.
- 1 December 2026: V1 contracts are paused. Pending V1 redemptions stay redeemable.
- Noble never got V2. Circle Mint stopped minting on Noble on 13 October 2026, its contract and CCTP routes pause on 12 January 2027, and manual redemption opens on 13 January 2027.
GET /v1/attestations/{messageHash} replaced by GET /v2/messages/{sourceDomainId}?transactionHash=.
CCTP vs USDT0 vs Chainlink CCIP vs Wormhole NTT
Each of these moves a different token, so the choice usually follows the stablecoin. What differs is who you trust to attest, and how a failure shows up.
| CCTP V2 | USDT0 (LayerZero OFT) | Chainlink CCIP | Wormhole NTT | |
|---|---|---|---|---|
| Moves | Native USDC | USDT0 | Any CCT token; native USDC routed via CCTP | The issuer's own token (USDS, RLUSD) |
| Model | Burn and mint | Lock on Ethereum, mint elsewhere; burn and mint between other chains | Burn/mint or lock/release pools | Burn and mint, or hub-and-spoke lock |
| Who attests | Circle (Iris) | 3 of 3 DVNs: LayerZero, USDT0, Canary | Verifier committee, with an emergency "curse" stop | 13 of 19 Guardians |
| Typical time | Seconds (Fast) or source finality | 30 seconds to 3 minutes | Source finality by default (~13–20 min on Ethereum and its L2s) | Depends on chain and configuration |
| Cost | Fast 0–13 bps; Standard free | LayerZero message fee in native gas; no protocol fee | $0.25–$1.50 network fee plus gas | Not documented in the sources I read |
| Limits | $10m per burn; global Fast allowance | No public cap in the docs I read | Token-bucket limits per lane | 24h rate limits with an optional queue |
The USDT0 row needs a caveat. An OFT's security depends on its DVN configuration, which is set per pathway, so "LayerZero" on its own tells you very little. USDT0 requires three independent verifiers. KelpDAO's route in April 2026 relied on a single one, and about $290m of rsETH went out through it. If you integrate any OFT, read its DVN config on-chain before you trust it.
Any OFT also floors amounts to its shared decimals (six by default) and refunds the remainder, so set minAmountLD from quoteOFT() rather than echoing the input amount. USDT0's Legacy Mesh, which reaches original USDT on Tron, TON and Solana, is a liquidity pool hub with a 0.03% fee, not burn-and-mint.
Bridged USDC.e is a separate token from native USDC. On Arbitrum and Polygon PoS both still exist side by side, and USDC.e has to be bridged back to Ethereum before it can be redeemed. Circle's Bridged USDC Standard allows an upgrade in place, which Linea, Sonic and World Chain have done, but only if the chain adopted the standard before deployment. If you accept stablecoin deposits, check the contract address, not the ticker. I covered the matching side of that in USDC payment matching.
Is CCTP Fast Transfer Worth Paying For?
Here is what integrators actually do. Between 05:13 and 08:12 UTC on 27 October, Base sent 205 CCTP V2 burns. 136 of them (66%) asked for Fast, but they carried only $186k of the $1.01m total, or 18.5%. The median Fast burn was $88 and the median Standard burn $347. Of the 17 burns above $10,000, 13 went Standard.
That split looks right to me, and this is opinion. The fee is not the issue: 1.3 bps on $10,000 is $1.30. Fast's real costs are the shared allowance, which other people's traffic can drain, and the silent downgrade, which turns an SLA into a best effort. Use Fast for user-facing transfers of a few thousand dollars or less, and show the Standard path in the UI when delayReason appears. Move treasury on a schedule with Standard. If you rebalance the same chains several times a day, look at Circle Gateway instead: once deposits finalise, it mints from a unified balance in under 500ms for 0.5 bps plus a per-source gas fee ($0.01 from Base or Arbitrum, $1.00 from Ethereum), but trustless withdrawal waits seven days.
My prediction is that undocumented destination pricing like the Arc discount becomes normal. Circle has every reason to pull volume onto Arc, the chain it launched in September, and CCTP fees are the cheapest lever it has, so expect them to keep moving per route without a docs update. Code that reads a fee table from a config file will overpay or get downgraded, and nobody will notice until someone complains.
What This Means for Payment Engineers in the UK and EU
1. Find V1 before 31 October. Search for five-parameter depositForBurn calls, replaceDepositForBurn, /v1/attestations and anything that reads a uint64 nonce. Anything on Noble needs a plan before 12 January 2027.
2. Key transfers on (sourceDomain, txHash). Store eventNonce, feeExecuted and finalityThresholdExecuted once attested, because they are what your ledger and fee reconciliation need.
3. Quote per route, every time. Fetch the fee, add 20%, and check the allowance before promising a large Fast transfer.
4. Make the poller boring. Use one worker, treat 404 as pending, back off on 429, and alert on delayReason and on messages nearing expirationBlock.
5. Set destinationCaller whenever a hook matters.
6. Choose the stablecoin before the rail, especially in the EU. ESMA's opinion of 8 October 2026 tells crypto-asset service providers not to serve non-MiCA-compliant e-money tokens, and gives them three months, to around 8 January 2027, to unwind legacy exposure. For an EU CASP that rules out USDT, whatever the bridge quality, so check the ESMA register before assuming USDT0 is any different. I found no ESMA or EBA guidance on whether bridged or wrapped copies count as the same e-money token. In the UK, the FCA's stablecoin regime under PS26/10 applies from 25 October 2027, and until then UK firms are choosing under rules that will change. My OCC GENIUS Act piece compares the UK and US redemption rules.
CCTP looks like a single function call. In production it's a state machine with a shared allowance, an expiry clock and a fee model that changes per route. Build for those states before the V1 cutoff forces the migration. More notes from the payments stack by Tom Wang.