> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/circlefin/evm-cctp-contracts/llms.txt
> Use this file to discover all available pages before exploring further.

# IRelayer

> Interface for sending cross-chain messages from source to destination domains

## Overview

The `IRelayer` interface defines the contract for sending cross-chain messages from the source domain to destination domains. It manages message formatting, nonce assignment, and event emission to enable off-chain attestation and delivery.

## Interface Definition

### IRelayer (V1)

```solidity theme={null}
interface IRelayer {
    function sendMessage(
        uint32 destinationDomain,
        bytes32 recipient,
        bytes calldata messageBody
    ) external returns (uint64);

    function sendMessageWithCaller(
        uint32 destinationDomain,
        bytes32 recipient,
        bytes32 destinationCaller,
        bytes calldata messageBody
    ) external returns (uint64);

    function replaceMessage(
        bytes calldata originalMessage,
        bytes calldata originalAttestation,
        bytes calldata newMessageBody,
        bytes32 newDestinationCaller
    ) external;
}
```

**Source:** `src/interfaces/IRelayer.sol:22`

### IRelayerV2

V2 simplifies the interface with a single unified send function that includes finality parameters:

```solidity theme={null}
interface IRelayerV2 {
    function sendMessage(
        uint32 destinationDomain,
        bytes32 recipient,
        bytes32 destinationCaller,
        uint32 minFinalityThreshold,
        bytes calldata messageBody
    ) external;
}
```

**Source:** `src/interfaces/v2/IRelayerV2.sol:24`

## Functions

### sendMessage (V1)

```solidity theme={null}
function sendMessage(
    uint32 destinationDomain,
    bytes32 recipient,
    bytes calldata messageBody
) external returns (uint64);
```

Sends an outgoing message to the destination domain, allowing any caller to deliver it.

**Parameters:**

* `destinationDomain` - The domain ID of the destination chain
* `recipient` - The address of the message recipient on the destination domain (as bytes32)
* `messageBody` - The raw bytes content of the message payload

**Returns:**

* The nonce reserved for this message

**Behavior:**

* Increments the nonce counter
* Formats the complete message with header
* Emits `MessageSent` event for attesters to observe
* Any address can call `receiveMessage` on the destination

### sendMessageWithCaller (V1)

```solidity theme={null}
function sendMessageWithCaller(
    uint32 destinationDomain,
    bytes32 recipient,
    bytes32 destinationCaller,
    bytes calldata messageBody
) external returns (uint64);
```

Sends an outgoing message with a restricted destination caller.

**Parameters:**

* `destinationDomain` - The domain ID of the destination chain
* `recipient` - The address of the message recipient (as bytes32)
* `destinationCaller` - The only address allowed to deliver this message (as bytes32)
* `messageBody` - The raw bytes content of the message

**Returns:**

* The nonce reserved for this message

**Warning:**
If `destinationCaller` does not represent a valid address, the message cannot be delivered on the destination domain. Use the standard `sendMessage()` when a specific caller is not required.

### replaceMessage (V1)

```solidity theme={null}
function replaceMessage(
    bytes calldata originalMessage,
    bytes calldata originalAttestation,
    bytes calldata newMessageBody,
    bytes32 newDestinationCaller
) external;
```

Replaces a previously sent message with a new message body and/or destination caller.

**Parameters:**

* `originalMessage` - The original message bytes to replace
* `originalAttestation` - Valid attestation of the original message
* `newMessageBody` - The new message body content
* `newDestinationCaller` - The new destination caller (or bytes32(0) for any caller)

**Requirements:**

* `originalAttestation` must be a valid attestation of `originalMessage`
* Original message must not have been received yet on destination
* Replacement reuses the original message's nonce

**Use Cases:**

* Update recipient address before message is delivered
* Change destination caller permissions
* Modify message content while preserving nonce

### sendMessage (V2)

```solidity theme={null}
function sendMessage(
    uint32 destinationDomain,
    bytes32 recipient,
    bytes32 destinationCaller,
    uint32 minFinalityThreshold,
    bytes calldata messageBody
) external;
```

Sends an outgoing message with finality requirements.

**Parameters:**

* `destinationDomain` - The domain ID of the destination chain
* `recipient` - The message recipient address (as bytes32)
* `destinationCaller` - Allowed caller on destination (bytes32(0) for any caller)
* `minFinalityThreshold` - Minimum finality threshold for attestation
* `messageBody` - The message payload

**Warning:**
If `destinationCaller` is not a valid address as bytes32, the message cannot be delivered. Use bytes32(0) to allow any caller.

## Relayer Role in Message Delivery

### Message Lifecycle

```
┌──────────────┐
│ Source Chain │
└──────┬───────┘
       │
       │ 1. sendMessage()
       ▼
┌─────────────────┐
│    IRelayer     │
│(MessageTransmitter)
└────────┬────────┘
         │ 2. Emit MessageSent event
         │
         ▼
┌─────────────────┐
│  Circle API     │
│  (Attesters)    │
└────────┬────────┘
         │ 3. Observe event
         │ 4. Generate attestation
         ▼
┌─────────────────┐
│  Relayer/User   │
│  (Off-chain)    │
└────────┬────────┘
         │ 5. Fetch attestation
         │ 6. Call receiveMessage()
         ▼
┌─────────────────┐
│ Destination     │
│     Chain       │
└─────────────────┘
```

### Relayer Responsibilities

1. **Message Observation**
   * Monitor `MessageSent` events on source chains
   * Track messages that need delivery

2. **Attestation Retrieval**
   * Query Circle's attestation API
   * Wait for attestation to be available
   * Verify attestation validity

3. **Message Delivery**
   * Call `receiveMessage()` on destination chain
   * Include message and attestation as parameters
   * Pay gas costs for destination transaction

4. **Status Tracking**
   * Monitor delivery success/failure
   * Handle retries if needed
   * Track delivery receipts

### MessageSent Event

```solidity theme={null}
event MessageSent(
    bytes message
);
```

Emitted when a message is sent, containing the complete formatted message:

```solidity theme={null}
// Message structure in event
struct Message {
    uint32 version;
    uint32 sourceDomain;
    uint32 destinationDomain;
    uint64 nonce;
    bytes32 sender;
    bytes32 recipient;
    bytes32 destinationCaller;
    bytes messageBody;
}
```

Relayers parse this event to:

* Extract message hash for attestation API
* Get destination domain for routing
* Identify recipient and caller restrictions

## Fee Handling in V2

### Relayer Fee Model

V2 introduces built-in support for relayer fees through multi-recipient minting:

```solidity theme={null}
// On source chain - user pays amount + fee
uint256 userAmount = 100e6;  // 100 USDC to recipient
uint256 relayerFee = 5e6;    // 5 USDC to relayer

// Burn total amount
tokenMessenger.depositForBurn(
    userAmount + relayerFee,
    destinationDomain,
    recipientBytes32,
    usdcAddress
);

// Message body encodes split
bytes memory messageBody = encodeMessageWithFee(
    recipient,
    userAmount,
    relayerAddress,
    relayerFee
);

relayer.sendMessage(
    destinationDomain,
    tokenMessengerBytes32,
    bytes32(0),  // Any caller
    2000,        // Finalized threshold
    messageBody
);
```

### Fee Distribution on Destination

```solidity theme={null}
// TokenMessengerV2 handles split
function handleReceiveMessage(
    uint32 sourceDomain,
    bytes32 sender,
    bytes calldata messageBody
) external returns (bool) {
    // Decode message with fee split
    (address recipient, uint256 amount, address relayer, uint256 fee) = 
        _decodeMessageWithFee(messageBody);
    
    // Mint to both recipients atomically
    tokenMinterV2.mint(
        sourceDomain,
        burnToken,
        recipient,  // User receives 100 USDC
        relayer,    // Relayer receives 5 USDC
        amount,
        fee
    );
    
    return true;
}
```

### Dynamic Fee Calculation

Relayers can implement dynamic fee models:

```solidity theme={null}
function calculateRelayerFee(
    uint32 destDomain,
    uint256 amount,
    uint32 priorityLevel
) external view returns (uint256 fee) {
    // Base fee by destination
    uint256 baseFee = destinationBaseFees[destDomain];
    
    // Percentage fee
    uint256 percentFee = (amount * feePercent) / 10000;
    
    // Priority multiplier
    uint256 priorityMultiplier = priorityLevel > 0 ? 2 : 1;
    
    return (baseFee + percentFee) * priorityMultiplier;
}
```

### Fee Payment Options

**Option 1: Pre-paid (V1 & V2)**

```solidity theme={null}
// User pays relayer off-chain (fiat, other tokens)
// Relayer delivers message for free
relayer.sendMessage(destDomain, recipient, messageBody);
```

**Option 2: Fee-on-delivery (V2)**

```solidity theme={null}
// User includes fee in burn amount
// Relayer receives payment on destination
tokenMessengerV2.depositForBurnWithFee(
    amount,
    fee,
    destDomain,
    recipient,
    relayerAddress,
    burnToken
);
```

**Option 3: Sponsored (V1 & V2)**

```solidity theme={null}
// Application sponsors user transactions
// Application acts as relayer
myDApp.sponsoredTransfer(user, amount, destDomain);
```

## Usage Examples

### Basic Message Send (V1)

```solidity theme={null}
// Send USDC burn message
IRelayer relayer = IRelayer(messageTransmitter);

bytes memory burnMessage = encodeBurnMessage(
    burnToken,
    recipient,
    amount,
    sender
);

uint64 nonce = relayer.sendMessage(
    0,           // Ethereum destination
    tokenMessengerBytes32,
    burnMessage
);
```

### Restricted Caller (V1)

```solidity theme={null}
// Only specific relayer can deliver
uint64 nonce = relayer.sendMessageWithCaller(
    0,           // Ethereum destination
    tokenMessengerBytes32,
    authorizedRelayerBytes32,
    burnMessage
);
```

### Message Replacement (V1)

```solidity theme={null}
// Change recipient before delivery
relayer.replaceMessage(
    originalMessage,
    originalAttestation,
    newBurnMessageWithUpdatedRecipient,
    bytes32(0)  // Keep caller restriction unchanged
);
```

### Finality-Aware Send (V2)

```solidity theme={null}
// Require high finality for large transfer
relayer.sendMessage(
    0,           // Ethereum destination
    recipient,
    bytes32(0),  // Any caller
    2500,        // High finality threshold
    messageBody
);

// Allow fast delivery for small transfer
relayer.sendMessage(
    0,
    recipient,
    bytes32(0),
    1000,        // Lower finality threshold
    messageBody
);
```

## Security Considerations

### Nonce Management

* Each message receives a unique, incrementing nonce
* Nonces prevent replay attacks
* Nonce is included in message hash for attestation

### Destination Caller Validation

```solidity theme={null}
// Validate caller if specified
if (destinationCaller != bytes32(0)) {
    require(
        destinationCaller == addressToBytes32(msg.sender),
        "Unauthorized caller"
    );
}
```

### Message Immutability

* Once attested, message content is cryptographically sealed
* Replacement creates new attestation for same nonce
* First delivered message at a nonce wins

### Domain Validation

* Destination domain must be registered and supported
* Source domain is automatically set to local domain
* Cross-domain validation prevents misrouting

## Related Interfaces

* [IReceiver](/api/interfaces/receiver) - Receives messages sent by relayers
* [IMessageHandler](/api/interfaces/message-handler) - Processes message content after receipt
* [MessageTransmitter](/api/message-transmitter) - Implements IRelayer for CCTP
