Skip to content

semiotic-ai/cctp-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

43 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

cctp-rs

Crates.io Documentation License Build Status

A production-ready Rust implementation of Circle's Cross-Chain Transfer Protocol (CCTP), enabling seamless USDC transfers across blockchain networks.

Features

  • πŸš€ Type-safe contract interactions using Alloy
  • πŸ”„ Multi-chain support for mainnet and testnet networks
  • πŸ“¦ Builder pattern for intuitive API usage

Supported Chains

Mainnet

  • Ethereum
  • Arbitrum
  • Base
  • Optimism
  • Avalanche
  • Polygon
  • Unichain

Testnet

  • Sepolia
  • Arbitrum Sepolia
  • Base Sepolia
  • Optimism Sepolia
  • Avalanche Fuji
  • Polygon Amoy

Quick Start

Add to your Cargo.toml:

[dependencies]
cctp-rs = "0.3.0"

Basic Example

use cctp_rs::{Cctp, CctpError};
use alloy_chains::NamedChain;
use alloy_primitives::{Address, U256};
use alloy_provider::{Provider, ProviderBuilder};

#[tokio::main]
async fn main() -> Result<(), CctpError> {
    // Create providers for source and destination chains
    let eth_provider = ProviderBuilder::new()
        .on_http("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY".parse()?);
    
    let arb_provider = ProviderBuilder::new()
        .on_http("https://arb-mainnet.g.alchemy.com/v2/YOUR_API_KEY".parse()?);

    // Set up the CCTP bridge
    let bridge = Cctp::builder()
        .source_chain(NamedChain::Mainnet)
        .destination_chain(NamedChain::Arbitrum)
        .source_provider(eth_provider)
        .destination_provider(arb_provider)
        .recipient("0xYourRecipientAddress".parse()?)
        .build();

    // Get contract addresses
    let token_messenger = bridge.token_messenger_contract()?;
    let destination_domain = bridge.destination_domain_id()?;
    
    println!("Token Messenger: {}", token_messenger);
    println!("Destination Domain: {}", destination_domain);
    
    Ok(())
}

Bridging USDC

use cctp_rs::{Cctp, BridgeParams, CctpError};
use alloy_chains::NamedChain;
use alloy_primitives::{Address, U256};

async fn bridge_usdc(bridge: &Cctp<impl Provider>) -> Result<(), CctpError> {
    // Step 1: Prepare bridge parameters
    let params = BridgeParams::builder()
        .from_address("0xYourAddress".parse()?)
        .recipient("0xRecipientAddress".parse()?)
        .token_address("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48".parse()?) // USDC on Ethereum
        .amount(U256::from(1_000_000)) // 1 USDC (6 decimals)
        .build();

    // Step 2: Approve USDC spending (implement this based on your provider)
    // approve_usdc_spending(&params).await?;

    // Step 3: Burn USDC on source chain (get tx hash)
    let burn_tx_hash = "0x...".parse()?; // From your burn transaction

    // Step 4: Get message and attestation
    let (message, message_hash) = bridge.get_message_sent_event(burn_tx_hash).await?;
    
    // Step 5: Wait for attestation
    let attestation = bridge.get_attestation(&message_hash, None, None).await?;
    
    println!("Bridge successful! Attestation: {:?}", attestation);
    
    // Step 6: Mint on destination chain using the attestation
    // mint_on_destination(&message, &attestation).await?;
    
    Ok(())
}

Architecture

The library is organized into several key modules:

  • bridge - Core CCTP bridge implementation
  • chain - Chain-specific configurations and support
  • attestation - Attestation response types from Circle's Iris API
  • error - Comprehensive error types for proper error handling
  • contracts - Type-safe bindings for TokenMessenger and MessageTransmitter

Error Handling

cctp-rs provides detailed error types for different failure scenarios:

use cctp_rs::{CctpError, Cctp};

match bridge.get_attestation(&message_hash, None, None).await {
    Ok(attestation) => println!("Success: {:?}", attestation),
    Err(CctpError::AttestationTimeout) => println!("Timeout waiting for attestation"),
    Err(CctpError::ChainNotSupported { chain }) => println!("Chain {} not supported", chain),
    Err(e) => println!("Other error: {}", e),
}

Advanced Usage

Custom Polling Configuration

// Wait up to 10 minutes with 30-second intervals
let attestation = bridge.get_attestation(
    &message_hash,
    Some(20),        // max attempts
    Some(30),        // poll interval in seconds
).await?;

Chain Configuration

use cctp_rs::CctpV1;
use alloy_chains::NamedChain;

// Get chain-specific information
let chain = NamedChain::Arbitrum;
let confirmation_time = chain.confirmation_average_time_seconds()?;
let domain_id = chain.cctp_domain_id()?;
let token_messenger = chain.token_messenger_address()?;

println!("Arbitrum confirmation time: {} seconds", confirmation_time);
println!("Domain ID: {}", domain_id);
println!("Token Messenger: {}", token_messenger);

Examples

Check out the examples/ directory for complete working examples:

Run examples with:

cargo run --example basic_bridge

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Testing

Run the test suite:

cargo test

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Acknowledgments

  • Circle for creating CCTP
  • Alloy for the excellent Ethereum libraries
  • The Rust community for amazing tools and support

Resources

About

Rust implementation of Circle CCTP

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •  

Languages