> ## 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.

# BurnMessage Format

> BurnMessage structure for token transfer message bodies

The BurnMessage library defines the format for the message body used in CCTP token transfers. This message is embedded within the main Message's `messageBody` field.

## BurnMessage Structure

<ParamField path="version" type="uint32" required>
  Message body version (4 bytes)
</ParamField>

<ParamField path="burnToken" type="bytes32" required>
  Address of the burned token on the source domain (32 bytes, starting at index 4)
</ParamField>

<ParamField path="mintRecipient" type="bytes32" required>
  Address that will receive minted tokens on destination domain (32 bytes, starting at index 36)
</ParamField>

<ParamField path="amount" type="uint256" required>
  Amount of tokens burned (32 bytes, starting at index 68)
</ParamField>

<ParamField path="messageSender" type="bytes32" required>
  Address that initiated the burn (32 bytes, starting at index 100)
</ParamField>

## Memory Layout (V1)

```
Field                 Bytes      Type       Index
-----------------------------------------------
version               4          uint32     0
burnToken             32         bytes32    4
mintRecipient         32         bytes32    36
amount                32         uint256    68
messageSender         32         bytes32    100

Total: 132 bytes (fixed size)
```

Source: \~/workspace/source/src/messages/BurnMessage.sol:23-30

## BurnMessage V2 Format

Version 2 adds fee handling and hook support:

```
Field                 Bytes      Type       Index
-----------------------------------------------
version               4          uint32     0
burnToken             32         bytes32    4
mintRecipient         32         bytes32    36
amount                32         uint256    68
messageSender         32         bytes32    100
maxFee                32         uint256    132
feeExecuted           32         uint256    164
expirationBlock       32         uint256    196
hookData              dynamic    bytes      228
```

Source: \~/workspace/source/src/messages/v2/BurnMessageV2.sol:26-37

### V2 Additions

<ParamField path="maxFee" type="uint256">
  Maximum fee the sender is willing to pay on the destination domain (32 bytes, starting at index 132)
</ParamField>

<ParamField path="feeExecuted" type="uint256">
  Actual fee charged during execution (set to 0 during message creation, populated on destination)
</ParamField>

<ParamField path="expirationBlock" type="uint256">
  Block number after which the message expires (set to 0 during message creation)
</ParamField>

<ParamField path="hookData" type="bytes">
  Optional dynamic data passed to hooks for custom processing on destination domain
</ParamField>

## Encoding Functions

### Format Burn Message (V1)

Source: \~/workspace/source/src/messages/BurnMessage.sol:57-72

```solidity theme={null}
function _formatMessage(
    uint32 _version,
    bytes32 _burnToken,
    bytes32 _mintRecipient,
    uint256 _amount,
    bytes32 _messageSender
) internal pure returns (bytes memory)
```

Creates a V1 burn message with exactly 132 bytes.

**Parameters:**

* `_version`: Message body version
* `_burnToken`: Burned token address on source domain (as bytes32)
* `_mintRecipient`: Recipient address on destination domain (as bytes32)
* `_amount`: Amount burned
* `_messageSender`: Address that initiated the burn (as bytes32)

**Returns:** Formatted 132-byte burn message

### Format Burn Message for Relay (V2)

Source: \~/workspace/source/src/messages/v2/BurnMessageV2.sol:68-89

```solidity theme={null}
function _formatMessageForRelay(
    uint32 _version,
    bytes32 _burnToken,
    bytes32 _mintRecipient,
    uint256 _amount,
    bytes32 _messageSender,
    uint256 _maxFee,
    bytes calldata _hookData
) internal pure returns (bytes memory)
```

Creates a V2 burn message with fee and hook support.

**Parameters:**

* `_version`: Message body version
* `_burnToken`: Burned token address (as bytes32)
* `_mintRecipient`: Recipient address (as bytes32)
* `_amount`: Amount burned
* `_messageSender`: Initiator address (as bytes32)
* `_maxFee`: Maximum fee for destination processing
* `_hookData`: Optional hook data for custom logic

**Returns:** Formatted burn message (minimum 228 bytes + hookData length)

<Info>
  `feeExecuted` and `expirationBlock` are set to 0 during message creation. These fields are populated during attestation and execution.
</Info>

## Decoding Functions

### V1 Getters

Source: \~/workspace/source/src/messages/BurnMessage.sol

```solidity theme={null}
// Get message version
function _getVersion(bytes29 _message) internal pure returns (uint32)

// Get burned token address
function _getBurnToken(bytes29 _message) internal pure returns (bytes32)

// Get mint recipient address
function _getMintRecipient(bytes29 _message) internal pure returns (bytes32)

// Get burned amount
function _getAmount(bytes29 _message) internal pure returns (uint256)

// Get message sender address
function _getMessageSender(bytes29 _message) internal pure returns (bytes32)
```

### V2 Getters

V2 inherits V1 getters and adds:

Source: \~/workspace/source/src/messages/v2/BurnMessageV2.sol

```solidity theme={null}
// Inherited V1 getters
function _getVersion(bytes29 _message) internal pure returns (uint32)
function _getBurnToken(bytes29 _message) internal pure returns (bytes32)
function _getMintRecipient(bytes29 _message) internal pure returns (bytes32)
function _getAmount(bytes29 _message) internal pure returns (uint256)
function _getMessageSender(bytes29 _message) internal pure returns (bytes32)

// V2-specific getters
function _getMaxFee(bytes29 _message) internal pure returns (uint256)
function _getFeeExecuted(bytes29 _message) internal pure returns (uint256)
function _getExpirationBlock(bytes29 _message) internal pure returns (uint256)
function _getHookData(bytes29 _message) internal pure returns (bytes29)
```

<Note>
  V2 uses BurnMessage as a library dependency, calling V1 functions internally (e.g., `_message._getVersion()`).
</Note>

## Validation

### V1 Validation

Source: \~/workspace/source/src/messages/BurnMessage.sol:131-134

```solidity theme={null}
function _validateBurnMessageFormat(bytes29 _message) internal pure {
    require(_message.isValid(), "Malformed message");
    require(_message.len() == BURN_MESSAGE_LEN, "Invalid message length");
}
```

Enforces exactly 132 bytes for V1 messages.

### V2 Validation

Source: \~/workspace/source/src/messages/v2/BurnMessageV2.sol:151-157

```solidity theme={null}
function _validateBurnMessageFormat(bytes29 _message) internal pure {
    require(_message.isValid(), "Malformed message");
    require(
        _message.len() >= HOOK_DATA_INDEX,
        "Invalid burn message: too short"
    );
}
```

Enforces minimum 228 bytes (allows variable-length hookData).

## TypedMemView Usage

BurnMessage uses TypedMemView for efficient parsing:

```solidity theme={null}
using TypedMemView for bytes;
using TypedMemView for bytes29;
```

* **indexUint(offset, length)**: Reads uint256/uint32 at byte offset
* **index(offset, length)**: Reads bytes32 at byte offset
* **slice(offset, length, type)**: Extracts subview for hookData

See [TypedMemView documentation](https://github.com/summa-tx/memview-sol) for details.

## Example Usage

### Encoding a V1 BurnMessage

```solidity theme={null}
import {BurnMessage} from "./messages/BurnMessage.sol";
import {AddressUtils} from "./messages/v2/AddressUtils.sol";

// Convert addresses
bytes32 tokenBytes = AddressUtils.toBytes32(usdcAddress);
bytes32 recipientBytes = AddressUtils.toBytes32(destinationAddress);
bytes32 senderBytes = AddressUtils.toBytes32(msg.sender);

// Format burn message
bytes memory burnMsg = BurnMessage._formatMessage(
    0,                // version
    tokenBytes,       // burn token
    recipientBytes,   // mint recipient
    1000000,          // amount (1 USDC with 6 decimals)
    senderBytes       // message sender
);

// burnMsg is exactly 132 bytes
```

### Encoding a V2 BurnMessage with Hooks

```solidity theme={null}
import {BurnMessageV2} from "./messages/v2/BurnMessageV2.sol";
import {AddressUtils} from "./messages/v2/AddressUtils.sol";

// Prepare hook data
bytes memory hookData = abi.encode(
    recipientContract,
    "customFunction(uint256)",
    additionalParams
);

// Format V2 burn message
bytes memory burnMsg = BurnMessageV2._formatMessageForRelay(
    1,                // version 1
    tokenBytes,       // burn token
    recipientBytes,   // mint recipient
    1000000,          // amount
    senderBytes,      // message sender
    5000,             // max fee (0.005 USDC)
    hookData          // hook data
);

// burnMsg is 228 + hookData.length bytes
```

### Decoding a BurnMessage

```solidity theme={null}
import {TypedMemView} from "@memview-sol/contracts/TypedMemView.sol";
import {BurnMessage} from "./messages/BurnMessage.sol";

using TypedMemView for bytes;
using BurnMessage for bytes29;

// Parse message body from main message
bytes29 messageBody = message._messageBody();

// Validate format
messageBody._validateBurnMessageFormat();

// Extract fields
uint32 version = messageBody._getVersion();
bytes32 burnToken = messageBody._getBurnToken();
bytes32 mintRecipient = messageBody._getMintRecipient();
uint256 amount = messageBody._getAmount();
bytes32 sender = messageBody._getMessageSender();

// Convert to addresses
address tokenAddress = AddressUtils.toAddress(burnToken);
address recipientAddress = AddressUtils.toAddress(mintRecipient);
```

### Decoding V2 with Fee and Hook Data

```solidity theme={null}
import {BurnMessageV2} from "./messages/v2/BurnMessageV2.sol";

using TypedMemView for bytes;
using BurnMessageV2 for bytes29;

bytes29 burnMessageView = messageBody.ref(0);

// Validate V2 format
burnMessageView._validateBurnMessageFormat();

// Extract V2-specific fields
uint256 maxFee = burnMessageView._getMaxFee();
uint256 feeExecuted = burnMessageView._getFeeExecuted();
uint256 expirationBlock = burnMessageView._getExpirationBlock();
bytes29 hookData = burnMessageView._getHookData();

// Process hook data if present
if (hookData.len() > 0) {
    // Decode and execute hook logic
    bytes memory hookBytes = hookData.clone();
    (address target, bytes memory callData) = abi.decode(hookBytes, (address, bytes));
    // Execute hook...
}
```

## Integration with Message

BurnMessage is embedded as the `messageBody` field in Message:

```solidity theme={null}
import {Message} from "./messages/Message.sol";
import {BurnMessage} from "./messages/BurnMessage.sol";

// Create burn message
bytes memory burnMsg = BurnMessage._formatMessage(...);

// Embed in main message
bytes memory fullMessage = Message._formatMessage(
    0,                  // message version
    sourceDomain,
    destinationDomain,
    nonce,
    sender,
    recipient,
    destinationCaller,
    burnMsg            // burn message as body
);
```

## See Also

* [Message Format](/api/messages/message) - Main message structure
* [AddressUtils](/api/messages/address-utils) - Address conversion utilities
* [TokenMessenger](/api/token-messenger) - Contract that creates burn messages
* [TokenMinter](/api/token-minter) - Contract that processes burn messages and mints tokens
