ICCTPBridgeAdapter
Title: ICCTPBridgeAdapter
Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from Circle CCTP v2 (https://github.com/circlefin/evm-cctp-contracts)
Admin / read / action surface of the Circle CCTP v2 USDC token-bridge adapter. CCTP is a BURN-AND- MINT token bridge (USDC is burned on the source chain and minted on the destination via an off-chain Iris attestation), NOT an ERC-7786 message gateway — it is deliberately not wrapped as a gateway source and is never routed through the OpenBridge / CrosschainLink messaging stack.
The CCTP domain table (Eth 0, Avax 1, OP 2, Arb 3, Base 6, …) is NOT hardcoded — it is admin-registered
per chainId, and the per-domain fee / finality / destinationCaller config is likewise admin-managed.
Outbound recipients are ERC-7930 interoperable addresses; the destination address is down-converted to
a bytes32 mintRecipient (so both 20-byte EVM and 32-byte non-EVM recipients are supported).
Functions
tokenMessenger
The CCTP v2 TokenMessengerV2 this adapter burns through.
function tokenMessenger() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
messageTransmitter
The CCTP v2 MessageTransmitterV2 this adapter relays inbound messages to.
function messageTransmitter() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
usdc
The bridged USDC token (burn source of funds is msg.sender, not the Diamond balance).
function usdc() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
getDomain
The CCTP domain registered for chainId (meaningless unless isChainRegistered is true).
function getDomain(uint256 chainId) external view returns (uint32);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint32 |
isChainRegistered
Whether chainId has a registered CCTP domain (distinguishes domain 0 = Ethereum from unset).
function isChainRegistered(uint256 chainId) external view returns (bool);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bool |
domainOwner
The chainId that registered domain (0 = unregistered).
function domainOwner(uint32 domain) external view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
getDomainConfig
The per-domain config used when burning toward domain.
function getDomainConfig(uint32 domain)
external
view
returns (uint256 maxFee, uint32 minFinalityThreshold, bytes32 destinationCaller);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 |
Returns
| Name | Type | Description |
|---|---|---|
| maxFee | uint256 | |
| minFinalityThreshold | uint32 | |
| destinationCaller | bytes32 |
hookExecutor
The role-less, fund-less CCTPHookExecutor this diamond routes inbound hooks through (deployed once at init, immutable — no setter). Never the zero address on an initialized adapter.
function hookExecutor() external view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
registerChainDomain
Registers chainId ⇒ CCTP domain. Admin only. Verify the domain table at deploy.
function registerChainDomain(uint256 chainId, uint32 domain) external;Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| domain | uint32 |
configureDomain
Sets the per-domain maxFee, minFinalityThreshold and destinationCaller. Admin only.
function configureDomain(uint32 domain, uint256 maxFee, uint32 minFinalityThreshold, bytes32 destinationCaller)
external;Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 | |
| maxFee | uint256 | |
| minFinalityThreshold | uint32 | |
| destinationCaller | bytes32 |
depositForBurn
Burns amount USDC (pulled from msg.sender) for minting to the ERC-7930 recipient on its
destination chain via CCTP. Approves the TokenMessenger for EXACTLY amount, then resets to 0.
function depositForBurn(uint256 amount, bytes calldata recipient) external;Parameters
| Name | Type | Description |
|---|---|---|
| amount | uint256 | |
| recipient | bytes |
depositForBurnWithHook
Like depositForBurn but attaches CCTP v2 hookData to the burn message (via
TokenMessengerV2.depositForBurnWithHook) for the destination recipient to execute. Reverts
CCTPEmptyHookData if hookData is empty (use depositForBurn for a hook-less burn). When
hookData is a Lattice envelope (HOOK_MAGIC ‖ target ‖ payload) it also reverts
CCTPHookWithoutDestinationCaller unless the destination domain's destinationCaller is set: it
MUST be the destination diamond, or anyone could mint via Circle's transmitter and skip the hook.
Other hookData is not guarded (the destination relays it plainly). The lock is PER DOMAIN, so it
also routes plain depositForBurn burns to that domain through the destination diamond.
function depositForBurnWithHook(uint256 amount, bytes calldata recipient, bytes calldata hookData) external;Parameters
| Name | Type | Description |
|---|---|---|
| amount | uint256 | |
| recipient | bytes | |
| hookData | bytes |
relayMessage
PERMISSIONLESS passthrough: forwards an Iris-attested CCTP message to the transmitter, which
mints USDC directly to the recipient. Reverts CCTPRelayFailed if the transmitter returns false.
A burn carrying a valid Lattice hook envelope (one relayMessageWithHook accepts) reverts
CCTPHookRelayRequired BEFORE minting unless the caller is its attested mintRecipient (an
escape hatch that delivers the funds without running the hook).
function relayMessage(bytes calldata message, bytes calldata attestation) external;Parameters
| Name | Type | Description |
|---|---|---|
| message | bytes | |
| attestation | bytes |
relayMessageWithHook
PERMISSIONLESS relay that ALSO executes a Lattice hook envelope carried in the burn message: it
validates the message is a BurnMessageV2 addressed to this adapter's TokenMessenger carrying a
valid Lattice hookData envelope, mints via the transmitter, THEN calls the decoded hook target
through the CCTPHookExecutor with Circle-ATTESTED context. Hook execution is LENIENT — a
reverting/return-bombing target does NOT revert the relay (the mint stands, nonce consumed) —
but a target whose OWN frame runs out of gas reverts the whole relay with
ICCTPHookExecutor.CCTPHookOutOfGas, leaving the nonce live for a retry with more gas. A sub-call
out-of-gas reads as an ordinary revert unless the target re-raises it (ICCTPHookReceiver).
Reverts CCTPNotBurnMessage / CCTPInvalidHookData on a non-conforming message BEFORE minting,
and CCTPRelayFailed if the transmitter returns false.
function relayMessageWithHook(bytes calldata message, bytes calldata attestation) external;Parameters
| Name | Type | Description |
|---|---|---|
| message | bytes | |
| attestation | bytes |
Events
DepositForBurn
Emitted when USDC is burned on this chain for minting on destinationDomain.
event DepositForBurn(
address indexed sender,
uint256 indexed destinationChainId,
uint32 destinationDomain,
bytes32 mintRecipient,
uint256 amount
);Parameters
| Name | Type | Description |
|---|---|---|
| sender | address | |
| destinationChainId | uint256 | |
| destinationDomain | uint32 | |
| mintRecipient | bytes32 | |
| amount | uint256 |
RelayedMessage
Emitted when an inbound Iris-attested CCTP message is relayed to the transmitter for minting.
event RelayedMessage(address indexed caller);Parameters
| Name | Type | Description |
|---|---|---|
| caller | address |
RegisteredChainDomain
Emitted when an EVM/non-EVM chainId ⇒ CCTP domain equivalence is registered.
event RegisteredChainDomain(uint256 indexed chainId, uint32 domain);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| domain | uint32 |
ConfiguredDomain
Emitted when the per-domain fee / finality / destinationCaller config is set.
event ConfiguredDomain(
uint32 indexed domain, uint256 maxFee, uint32 minFinalityThreshold, bytes32 destinationCaller
);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 | |
| maxFee | uint256 | |
| minFinalityThreshold | uint32 | |
| destinationCaller | bytes32 |
DepositForBurnWithHook
Emitted when USDC is burned WITH a CCTP v2 hook payload for the destination recipient to execute.
event DepositForBurnWithHook(
address indexed sender,
uint256 indexed destinationChainId,
uint32 destinationDomain,
bytes32 mintRecipient,
uint256 amount,
bytes hookData
);Parameters
| Name | Type | Description |
|---|---|---|
| sender | address | |
| destinationChainId | uint256 | |
| destinationDomain | uint32 | |
| mintRecipient | bytes32 | |
| amount | uint256 | |
| hookData | bytes |
HookExecuted
Emitted after an inbound hooked message is relayed: success is whether the hook target ran
without reverting. The mint stands and the CCTP nonce is consumed regardless of success (a
target whose OWN frame runs out of gas reverts the relay instead; an out-of-gas in a sub-call it
makes still emits false unless the target re-raises it, see ICCTPHookReceiver).
event HookExecuted(bytes32 indexed nonce, address indexed target, bool success);Parameters
| Name | Type | Description |
|---|---|---|
| nonce | bytes32 | |
| target | address | |
| success | bool |
Errors
CCTPZeroAddress
A required address (tokenMessenger / messageTransmitter / usdc) was the zero address.
error CCTPZeroAddress();CCTPUnknownDestinationChain
No CCTP domain is registered for the destination chainId decoded from the recipient.
error CCTPUnknownDestinationChain(uint256 chainId);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
CCTPChainReferenceTooLong
The chain reference decoded from the ERC-7930 recipient does not fit in a uint256.
error CCTPChainReferenceTooLong(uint256 length);Parameters
| Name | Type | Description |
|---|---|---|
| length | uint256 |
CCTPRelayFailed
The CCTP transmitter's receiveMessage returned false (attestation invalid / already used).
error CCTPRelayFailed();CCTPZeroChainId
registerChainDomain was called with chainId 0 (reserved as the unregistered sentinel).
error CCTPZeroChainId();CCTPChainAlreadyRegistered
The chainId is already registered — identity registers exactly once (fail-loud, no overwrite).
error CCTPChainAlreadyRegistered(uint256 chainId);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
CCTPDomainAlreadyRegistered
The domain is already owned by ownerChainId — two chains can never share a CCTP domain.
error CCTPDomainAlreadyRegistered(uint32 domain, uint256 ownerChainId);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 | |
| ownerChainId | uint256 |
CCTPDomainNotRegistered
configureDomain targeted a domain no chain has registered.
error CCTPDomainNotRegistered(uint32 domain);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 |
CCTPMaxFeeExceedsAmount
The domain's configured maxFee is >= the burn amount (CCTP requires amount > maxFee; the
>= form also rejects a zero-amount burn).
error CCTPMaxFeeExceedsAmount(uint256 maxFee, uint256 amount);Parameters
| Name | Type | Description |
|---|---|---|
| maxFee | uint256 | |
| amount | uint256 |
CCTPEmptyHookData
depositForBurnWithHook was called with empty hookData (use depositForBurn for no hook).
error CCTPEmptyHookData();CCTPInvalidHookData
An inbound hooked message's hookData is not a valid Lattice envelope (missing magic or < 24 B).
error CCTPInvalidHookData();CCTPNotBurnMessage
An inbound message is not a CCTP v2 BurnMessageV2 addressed to this adapter's TokenMessenger
(wrong length, wrong header/body version, or a mismatched header recipient).
error CCTPNotBurnMessage();CCTPHookRelayRequired
relayMessage was given a burn carrying a valid Lattice hook envelope by someone other than its
attested mintRecipient. Relay it through relayMessageWithHook so the hook runs.
error CCTPHookRelayRequired();CCTPHookWithoutDestinationCaller
depositForBurnWithHook sent a Lattice hook envelope toward a domain whose destinationCaller is
bytes32(0): anyone could then mint through Circle's transmitter directly and skip the hook.
Configure the destination diamond as the domain's destinationCaller first.
error CCTPHookWithoutDestinationCaller(uint32 domain);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 |