CCTP

Aptos Packages

CCTP V1 Packages on the Aptos blockchain

The CCTP Aptos smart contract implementation is written in Move. The Aptos CCTP implementation is split into two packages: MessageTransmitter and TokenMessengerMinter. TokenMessengerMinter encapsulates the functionality of both TokenMessenger and TokenMinter contracts on EVM chains. To ensure alignment with EVM contracts logic and state, and to facilitate future upgrades and maintenance, the code and state of the Aptos packages reflect the EVM counterparts as closely as possible.

The key difference with Aptos packages from EVM and other CCTP implementations is the receive message flow. Since the Move language uses static dispatch and requires all dependencies to be available at compile time, the MessageTransmitter receive_message function cannot call into the receiver package (e.g. TokenMessengerMinter for USDC transfers). The workaround for this limitation is that callers of message_transmitter::receive_message must also atomically (in the same transaction or move script) call into the receiver package's handle_receive_message function with a Receipt object returned from receive_message, and then pass a Receipt object back into the message_transmitter::complete_receive_message function to complete the message and destroy the Receipt object. Please see the interface and examples below for more information on this flow.

Below are the known package IDs and object IDs on Aptos testnet and mainnet.

PackageDomainAddress
MessageTransmitter90x081e86cebf457a0c6004f35bd648a2794698f52e0dde09a48619dcd3d4cc23d9
TokenMessengerMinter90x5f9b937419dda90aa06c1836b7847f65bbbe3f1217567758dc2488be31a477b9
ObjectObject ID
MessageTransmitter0xcbb70e4f5d89b4a37e850c22d7c994e32c31e9cf693e9633784e482e9a879e0c
TokenMessengerMinter0x1fbf4458a00a842a4774f441fac7a41f2da0488dd93a43880e76d58789144e17
Stablecoin0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832

CCTP and Stablcoin use a shared package AptosExtensions deployed at 0xb75a74c6f8fddb93fdc00194e2295d8d5c3f6a721e79a2b86884394dcc554f8f

PackageDomainAddress
MessageTransmitter90x177e17751820e4b4371873ca8c30279be63bdea63b88ed0f2239c2eea10f1772
TokenMessengerMinter90x9bce6734f7b63e835108e3bd8c36743d4709fe435f44791918801d0989640a9d
ObjectObject ID
MessageTransmitter0x45bf7f71e44750f2b2a7a1fea21fc44b4a83ba5d68ab10c7a3935f6d8cbdbc75
TokenMessengerMinter0x9e6702a472080ea3caaf6ba9dfaa6effad2290a9ba9adaacd5af5c618e42782d
Stablecoin0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b

The shared package AptosExtensions is deployed at 0x98bce69c31ee2cf91ac50a3f38db7b422e3df7cdde9fe672ee1d03538a6aeae0

The Aptos CCTP source code is available on GitHub.

The interface below serves as a reference for permissionless messaging functions exposed by the programs.

deposit_for_burn

Burns passed in FungibleAsset from sender to be minted on the destination domain. Minted tokens will be transferred to mint_recipient on the destination chain. The mint_recipient can be an account address or a store address. The deposit_for_burn interface and functionality is very similar to the EVM implementation. The asset parameter is the key difference due to how passing tokens around on Aptos works. The asset parameter is Aptos Fungible Asset type, defining information of the token to deposit and burn.

Nonce reserved for the message is returned, but it is not required to do anything with this return value, they are returned for convenience.

Parameters

FieldTypeDescription
callerSignerSigner executing the transaction
assetFungibleAssetAsset to be burned.
destination_domainu32Destination domain identifier.
mint_recipientaddressAddress of mint recipient on destination domain. Can be an account address or store address. Note: If destination is a non-Move chain, mint_recipient address should be converted to hex and passed in using the @0x123 address format.

deposit_for_burn_with_caller

The same as deposit_for_burn, but with an additional parameter: destination_caller. This parameter specifies which address has permission to call receiveMessage on the destination domain for the message.

Parameters

FieldTypeDescription
callerSignerSigner executing the transaction
assetFungibleAssetAsset to be burned.
destination_domainu32Destination domain identifier.
mint_recipientaddressAddress of mint recipient on destination domain. Can be an account address or store address. Note: If destination is a non-Move chain, mint_recipient address should be converted to hex and passed in using the @0x123 address format.
destination_calleraddressAddress of caller on destination chain.

replace_deposit_for_burn_with

Replace a BurnMessage to change the mint recipient and/or destination caller. Allows the sender of a previous BurnMessage (created by deposit_for_burn or deposit_for_burn_with_caller) to send a new BurnMessage to replace the original.

Remarks:

  • Only the sender of the original deposit_for_burn transaction has access to call replace_deposit_for_burn
  • The new BurnMessage will reuse the amount and burn token of the original, without requiring a new FA deposit.
  • The resulting mint will supersede the original mint, as long as the original mint has not confirmed yet onchain.
  • A valid attestation is required before calling this function.
  • This is useful in situations where the user specified an incorrect address and has no way to safely mint the previously burned USDC.

Parameters

FieldTypeDescription
callerSignerSigner executing the transaction
original_messagevector<u8>Original message bytes (to replace).
original_attestationvector<u8>Original attestation
new_destination_callerOption<address>The new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller, indicating that any destination caller is valid.
new_mint_recipientOption<address>The new mint recipient, which may be the same as the original mint recipient, or different.

handle_receive_message

Handles an incoming message that has already been verified by message_transmitter, and mints USDC to the recipient for valid messages. This function can only be called with a mutable reference to a Receipt object, which can only be created via a call with a valid message to the message_transmitter::receive_message function. In this function MessageTransmitter::complete_receive_message is called with the Receipt to emit the MessageReceived event to complete the message and destroy Receipt.

This should be called in a single transaction after calling message_transmitter::receive_message. EOAs can execute these functions in a single Move script. See the Examples section for the entire flow of receiving a message.

Parameters

FieldTypeDescription
receiptReceiptReceipt struct returned by message_transmitter:receive_message

receive_message

Receives a message emitted from a source chain. Messages with a given nonce can only be received once for a (sourceDomain, destinationDomain) pair.

This function returns a Receipt struct (Hot Potato) after validating the attestation and marking the nonce as used. In order to destroy the Receipt and complete the message, in a single transaction, handle_receive_message() must be called with the Receipt in the receiver package. EOAs can execute these functions in a single Move script.

Returns a Receipt object that must be handled by the intended receiving package, and completed via a complete_receive_message call before the transaction ends. See the Examples section for more information on receiving USDC transfers.

Parameters

FieldTypeDescription
callerSignerSigner executing the transaction
message_bytesvector<u8>Message bytes
attestationvector<u8>Attestation

complete_receive_message

Completes the message by emitting a MessageReceived event for a receipt and destroying the receipt.

Parameters

FieldTypeDescription
callerSignerSigner for the receipt.recipient address
receiptReceiptReceipt struct to be destroyed

send_message

Sends a message to the destination domain and recipient. Nonce reserved for the message is returned, but it is not required to do anything with this struct, it is returned for convenience.

Remarks:

  • For USDC transfers, this function is called directly by the TokenMessengerMinter package in deposit_for_burn().

Parameters

FieldTypeDescription
callerSignerSigner for executing the transaction
destination_domainu32Destination domain identifier.
recipientaddressRecipient address. Note: If destination is a non-Move chain, recipient address should be converted to hex and passed in using the @0x123 address format.
message_bodyvector<u8>Message to be sent to destination chain

send_message_with_caller

This is the same as send_message, except the receive_message call on the destination domain must be called by destination_caller.

Parameters

FieldTypeDescription
callerSignerSigner for executing the transaction
destination_domainu32Destination domain identifier.
recipientaddressRecipient address. Note: If destination is a non-Move chain, recipient address should be converted to hex and passed in using the @0x123 address format.
destination_calleraddressAddress of caller on destination chain.
message_bodyvector<u8>Message to be sent to destination chain

replace_message

Replace a message with a new message body and/or destination caller. The originalAttestation must be a valid attestation of originalMessage, produced by Circle’s attestation service.

Remarks:

  • Only the sender of the original deposit_for_burn transaction has access to call replace_message

Parameters

FieldTypeDescription
callerSignerSigner executing the transaction
original_messagevector<u8>Original message bytes (to replace).
original_attestationvector<u8>Original attestation
new_message_bodyOption<vector<u8>>New message body
new_destination_callerOption<address>The new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller, indicating that any destination caller is valid.

Pre-compiled scripts for executing deposit_for_burn and handle_receive_message are available in the repo for testnet and mainnet. Alternatively, the scripts can be compiled from the source code. The documentation can be found on the official Aptos website.

Outgoing mint recipient addresses from Aptos are passed as Aptos address types and can be treated the same as a bytes32 mint recipient parameter on EVM implementations.

Aptos mint recipient addresses from other chains should be treated the same as a hex bytes32 parameter.

Did this page help you?
© 2023-2025 Circle Technology Services, LLC. All rights reserved.