Skip to main content
This is CCTP V1 version. For the latest version, see CCTP.

Overview

The CCTP V1 Aptos smart contract implementation is written in Move. The Aptos CCTP V1 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 V1 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.

Testnet

Package IDs

Object IDs

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

Mainnet

Package IDs

Object IDs

The shared package AptosExtensions is deployed at 0x98bce69c31ee2cf91ac50a3f38db7b422e3df7cdde9fe672ee1d03538a6aeae0

Interface

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

TokenMessengerMinter

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

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
Destination Caller NotesIf the destination_caller does not represent a valid address, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard deposit_for_burn should be preferred for use cases where a specific destination caller is not required.Note: If destination is a non-Move chain, destination_caller address should be converted to hex and passed in using the @0x123 address format.

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

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

MessageTransmitter

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

complete_receive_message

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

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

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
Destination Caller NotesIf the destination_caller does not represent a valid address, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard deposit_for_burn should be preferred for use cases where a specific destination caller is not required.Note: If destination is a non-Move chain, destination_caller address should be converted to hex and passed in using the @0x123 address format.

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

Additional Notes

Using Move Scripts

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.

Mint Recipient Addresses for Aptos as Source Chain

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.

Mint Recipient Addresses for Aptos as Destination Chain

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