We refreshed our doc site!

Bookmarked links may have changed

Read release notes

Interactive Quickstarts

Cross Chain Transfer Protocol

Introduction

Circle's Cross-Chain Transfer Protocol (CCTP) facilitates the transfer of USDC between distinct blockchains, providing a more streamlined experience. By integrating CCTP with programmable wallets in your applications, you enable seamless USDC transactions across multiple chains. This reduces the need for users to manage separate wallets for different blockchains, potentially broadening your audience and providing increased liquidity and adaptability. It's designed to provide users with a cohesive and efficient digital currency experience.

Leverage Blockchain-Specific Attributes

Use blockchain-specific characteristics to optimize your user experience. For instance, by bridging your ETH from Ethereum Mainnet to an Ethereum Layer 2 rollup, such as Polygon, you gain access to lower transaction fees while still enjoying the benefits of USDC.

Cross-Chain Swaps

Enable cross-chain swaps, allowing users to exchange digital assets that reside on different chains. For example, users can swap AVAX for USDC on Avalanche, route it to Polygon Mainnet, and further swap it for MATIC token, expanding liquidity across multiple chains.

Cross-Chain Purchases

Facilitate cross-chain purchases with minimal effort. Users can utilize USDC on Avalanche to buy an NFT on Uniswap on Ethereum, then list it for sale on OpenSea. CCTP effortlessly routes the USDC from Avalanche to Ethereum for the purchase.

Solve Fragmented Liquidity

Remove liquidity fragmentation barriers. If a user needs to send USDC to an address on Avalanche but only holds USDC on Ethereum, the solution becomes seamless. By bridging the USDC from Ethereum to Avalanche through CCTP, users can transact across different blockchains.

Outcomes of this Interactive Quickstart Guide

By the conclusion of this interactive guide, you will learn how to facilitate a transfer of USDC across blockchains using a Programmable Wallet. Specifically, the guide will demonstrate a scenario wherein a user conducts a USDC transfer leveraging the Cross-Chain Transfer Protocol (CCTP). You will follow step-by-step instructions to create and execute a USDC transfer from Sepolia, an Ethereum testnet, to Mumbai, the Polygon Testnet, via a programmable wallet. This practical walkthrough is designed to equip you with the knowledge to implement CCTP in your own applications.

Completing a Cross-Blockchain Transfer: Step-By-Step Process

  1. 1

    Approve USDC Contract to Initiate Transfers

    To utilize CCTP effectively, it's necessary to authorize the USDC contract to conduct transfers on a user's behalf. In this guide, we approve only a small amount of USDC for demonstration. However, for operational efficiency, you might want to approve a larger amount to minimize the frequency of this action in a production environment.

  2. 2

    Initiate the Burning of USDC

    Following the user's request to move USDC from Ethereum to Polygon, leverage the provided tools to initiate burning the specified amount of USDC from the Ethereum wallet created for this transaction.

    Burn USDC
  3. 3

    Obtain Circle’s Attestation

    Circle monitors the burn event on the Ethereum blockchain and issues an attestation. Retrieve this attestation using the relevant procedures, which serves as the authorization required to mint the corresponding USDC amount on the Polygon blockchain.

    Fetch Attestation
  4. 4

    Trigger USDC Minting

    Utilize the retrieved attestation to start the minting process. The attestation confirms the amount of USDC to mint on the Polygon blockchain, and the amount to allocate to the specified Polygon wallet.

    Mint USDC

Understanding Smart Contracts

Smart contracts are computer protocols that automate the execution of agreements, operating under a set of predefined conditions. Once deployed onto a blockchain, they follow an "if-then" logic to perform actions automatically when specific conditions are met. The immutable nature of blockchain ensures that the smart contract code cannot be changed once established, which reinforces their reliability as they will always execute exactly as programmed. A smart contract typically consists of code that defines its operations, a data storage area, memory, and a unique public address that can be interacted with through its functions. For a comprehensive exploration of smart contracts, you are encouraged to read further on the dedicated resource.

Exploring the Cross-Chain Transfer Protocol (CCTP)

The Cross-Chain Transfer Protocol (CCTP) serves as an integral tool within the blockchain infrastructure to guarantee the secure and seamless transfer of USDC across various blockchain networks. By adopting CCTP, users can benefit from a protected and efficient means of transferring USDC between supported chains, which currently include Ethereum, Arbitrum, Optimism, and Avalanche. Ongoing developments suggest plans to expand support to additional networks. To learn more about CCTP, see Cross-Chain Transfer Protocol in the Circle Developer Documentation.

To get started, Create a Circle Web3 Services account in the console.

Prerequisites

Before you get started, ensure that you have:

Burn USDC

In the process of transferring USDC from Ethereum to Polygon, you need to give the TokenMessenger contract the necessary permissions to execute the USDC transfer on your behalf. In essence, you're empowering the TokenMessenger contract to access and transfer the specified amount of USDC from your source wallet.

For this, we use the Programmable Wallets contract execution API:

TermDefinition
contractAddress

You interact with the USDC contract on the source chain, so the contractAddress parameter of the request is 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238.

abiFunctionSignature

The function called on the USDC contract is approve(address spender, uint256 value). Calling approve allows the spender to spend value USDC on your behalf. This is necessary in the depositForBurn step later on.

value is denominated in the smallest unit of USDC, which is a millionth of a dollar.

In this case it's approve(address,uint256)

abiParameters

In this case, address is the TokenMessenger contract's address and value is 100000000 (100 USDC).

In this case it's ["0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5", 100000000]

walletId

The wallet that performs the contract execution. This is the ID of the developer-controlled wallet you created earlier.

feeLevel

A dynamic blockchain fee level setting (LOW, MEDIUM, or HIGH) that will be used to pay gas for the transaction. HIGH is used for this transaction.

idempotencyKey

Universally unique identifier (UUID v4) idempotency key. This is automatically generated for you.

entitySecretCiphertext

A base64 string expression of the entity secret ciphertext. Refer to this helpful tool.

Approve USDC Sepolia from source wallet

The second step of the process facilitates a burn of the specified amount of USDC on Ethereum Sepolia (the source chain) that you are looking to move to Polygon Mumbai (the destination chain).

To do this, you again use Programmable Wallets contract execution API:

TermDefinition
contractAddress

You interact with the Token Messenger contract on the source chain, so the contractAddress parameter of the request is 0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5.

abiFunctionSignature

The function being called on the TokenMessenger contract is:
depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken)

This will be the abiFunctionSignature property of the request. In this case it's depositForBurn(uint256,uint32,bytes32,address)

abiParameters

The abiParameters property defines the values to pass to the function. For the call to depositForBurn, they are amount, destinationDomain, mintRecipient and burnToken.

  • amount: the amount of USDC to burn. This amount will be created on the destination chain after the mint. You will burn 1 USDC of the allowance you approved earlier.
  • destinationDomain: a Circle-issued identifier for a network/chain where CCTP contracts are deployed. Since the destination is Polygon, you will use 7. See CCTP: Domain List.
  • mintRecipient: this is the destination address, encoded to a Solidity address representation. This will be the same address as the source wallet. In your application, you will need to encode the destination address to the correct format using a library like web3js - but we have done it for you here.
  • burnToken: the contract address of the token that is being burnt. In this case, it is the USDC contract on the source chain. Other tokens will be supported in the near future.
JavaScript
const encodedDestinationAddress = web3.eth.abi
                    .encodeParameter('address', destinationAddress);

Therefore, the complete abiParameters value is [1000000, 7, {encodedDestinationAddress}, “0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238”].

walletId

The wallet that is performing the contract execution. This will be the ID of the developer-controlled wallet you created earlier.

feeLevel

A dynamic blockchain fee level setting (LOW, MEDIUM, or HIGH) that will be used to pay gas for the transaction. HIGH is used for this transaction.

idempotencyKey

Universally unique identifier (UUID v4) idempotency key. This is automatically generated for you.

entitySecretCiphertext

A base64 string expression of the entity secret ciphertext. Refer to this helpful tool.

Just like your first contract execution request, the other parameters - walletId, feeLevel, idempotencyKey, and EntitySecretCiphertext - were automatically populated in the request.

Deposit for Burn on Ethereum

Validating the Burn of 1 USDC in your Developer Console

After initiating the burn of USDC through our API, you can check whether it was successful in our Developer Console.

  1. 1

    Login to the Web3 Services Console

    To begin the process of validating your burn of USDC, log in to the Web3 Services Console.

  2. 2

    Navigate to the List of Wallets

    Within the console, locate the Wallets page under Dev Controlled Wallet. This page displays all of the wallets you created thus far. Open the Wallets page.

  3. 3

    Open the Wallet Details Screen

    Find and click on the Ethereum Sepolia wallet from which you initiated the USDC burn.

  4. 4

    View Your Wallet Balance

    On the wallet details screen, scroll down to the bottom to find the section displaying your wallet balances. As you successfully created your Sepolia Wallet, an initial deposit of 10 USDC was made. If you have successfully burned 1 USDC, the total wallet balance should now reflect 9 USDC, indicating the accurate deduction of the burned amount.

    Successful Burn Image

By following these step-by-step instructions and reviewing your wallet balance in the Web3 Services Console, you can confidently validate the burn of your USDC tokens and verify the correct adjustment in your wallet's overall balance.

Approve Burn

As a result of interacting with the TokenMessenger contract, Circle generates a unique ID for the transaction. Starting with the returned transaction ID, you call Circle's Attestation service to fetch an attestation that the burn took place. This attestation proves that the USDC was removed from circulation on the source chain.

The attestation is used on the destination chain to mint new USDC. You can make API calls to get the transaction's transactionHash, retrieve the logs of the depositForBurn transaction, and use Circle's Attestation API to fetch the attestation signature. The steps have been broken down for you here, but you can use the following "Try It Out" component to run all of these steps together.

  1. 1

    Fetching the Deposit Transaction Object from Programmable Wallets.

    Call the Programmable Wallets API to fetch the transaction object for the depositForBurn transaction. Make a GET request using the provided code and the transaction ID. Retrieve the transaction object from the response data.

    Code
  2. 2

    Decoding and Creating messageBytes and messageHash with a Web3 Library

    Using a Web3 library like web3 or ethers, decode and create messageBytes and messageHash from the transaction object's txHash. Follow the provided code snippet to extract the relevant information.

    JavaScript
    // get messageBytes from EVM logs using txHash of the transaction.
    const transactionReceipt = await web3.eth.getTransactionReceipt(
    transaction.txHash,
    )
    const eventTopic = web3.utils.keccak256('MessageSent(bytes)')
    const log = transactionReceipt.logs.find((l) => l.topics[0] === eventTopic)
    const messageBytes = web3.eth.abi.decodeParameters(['bytes'], log.data)[0]
    const messageHash = web3.utils.keccak256(messageBytes)
    
  3. 3

    Fetch Attestation Signature from Circle's Iris API

    Retrieve the attestation signature from Circle's Iris API using the messageHash obtained in the previous step. Use the provided code inside a loop to query the API until the attestation status is "complete". Access the attestation signature from the response.

    JavaScript
    // Get attestation signature from iris-api.circle.com
    let attestationResponse = { status: 'pending' }
    while (attestationResponse.status != 'complete') {
    const response = await fetch(
    `https://iris-api-sandbox.circle.com/attestations/${messageHash}`,
    )
    attestationResponse = await response.json()
    await new Promise((r) => setTimeout(r, 2000))
    }
    
Fetch Attestation

Mint USDC

To mint USDC on the destination blockchain, we're using the messageBytes from the depositForBurn event and the attestation signature (attestationResponse.attestation). We're fetching both from Circle's attestation services and calling the receiveMessage function on the Message Transmitter contract in the destination blockchain network.

Using the Programmable Wallets smart contract execution API:

TermDefinition
contractAddress

You interact with the Message Transmitter contract on the destination chain, so the contractAddress parameter of the request is 0xe09A679F56207EF33F5b9d8fb4499Ec00792eA73

abiFunctionSignature

The function being called on the Message Transmitter contract is:
receiveMessage(bytes message, ,bytes attestation)

This is the abiFunctionSignature property of the request receiveMessage(bytes,bytes)

abiParameters

For the call to receiveMessage, the abiParameters are

  • message: the bytes emitted by MessageSent event from the depositForBurn transaction logs. This is messageBytes from the attestation steps earlier.
  • Attestation: The signature from Circle's attestation service. This is attestationResponse.attestation from earlier.
walletId

The wallet that is performing the contract execution. This will be the ID of the developer-controlled wallet you created earlier.

feeLevel

A dynamic blockchain fee level setting (LOW, MEDIUM, or HIGH) that will be used to pay gas for the transaction. HIGH is used for this transaction.

idempotencyKey

Universally unique identifier (UUID v4) idempotency key. This is automatically generated for you.

entitySecretCiphertext

A base64 string expression of the entity secret ciphertext. Refer to this helpful tool.

Once the message has been received, the specified amount of USDC is minted at the recipient's address on the destination blockchain.

Mint on Polygon

This returns a transactionId after you submit the receiveMessage request. You can use this transactionId to look up the status and details of the final transaction.

Check transaction

Congratulations on your Progress!

Throughout this process, you've successfully:

Set up a Developer-Controlled Wallet

You successfully established a developer-controlled wallet using the Programmable Wallet system. This wallet gives you full control and flexibility over your users' wallets, ensuring a secure and frictionless experience.

Interacted with USDC and CCTP Contracts

Using your newly created wallet, you seamlessly interacted with the USDC and CCTP contracts. This enabled you to initiate and monitor USDC transfers, ensuring transparency and control over the process.

Completed USDC Mint on Mumbai

To finalize the USDC minting process on the Mumbai testnet, you called Circle's attestation service. This step ensures the successful creation and verification of USDC tokens on Matic.

Stay connected & Explore more

Your journey with us doesn't stop here. There's so much more to discover und dive into:

Dive into our documentation

Your comprehensive resource for understanding our web3 tools, technologies, and best practices.

Join our Discord server

Engage, ask, share, and collaborate. Become an integral part of our vibrant developer community.

Sample Apps

Get hands-on with real-world use cases, or gain inspiration for your next big project.

Start building with our SDKs

Explore our server and client-side SDKs to start building.

Engage, Build, Share! Dive into our forums, share your feedback, and keep an eye out for exciting challenges and hackathons. Your unique perspective and skills are valuable, and we're eager to see the innovations you'll introduce to our growing ecosystem.

Your feedback matters

Before you embark further on your journey, we'd love to hear from you. Your feedback shapes the future of our platform and helps us provide a better experience for all developers.

What did you love about the process? Was there something you wish was different? Every insight, no matter how small, matters to us.

Thank you for your trust, dedication, and enthusiasm. Here's to the next chapter in your web3 journey and the marvelous innovations you'll bring forth.

Happy Building! 🚀


Next: Explore more Quickstarts

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