Skip to main content

Overview

Solana CCTP programs are written in Rust and leverage the Anchor framework. The Solana CCTP V2 protocol implementation is split into two programs: MessageTransmitterV2 and TokenMessengerMinterV2. TokenMessengerMinterV2 encapsulates the functionality of both TokenMessengerV2 and TokenMinterV2 contracts on EVM chains. To ensure alignment with EVM contracts’ logic and state, and to facilitate upgrades and maintenance, the code and state of Solana programs reflect the EVM counterparts as closely as possible.

Mainnet Program Addresses

Devnet Program Addresses

The Solana CCTP source code is available on GitHub. The interface below serves as a reference for permissionless messaging functions exposed by the programs.

CCTP V2 Interface

The interface below serves as a reference for permissionless messaging functions exposed by the TokenMessengerMinter and MessageTransmitter programs. The full IDLs can be found onchain using a block explorer. MessageTransmitterV2 IDL and TokenMessengerMinterV2 IDL. Please see the instruction rust files or quick-start for PDA information.

Changes from CCTP V1

New Functions

  • TokenMessengerMinterV2#deposit_for_burn_with_hook (extends deposit_for_burn by adding hook data)
  • TokenMessengerMinterV2#handle_receive_unfinalized_message (replaces handle_receive_message)
  • TokenMessengerMinterV2#handle_receive_finalized_message (replaces handle_receive_message)

Modified Functions

  • TokenMessengerMinterV2#deposit_for_burn
  • MessageTransmitterV2#send_message
  • MessageTransmitterV2#receive_message
  • MessageTransmitterV2#reclaim_event_account (5 day waiting window added, see TokenMessengerMinterV2 section for more information)

Removed Functions

  • TokenMessengerV2#handle_receive_message
  • TokenMessengerV2#replace_deposit_for_burn
  • TokenMessengerV2#deposit_for_burn_with_caller
  • MessageTransmitterV2#replace_message
  • MessageTransmitterV2#send_message_with_caller

TokenMessengerMinterV2

depositForBurn

Deposits and burns tokens from sender to be minted on destination domain. Minted tokens will be transferred to mintRecipient. Parameters
FeesA fee may be charged for standard USDC transfers. Fees for standard transfers are set to 0, but are subject to change. See CCTP Fees for more information.
MessageSent event storageTo ensure persistent and reliable message storage, MessageSent events are stored in accounts. MessageSent event accounts are generated client-side, passed into the instruction call, and assigned to have the MessageTransmitterV2 program as the owner. See the Quickstart Guide for how to generate this account and pass it to the instruction call.For depositForBurn CCTP V1 messages, this costs ~0.00381408 SOL in rent. This rent is paid by the event_rent_payer account which can be the user or subsidized by a calling program or integrator.In CCTP V1, this SOL could be reclaimed by calling reclaim_event_account once the attestation is available.In CCTP V2, message nonces are generated offchain, meaning the source messages cannot be identified from the attestation. Due to this, there is a 5 day window after sending a message that callers must wait before reclaim_event_account can be called. This is to ensure that the message has been fully processed by Circle’s offchain services.

depositForBurnWithHook

Deposits and burns tokens from sender to be minted on destination domain, and emits a crosschain message with additional hook data appended. In addition to the standard deposit_for_burn parameters, deposit_for_burn_with_hook accepts a dynamic-length hookData parameter, allowing the caller to include additional metadata to the attested message, which can be used to trigger custom logic on the destination chain. Parameters

handleReceiveFinalizedMessage

Handles incoming message received by the local MessageTransmitter, and takes the appropriate action. For a burn message, mints the associated token to the requested recipient on the local domain. Validates the function sender is the local MessageTransmitter, and the remote sender is a registered remote TokenMessenger for remoteDomain. Additionally, reads the feeExecuted parameter from the BurnMessage. If nonzero, the feeExecuted amount is minted to the feeRecipient. Parameters

handleReceiveUnfinalizedMessage

Handles incoming message received by the local MessageTransmitter, and takes the appropriate action. For a burn message, mints the associated token to the requested recipient on the local domain. Validates the function sender is the local MessageTransmitter, and the remote sender is a registered remote TokenMessenger for remoteDomain. Similar to handleReceiveFinalizedMessage, but is called for messages which are not finalized (finalityThresholdExecuted < 2000). Unlike handleReceiveFinalizedMessage, handleReceiveUnfinalizedMessage has the following messageBody parameter:
  • expirationBlock. If expirationBlockblockNumber on the destination domain, the message will revert and must be re-signed without the expiration block.
Parameters

MessageTransmitterV2

receiveMessage

Messages with a given nonce can only be broadcast successfully once for a pair of domains. The message body of a valid message is passed to the specified recipient for further processing. Parameters Remaining Accounts If the receiveMessage instruction is being called with a deposit for burn message that will be received by the TokenMessengerMinterV2, additional remainingAccounts are required so they can be passed with the CPI to TokenMessengerMinter#handle_receive_finalized_message or TokenMessengerMinter#handle_receive_unfinalized_message:

sendMessage

Sends a message to the destination domain and recipient. Stores message in a MessageSent account which will be attested by Circle’s attestation service. Parameters

Additional Notes

These notes are applicable to all CCTP versions.

Mint Recipient for Solana as Destination Chain Transfers

When calling depositForBurn on a non-Solana chain with Solana as the destination, the mintRecipient should be a hex encoded USDC token account address. The token account* must exist at the time receiveMessage is called on Solana* or else this instruction will revert. An example of converting an address from Base58 to hex taken from the Solana quickstart tutorial in Typescript can be seen below:
Typescript

Mint Recipient for Solana as Source Chain Transfers

When specifying the mintRecipient for Solana deposit_for_burn instruction calls, the address must be given as the 32 byte version of the hex address in base58 format. An example taken from the Solana quickstart tutorial in Typescript can be seen below:
Typescript

Program Events

Program events like DepositForBurn , MintAndWithdraw , and MessageReceived are emitted as Anchor CPI events. This means a self-CPI is made into the program with the serialized event as instruction data so it is persisted in the transaction and can be fetched later on as needed. More information can be seen in the Anchor implementation PR, and an example of reading CPI events can be seen in the solana-cctp-contracts repository. MessageSent events are different, as they are stored in accounts. Please see the MessageSent Event Storage section for more info.

CCTP Workflow vs. CCTP V1

This table highlights the key workflow improvements of CCTP over CCTP V1 in terms of enhanced cross-chain messaging, fewer manual steps, and greater control over message acceptance:
WHAT’S NEXT