cctp-rs 5.0.0

Type-safe Rust SDK for Circle's Cross-Chain Transfer Protocol (CCTP) v1 and v2 — bridge USDC across 26+ EVM chains with fast transfer support.
Documentation
// SPDX-FileCopyrightText: 2025 Semiotic AI, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//! # cctp-rs
//!
//! A production-ready Rust SDK for Circle's Cross-Chain Transfer Protocol (CCTP).
//!
//! This library provides a safe, ergonomic interface for bridging USDC across
//! multiple blockchain networks using Circle's CCTP infrastructure.
//!
//! ## Choosing an API
//!
//! | Task                                                | Type                                |
//! |-----------------------------------------------------|-------------------------------------|
//! | Bridge USDC (recommended)                           | [`CctpV2Bridge`]                    |
//! | Bridge USDC on a v1-only legacy chain               | [`Cctp`]                            |
//! | Self-relay safely against permissionless relayers   | [`CctpV2Bridge::mint_if_needed`]    |
//! | Wait for any relayer (cheapest happy path)          | [`CctpV2Bridge::wait_for_receive`]  |
//! | Inspect a v2 message as serializable JSON           | [`ParsedV2MessageSummary`]          |
//! | Look up chain config without a provider             | [`CctpV1`] / [`CctpV2`] traits      |
//! | Drive contracts directly                            | [`TokenMessengerV2Contract`] etc.   |
//!
//! For longer-form guidance and the full list of footguns see `AGENTS.md` in
//! the repository.
//!
//! ## Quick Start (V2, recommended)
//!
//! ```rust,no_run
//! use cctp_rs::{CctpV2Bridge, CctpError, PollingConfig};
//! use alloy_chains::NamedChain;
//! use alloy_primitives::FixedBytes;
//!
//! # async fn example() -> Result<(), CctpError> {
//! # use alloy_provider::ProviderBuilder;
//! // V2 bridge with fast transfer support
//! let eth_provider = ProviderBuilder::new().connect("http://localhost:8545").await?;
//! let linea_provider = ProviderBuilder::new().connect("http://localhost:8546").await?;
//!
//! let bridge = CctpV2Bridge::builder()
//!     .source_chain(NamedChain::Mainnet)
//!     .destination_chain(NamedChain::Linea)
//!     .source_provider(eth_provider)
//!     .destination_provider(linea_provider)
//!     .recipient("0x742d35Cc6634C0532925a3b844Bc9e7595f8fA0d".parse()?)
//!     .fast_transfer(true)  // Enable sub-30 second settlement
//!     .build();
//!
//! // V2 uses transaction hash directly and returns both message and attestation
//! let burn_tx_hash = FixedBytes::from([0u8; 32]);
//! let (message, attestation) = bridge.get_attestation(
//!     burn_tx_hash,
//!     PollingConfig::fast_transfer(),  // Optimized for fast transfers
//! ).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Quick Start (V1, legacy v1-only chains)
//!
//! ```rust,no_run
//! use cctp_rs::{Cctp, CctpError, PollingConfig};
//! use alloy_chains::NamedChain;
//! use alloy_primitives::FixedBytes;
//!
//! # async fn example() -> Result<(), CctpError> {
//! # use alloy_provider::ProviderBuilder;
//! // Set up providers and create bridge
//! let eth_provider = ProviderBuilder::new().connect("http://localhost:8545").await?;
//! let arb_provider = ProviderBuilder::new().connect("http://localhost:8546").await?;
//!
//! let bridge = Cctp::builder()
//!     .source_chain(NamedChain::Mainnet)
//!     .destination_chain(NamedChain::Arbitrum)
//!     .source_provider(eth_provider)
//!     .destination_provider(arb_provider)
//!     .recipient("0x742d35Cc6634C0532925a3b844Bc9e7595f8fA0d".parse()?)
//!     .build();
//!
//! // Get message from burn transaction, then fetch attestation
//! let burn_tx_hash = FixedBytes::from([0u8; 32]);
//! let (message, message_hash) = bridge.get_message_sent_event(burn_tx_hash).await?;
//! let attestation = bridge.get_attestation(message_hash, PollingConfig::default()).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Direct Contract Access
//!
//! For advanced use cases, you can use the contract wrappers directly:
//!
//! ```rust,no_run
//! use cctp_rs::{TokenMessengerV2Contract, MessageTransmitterV2Contract};
//! use alloy_primitives::address;
//! use alloy_provider::ProviderBuilder;
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = ProviderBuilder::new().connect("http://localhost:8545").await?;
//! let contract_address = address!("9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5");
//!
//! // Create contract wrapper
//! let token_messenger = TokenMessengerV2Contract::new(contract_address, provider);
//! # Ok(())
//! # }
//! ```
//!
//! ## Features
//!
//! - **Type-safe contract interactions** using Alloy
//! - **Multi-chain support** for mainnet and testnet networks
//! - **Comprehensive error handling** with detailed error types
//! - **Builder pattern** for intuitive API usage
//! - **Agent-friendly protocol inspection** with serializable v2 message parsing
//! - **Extensive test coverage** ensuring reliability
//!
//! ## Public API
//!
//! - [`AttestationResponse`] and [`AttestationStatus`] - Circle's Iris API attestation types
//! - [`Cctp`] and [`CctpV2Bridge`] - Core CCTP bridge implementations for v1 and v2
//! - [`CctpV1`] and [`CctpV2`] - Traits for chain-specific configurations
//! - [`PollingConfig`] - Configuration for attestation polling behavior
//! - [`ParsedV2Message`] and [`ParsedV2MessageSummary`] - Parse canonical v2 messages into serializable structs
//! - [`ParseMessageError`] - Error type for canonical v2 message parsing
//! - [`InvalidDomainId`] and [`InvalidFinalityThreshold`] - Errors returned by `TryFrom<u32>` for [`DomainId`] / [`FinalityThreshold`]
//! - [`CctpError`] and [`Result`] - Error types for error handling
//! - Contract wrappers for direct contract interaction:
//!   - v1: [`TokenMessengerContract`], [`MessageTransmitterContract`]
//!   - v2: [`TokenMessengerV2Contract`], [`MessageTransmitterV2Contract`]

mod bridge;
mod chain;
mod contracts;
mod error;
mod protocol;
mod provider;

// Public API - minimal surface for 1.0.0 stability
pub use bridge::{
    batch_token_state, Cctp, CctpBridge, CctpV2 as CctpV2Bridge, MintResult, PollingConfig,
    TokenState,
};
pub use chain::addresses::{
    CCTP_V2_MESSAGE_TRANSMITTER_MAINNET, CCTP_V2_MESSAGE_TRANSMITTER_TESTNET,
    CCTP_V2_TOKEN_MESSENGER_MAINNET, CCTP_V2_TOKEN_MESSENGER_TESTNET,
};
pub use chain::{CctpV1, CctpV2};
pub use contracts::{
    erc20::Erc20Contract,
    message_transmitter::MessageTransmitterContract,
    token_messenger::TokenMessengerContract,
    v2::{MessageTransmitterV2Contract, TokenMessengerV2Contract},
};
pub use error::{AttestationFailureKind, CctpError, Result};
pub use protocol::{
    AttestationBytes, AttestationResponse, AttestationStatus, BurnMessageV2, DomainId,
    FinalityThreshold, InvalidDomainId, InvalidFinalityThreshold, MessageHeader, ParseMessageError,
    ParsedV2Message, ParsedV2MessageSummary, V2AttestationResponse, V2Message,
};
pub use provider::{
    calculate_gas_price_with_buffer, estimate_gas_with_buffer, ProviderConfig,
    ProviderConfigBuilder, DEFAULT_GAS_BUFFER_PERCENT, DEFAULT_RETRY_ATTEMPTS,
    DEFAULT_TIMEOUT_SECS,
};

// Public module for advanced users who need custom instrumentation
pub mod spans;