Skip to main content
CCTP for non-USDC transfers can carry arbitrary hookData that is delivered together with the tokens on the destination blockchain. When autoExecuteHookData is true and the recipient implements executeWithCrossChainToken, CCTP for non-USDC invokes that entrypoint in the same transaction that delivers the tokens.

Enabling hook execution

A sender provides three parameters on crossChainTransfer to control hook behavior: If autoExecuteHookData is false, the tokens are delivered but the hook is not called. If hookData is empty, the hook is not called even when autoExecuteHookData is true.
Hook receivers execute arbitrary logic in the same transaction that delivers tokens. A vulnerable hook can lock or redirect funds permanently. Thoroughly audit any hook contract before deploying to mainnet—incorrect access control, unchecked external calls, and missing input validation are common failure modes.

Receiver contract requirement

When autoExecuteHookData is true and hookData is non-empty, the destinationAddress must be a contract that implements executeWithCrossChainToken and returns the EXECUTE_SUCCESS sentinel. Restrict the caller to the local CrossChainTokenService.
Solidity
Return keccak256("circle-cctpx-execute-success"). See Build a hook receiver for a full example. If the destination is an externally owned account, doesn’t implement the interface, or returns a value other than EXECUTE_SUCCESS, the destination service reverts with HookDataExecutionFailed. Sending hook data to an address that can’t satisfy the interface will fail the transfer at delivery.

Atomicity

The hook executes in the same transaction as token delivery. If the hook reverts, the entire transfer reverts. Tokens are not delivered and the source-domain transfer remains intact. Designing hooks that consider their own failure modes is the receiver’s responsibility.

Hook parameters

The sourceAddress is encoded as bytes rather than address to support source blockchains where addresses do not fit in 20 bytes. finalityThresholdExecuted is the finality threshold at which the inbound message was attested: 2000 for finalized transfers, 1000 for fast (pre-finalized) transfers. Receivers can branch on this value to decide whether to perform side-effects immediately or defer them.

Finality threshold and rollback

Hooks may execute on pre-finalized messages when the sender opts into minFinalityThreshold < 2000. At that finality, the source blockchain transaction can still be reorged, which would invalidate the delivery. Integrators using autoExecuteHookData with minFinalityThreshold < 2000 must treat hook execution on unfinalized messages as provisional and design their hook contracts to tolerate potential rollback—for example, by deferring irreversible side-effects until finalityThresholdExecuted equals 2000 or until finality is otherwise confirmed. Prefer standard finality (2000) for hook transfers unless you have explicitly designed for provisional execution.

Self-relay required for hook transfers

Iris does not relay transfers that carry hook data with autoExecuteHookData = true. Do not include FORWARD in the fee quote for these transfers. You or your own relayer infrastructure must call receiveMessage on the destination MessageTransmitterV2 to complete the transfer. Plan for this when designing a hook-based integration: every hook transfer requires the sender (or a relayer the sender operates) to drive the destination call.