Skip to main content

Overview

The IrisClient provides methods for fetching attestations from Circle’s Iris API, which is required to complete cross-chain USDC transfers. After burning USDC on the source chain, you must obtain an attestation from Iris before minting on the destination chain.

IrisClient Type

client.go:79
type IrisClient struct {
    baseURL    string
    httpClient *http.Client
}
baseURL
string
required
Base URL for the Iris API (mainnet or testnet)
httpClient
*http.Client
HTTP client with 30-second timeout

Creating a Client

client.go:86
func NewIrisClient(baseURL string) *IrisClient
client := cctp.NewIrisClient("https://iris-api.circle.com")

Core Methods

GetMessages

Fetch messages and attestations for a specific transaction:
client.go:95
func (c *IrisClient) GetMessages(
    ctx context.Context,
    sourceDomain uint32,
    txHash string,
) (*MessagesResponse, error)
ctx
context.Context
required
Context for cancellation and timeout
sourceDomain
uint32
required
CCTP domain of the source chain
txHash
string
required
Transaction hash of the burn transaction
resp, err := client.GetMessages(
    ctx,
    0, // Ethereum domain
    "0x1234...",
)
if err != nil {
    log.Fatal(err)
}

if len(resp.Messages) > 0 {
    msg := resp.Messages[0]
    fmt.Printf("Status: %s\n", msg.Status)
    fmt.Printf("Attestation: %s\n", msg.Attestation)
}

PollForAttestation

Poll for an attestation until it’s ready or context is cancelled:
client.go:162
func (c *IrisClient) PollForAttestation(
    ctx context.Context,
    sourceDomain uint32,
    txHash string,
    progressCallback func(attempt int, elapsed time.Duration),
) (*Message, error)
ctx
context.Context
required
Context for cancellation and timeout
sourceDomain
uint32
required
CCTP domain of the source chain
txHash
string
required
Transaction hash of the burn transaction
progressCallback
func(int, time.Duration)
Optional callback invoked on each polling attempt
msg, err := client.PollForAttestation(
    ctx,
    0, // Ethereum
    burnTxHash,
    nil, // No progress callback
)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Attestation received: %s\n", msg.Attestation)
The polling function implements exponential backoff (2s → 4s → 8s → 10s max) and handles transient 404 errors during indexing.

GetTransferFees

Query fee information for transfers between domains:
client.go:234
func (c *IrisClient) GetTransferFees(
    ctx context.Context,
    sourceDomain uint32,
    destDomain uint32,
) (*FeesResponse, error)
ctx
context.Context
required
Context for cancellation and timeout
sourceDomain
uint32
required
Source chain CCTP domain
destDomain
uint32
required
Destination chain CCTP domain
feesResp, err := client.GetTransferFees(
    ctx,
    0, // Ethereum
    1, // Avalanche
)
if err != nil {
    log.Fatal(err)
}

for _, feeInfo := range feesResp.Data {
    fmt.Printf("Threshold %d: %d bps\n",
        feeInfo.FinalityThreshold,
        feeInfo.MinimumFee,
    )
}
Fees are returned in basis points (bps). For example, 14 bps = 0.14% fee.

Attestation Status

Attestation status indicates whether an attestation is ready:
client.go:31
type AttestationStatus string

const (
    AttestationStatusPending  AttestationStatus = "pending"
    AttestationStatusComplete AttestationStatus = "complete"
)

Error Handling

The Iris API enforces rate limits. A 429 status code indicates rate limiting.
msg, err := client.GetMessages(ctx, domain, txHash)
if err != nil {
    if strings.Contains(err.Error(), "429") {
        log.Println("Rate limited - wait 5 minutes before retrying")
    }
    return err
}

Estimated Attestation Times

Helper function to estimate attestation time based on chain characteristics:
client.go:266
func EstimatedAttestationTime(instantFinality bool) time.Duration
// For instant finality chains (Avalanche, Polygon, etc.)
if sourceChain.InstantFinality {
    estimate := cctp.EstimatedAttestationTime(true)
    fmt.Printf("Expected attestation in ~%s\n", estimate) // ~10 seconds
}

// For standard EVM chains
estimate := cctp.EstimatedAttestationTime(false)
fmt.Printf("Expected attestation in ~%s\n", estimate) // ~15 seconds for Fast Transfer

Best Practices

1

Use Context Timeouts

Always set reasonable timeouts to prevent indefinite waiting:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
2

Handle 404 Errors

The API may return 404 immediately after a burn transaction while indexing. The PollForAttestation function handles this automatically.
3

Check Attestation Status

Verify that msg.Status == AttestationStatusComplete and msg.Attestation != "" before proceeding to mint.
4

Implement Retry Logic

Handle transient network errors with exponential backoff:
for attempt := 1; attempt <= 3; attempt++ {
    msg, err := client.GetMessages(ctx, domain, txHash)
    if err == nil {
        break
    }
    time.Sleep(time.Duration(attempt) * time.Second)
}

Next Steps

Transfer Orchestrator

See how IrisClient is used in the complete transfer flow

Contract Bindings

Use attestations with MessageTransmitterV2

Build docs developers (and LLMs) love