Renderizado do repositório de origem, preservando títulos, exemplos, código, tabelas, links e imagens.
Cross-Chain on Stellar
Stellar connects to other blockchains over several production rails, each built for a different job. Picking the wrong rail wastes engineering effort; picking the right one is a routing decision, not a research project. This file routes; the deep dives live alongside it — read the file that matches the task:
| You want to | Use | Where |
|---|---|---|
| Move native USDC between Stellar and an EVM chain or Solana (no wrapped assets, no liquidity pools) | Circle CCTP V2 | cctp.md |
| Move native USDT between Stellar and an EVM chain | USDT0, a LayerZero OFT | layerzero.md |
| Have a Stellar contract call a contract on another chain, or receive calls from one (arbitrary payloads) | Axelar GMP or LayerZero OApp | axelar.md, layerzero.md |
| Make a token — new or an existing Stellar asset — exist on multiple chains | Axelar ITS or LayerZero OFT | axelar.md, layerzero.md |
| Swap any asset cross-chain (BTC, ETH, SOL, … → XLM or Stellar USDC) without integrating a bridge yourself | NEAR Intents | below |
Rules of thumb: if the asset is USDC and both ends are CCTP chains, CCTP is the cheapest and most direct (it burns and mints Circle-native USDC — nothing wrapped, nothing pooled). If the asset is USDT, the answer is USDT0 over LayerZero OFT — a different rail, and one whose shape changes per leg: Stellar burns and mints, while the Ethereum leg locks and unlocks canonical USDT through an OFT Adapter, so check the route's OFT mode before you describe the flow. If you need logic, not just value, on the far chain, that is message passing — two rails do it, and the comparison at the end of layerzero.md helps you pick between Axelar's shared validator security and LayerZero's app-configured DVN sets. If you control a token and want it multichain, that is ITS or OFT on the same split. If the user just wants "turn my X on chain A into Y on Stellar" and you don't want bridge plumbing at all, quote it through NEAR Intents.
When to use this skill
- Bridging USDC between Stellar and Ethereum, Base, Arbitrum, Solana, or another CCTP-supported chain
- Bridging USDT between Stellar and an EVM chain (USDT0 over LayerZero OFT)
- Receiving bridged USDC into a Stellar account or contract (and not bricking the funds — see the forwarder warning below)
- Writing a Stellar smart contract that sends messages to or receives messages from contracts on other chains
- Deploying an interchain token, or connecting an existing Stellar asset to other ecosystems
- Adding a "deposit from any chain" or cross-chain swap flow to a wallet or dapp
Related skills
- Trustlines, SAC deployment, asset anatomy →
../assets/SKILL.md - Writing the Stellar smart contracts that send/receive messages →
../smart-contracts/SKILL.md - Frontend transaction building, Freighter signing, RPC submission →
../dapp/SKILL.md - Watching for the destination-side mint or contract events →
../data/SKILL.md - Paying AI agents (x402/MPP) rather than bridging →
../agentic-payments/SKILL.md
Pitfalls shared by every rail
These bite regardless of which rail you pick. Each companion file adds rail-specific ones.
- Address formats do not translate. Stellar addresses are
strkeystrings (G…accounts,C…contracts,M…muxed); EVM uses 20-byte hex; Solana uses base58. Every rail defines its own encoding for foreign addresses (CCTP: raw 32-byte payloads; Axelar: strings + bytes payloads). Never paste an address from one chain into a field meant for another — encode it the way the rail specifies, and validate with the SDK (StrKey.isValidEd25519PublicKey/isValidContract) before encoding. - Decimals differ. Classic Stellar assets and their SACs use 7 decimals, but other Stellar token contracts (ITS-deployed tokens included) declare their own — call
decimals()instead of assuming. USDC is 6 on every supported chain except Stellar (which uses 7); EVM tokens are commonly 18; CCTP messages are always 6-decimal. Convert at every boundary and test with amounts that exercise the last digit (see the worked decimal examples in cctp.md). LayerZero OFTs add a second layer: an OFT declaresshared_decimals(6 for USDT0) alongside the token's local decimals, and silently drops the remainder below that precision on send — quote withquote_oftand trust itsOFTReceipt, not your input amount (see layerzero.md). - Classic Stellar recipients need a trustline first. A
G…account cannot receive an issued asset (USDC included) without a trustline to that asset. Bridged funds destined for an account without one will not land. Check and provision before starting the transfer — see../assets/SKILL.md. - Cross-chain is asynchronous. Every rail has a wait: CCTP waits for finality plus Circle's attestation (seconds to ~15 minutes depending on chain and finality threshold), Axelar waits for validator confirmation, intents wait for a market maker. Build UIs and agents around polling a status, never around "submit and assume".
- Testnet first, always. Do the full round-trip on testnet before touching mainnet — cross-chain mistakes are frequently unrecoverable by design (burns are final, and some misencodings permanently strand funds). Two rails cannot be rehearsed that way: NEAR Intents is filled by real market makers, and USDT0 publishes no testnet deployment even though LayerZero's testnet endpoint exists. For both, the rehearsal path is read-only quotes (
quote_oftandquote_sendfor USDT0, dry quotes for intents) followed by a dust-sized real transfer. LayerZero also has a testnet endpoint (EID40600) you can point your own OApp or OFT at, but confirm one testnet send actually delivers before you rely on it — see the status notes.
NEAR Intents (intent-based swaps)
Status-sensitive. Chain and asset support changes frequently — verify Stellar's current status in the NEAR Intents docs before building.
NEAR Intents is an intent protocol: the user states an outcome ("swap 0.1 BTC to USDC on Stellar"), market makers compete to execute it. Stellar (XLM and USDC) is a supported destination and source, which makes this the shortest path to "deposit from any chain" UX — there is no bridge contract to integrate on the Stellar side at all.
Integration is the 1Click API: POST /v0/quote with the asset pair returns a price and a deposit address; send funds there and market makers carry out the swap. GET /v0/tokens lists supported assets (the Stellar entries: XLM and USDC, 7-decimal), and a quote with "dry": true returns pricing and an ETA without creating a deposit commitment — probe pairs freely, commit later. Official SDKs exist for TypeScript, Go, and Rust.
Three Stellar-specific facts (verified against the live API):
- Stellar deposits are MEMO mode only, and the API enforces it. A Stellar-origin quote must set
"depositMode": "MEMO"— without it/v0/quoterejects withIncorrect depositMode for originAsset from stellar chain. The quote then returns a deposit address plus a memo (depositAddress+depositMemo), and the memo is what routes your funds to your swap. A deposit without the memo is not credited — treat the memo as part of the address, and refuse to display one without the other. - There is no testnet. Intents are filled by real market makers with real liquidity, so the rehearsal path is dry quotes followed by a dust-sized real swap — not a testnet round trip.
- Registering for an API key via the partners portal removes the default integrator fee; anonymous use works but is surcharged (it shows up in the quoted spread).
For anything deeper (quote parameters, slippage, refund handling), work from the live 1Click API docs rather than this file — the protocol iterates quickly.

