Building With CCTP On Stellar

cctp Stellar

Circle’s Cross-Chain Transfer Protocol (CCTP) has just been integrated with Stellar. It let’s us move assets between chains at 1:1. Burn on one chain, mint native USDC on the other. No bridge pool, no synthetic token, no liquidity overhead.

I’ve put together a demo at: https://github.com/jamesbachini/CCTP-Stellar

The repo has two working examples:

  • bridgeout.js – Burn testnet Stellar USDC, mint native USDC on EVM (Base Sepolia testnet).
  • bridgein.js – Burn EVM USDC, mint and forward USDC to a Stellar account.

The scripts are small and simple by design to show the moving parts: amount conversion, approvals, burn calls, attestation polling, final mint.

James On YouTube

How CCTP Works

  • Step 1: USDC is burned on the source chain through Circle’s contracts.
  • Step 2: Circle’s Iris attestation service detects the burn and signs a message confirming it.
  • Step 3: Someone (the app, a relayer, or a user with a terminal) submits the message and attestation on the destination chain.
  • Step 4: The destination contract verifies the signature and mints native USDC.

For Stellar inbound, the EVM burn targets CctpForwarder instead of a user address. The final Stellar recipient is packed into hookData. The forwarder handles the rest.

The Decimal Trap

Note that Stellar USDC has 7 decimals. EVM USDC has 6. CCTP amount fields use 6.

If you send 1 USDC from Stellar, that is 10000000 (7 decimals). The script converts it to 1000000 (6 decimals) before burning. Get it wrong and you either get Amount has more than 7 decimal places or Amount has more than 6 decimal places.

This is the most common error. Do not hide this conversion in your UI code.


Running The Scripts

NodeJS @ https://nodejs.org/

Stellar side: An account with testnet XLM, a USDC trustline (issuer GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5), and testnet USDC from Circle’s faucet.

EVM side: A wallet on Base Sepolia or Ethereum Sepolia with native gas and testnet USDC from faucet.circle.com.

Set STELLAR_CLIENT_PRIVATE_KEYDESTINATION_CHAINSOURCE_CHAINAMOUNT, and STELLAR_RECIPIENT in .env. Run node bridgeout.js or node bridgein.js.

If you bridge EVM -> Stellar and want the forwarder path, STELLAR_RECIPIENT is the final Stellar account, not the forwarder contract address. The script handles the encoding.

Get testnet funds for base at https://docs.base.org/base-chain/network-information/network-faucets

Get testnet funds for stellar at https://lab.stellar.org/account/fund

Once we have .env setup we can run the scripts via node.

Note the bridgein.js script takes longer to run while you wait for Circle attestation. There is a fast option as well if you want to pay a ~14bps fee.


Notes On Building With CCTP

CCTP is going to enable dApp builders seamless onboarding of funds from across various blockchain networks.

By enabling CCTP deposits and withdrawals we can make it as easy as possible for users to move USDC in and out of the Stellar network.

Note the scripts in this repo are basic examples, not a production relayer. Production needs job persistence, retry queues, idempotency, monitoring, rate-limit handling, and key management.

  • Persist the burn hash before polling. If your process crashes, resume from the hash instead of burning again. bridgein.js demonstrates this with SOURCE_TX_HASH.
  • Separate user transfer from relay. Anyone can submit the attested message on the destination chain. Let the user burn, let a backend watch Iris and complete.
  • Use least-privilege allowances. Approve only what you need. Larger approvals are a product and security decision.
  • Plan for replays. Destination mint_and_forward fails once a message is consumed. Treat that as a terminal state, not an error.
  • Don’t hardcode mainnet values. Contract addresses, domains, and fees change. Pull from Circle’s current docs or your own config registry.


Get The Blockchain Sector Newsletter, binge the YouTube channel and connect with me on Twitter

The Blockchain Sector newsletter goes out a few times a month when there is breaking news or interesting developments to discuss. All the content I produce is free, if you’d like to help please share this content on social media.

Thank you.

James Bachini

Disclaimer: Not a financial advisor, not financial advice. The content I create is to document my journey and for educational and entertainment purposes only. It is not under any circumstances investment advice. I am not an investment or trading professional and am learning myself while still making plenty of mistakes along the way. Any code published is experimental and not production ready to be used for financial transactions. Do your own research and do not play with funds you do not want to lose.


Posted

in

, , , ,

by

Tags: