> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# CCTP Aptos packages and interfaces V1

> Packages for CCTP V1 support on the Aptos blockchain

<Warning>
  **This is CCTP V1 version. For the latest version, see [CCTP](/cctp)**.
</Warning>

## Overview

The CCTP V1 Aptos smart contract implementation is written in
[Move](https://aptos.dev/en/build/smart-contracts). 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](https://aptos.dev/en/build/smart-contracts/scripts)) 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

| Package | [Domain](/cctp/v1/supported-domains) | Address |
| :- | :- | :- |
| MessageTransmitter | 9 | `0x081e86cebf457a0c6004f35bd648a2794698f52e0dde09a48619dcd3d4cc23d9` |
| TokenMessengerMinter | 9 | `0x5f9b937419dda90aa06c1836b7847f65bbbe3f1217567758dc2488be31a477b9` |

#### Object IDs

| Object | Object ID |
| :- | :- |
| MessageTransmitter | `0xcbb70e4f5d89b4a37e850c22d7c994e32c31e9cf693e9633784e482e9a879e0c` |
| TokenMessengerMinter | `0x1fbf4458a00a842a4774f441fac7a41f2da0488dd93a43880e76d58789144e17` |
| Stablecoin | `0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832` |

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

### Mainnet

#### Package IDs

| Package | [Domain](/cctp/v1/supported-domains) | Address |
| :- | :- | :- |
| MessageTransmitter | 9 | `0x177e17751820e4b4371873ca8c30279be63bdea63b88ed0f2239c2eea10f1772` |
| TokenMessengerMinter | 9 | `0x9bce6734f7b63e835108e3bd8c36743d4709fe435f44791918801d0989640a9d` |

#### Object IDs

| Object | Object ID |
| :- | :- |
| MessageTransmitter | `0x45bf7f71e44750f2b2a7a1fea21fc44b4a83ba5d68ab10c7a3935f6d8cbdbc75` |
| TokenMessengerMinter | `0x9e6702a472080ea3caaf6ba9dfaa6effad2290a9ba9adaacd5af5c618e42782d` |
| Stablecoin | `0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b` |

The shared package `AptosExtensions` is deployed at
`0x98bce69c31ee2cf91ac50a3f38db7b422e3df7cdde9fe672ee1d03538a6aeae0`

## Interface

The Aptos CCTP V1 source code is
[available on GitHub](https://github.com/circlefin/aptos-cctp/).

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

### TokenMessengerMinter

#### [deposit\_for\_burn](https://github.com/circlefin/aptos-cctp/blob/master/packages/token_messenger_minter/sources/token_messenger/token_messenger.move#L123)

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**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer executing the transaction |
| asset | `FungibleAsset` | Asset to be burned. |
| destination\_domain | `u32` | Destination domain identifier. |
| mint\_recipient | `address` | Address of mint recipient on destination domain. Can be an account address or [store address](https://aptos.dev/en/build/smart-contracts/fungible-asset#managing-stores-advanced). *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](https://github.com/circlefin/aptos-cctp/blob/master/packages/token_messenger_minter/sources/token_messenger/token_messenger.move#L147)

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**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer executing the transaction |
| asset | `FungibleAsset` | Asset to be burned. |
| destination\_domain | `u32` | Destination domain identifier. |
| mint\_recipient | `address` | Address of mint recipient on destination domain. Can be an account address or [store address](https://aptos.dev/en/build/smart-contracts/fungible-asset#managing-stores-advanced). *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\_caller | `address` | Address of caller on destination chain. |

<Note>
  **Destination Caller Notes**

  If 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.*
</Note>

#### [replace\_deposit\_for\_burn\_with](https://github.com/circlefin/aptos-cctp/blob/master/packages/token_messenger_minter/sources/token_messenger/token_messenger.move#L171)

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**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer executing the transaction |
| original\_message | `vector<u8>` | Original message bytes (to replace). |
| original\_attestation | `vector<u8>` | Original attestation |
| new\_destination\_caller | `Option<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\_recipient | `Option<address>` | The new mint recipient, which may be the same as the original mint recipient, or different. |

#### [handle\_receive\_message](https://github.com/circlefin/aptos-cctp/blob/master/packages/token_messenger_minter/sources/token_messenger/token_messenger.move#241)

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](https://github.com/circlefin/aptos-cctp/blob/master/packages/token_messenger_minter/scripts/handle_receive_message.move#L5).
See the Examples section for the entire flow of receiving a message.

**Parameters**

| Field | Type | Description |
| :- | :- | :- |
| receipt | `Receipt` | Receipt struct returned by `message_transmitter:receive_message` |

### MessageTransmitter

#### [receive\_message](https://github.com/circlefin/aptos-cctp/blob/master/packages/message_transmitter/sources/message_transmitter.move#L287)

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](https://medium.com/@borispovod/move-hot-potato-pattern-bbc48a48d93c))
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](https://github.com/circlefin/aptos-cctp/blob/master/packages/token_messenger_minter/scripts/handle_receive_message.move#L5).

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](/cctp/v1/transfer-usdc-on-testnet-from-aptos-to-base) section for
more information on receiving USDC transfers.

**Parameters**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer executing the transaction |
| message\_bytes | `vector<u8>` | Message bytes |
| attestation | `vector<u8>` | Attestation |

#### [complete\_receive\_message](https://github.com/circlefin/aptos-cctp/blob/master/packages/message_transmitter/sources/message_transmitter.move#L330)

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

**Parameters**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer for the `receipt.recipient` address |
| receipt | `Receipt` | Receipt struct to be destroyed |

#### [send\_message](https://github.com/circlefin/aptos-cctp/blob/master/packages/message_transmitter/sources/message_transmitter.move#L169)

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**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer for executing the transaction |
| destination\_domain | `u32` | Destination domain identifier. |
| recipient | `address` | Recipient 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\_body | `vector<u8>` | Message to be sent to destination chain |

#### [send\_message\_with\_caller](https://github.com/circlefin/aptos-cctp/blob/master/packages/message_transmitter/sources/message_transmitter.move#L198)

This is the same as send\_message, except the `receive_message` call on the
destination domain must be called by `destination_caller`.

**Parameters**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer for executing the transaction |
| destination\_domain | `u32` | Destination domain identifier. |
| recipient | `address` | Recipient 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\_caller | `address` | Address of caller on destination chain. |
| message\_body | `vector<u8>` | Message to be sent to destination chain |

<Note>
  **Destination Caller Notes**

  If 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.*
</Note>

#### [replace\_message](https://github.com/circlefin/aptos-cctp/blob/master/packages/message_transmitter/sources/message_transmitter.move#L229)

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**

| Field | Type | Description |
| :- | :- | :- |
| caller | `Signer` | Signer executing the transaction |
| original\_message | `vector<u8>` | Original message bytes (to replace). |
| original\_attestation | `vector<u8>` | Original attestation |
| new\_message\_body | `Option<vector<u8>>` | New message body |
| new\_destination\_caller | `Option<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. |

## Additional Notes

### Using Move Scripts

Pre-compiled scripts for executing `deposit_for_burn` and
`handle_receive_message` are available in the
[repo](https://github.com/circlefin/aptos-cctp/tree/master/typescript/example/precompiled-move-scripts)
for testnet and mainnet. Alternatively, the scripts can be compiled from the
source code. The documentation can be found on the official Aptos
[website](https://aptos.dev/en/build/smart-contracts/scripts/compiling-scripts).

### 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.
