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

# AddressUtils

> Address conversion utilities for EVM and non-EVM compatibility

The AddressUtils library provides functions for converting between EVM addresses and bytes32 format. This enables cross-chain compatibility, allowing EVM chains to interact with non-EVM chains that use different address formats.

## Overview

CCTP uses `bytes32` for all address fields in messages to maintain compatibility across chains:

* **EVM chains**: 20-byte addresses are left-padded with 12 zero bytes
* **Non-EVM chains**: Native address formats can be encoded as bytes32

Two versions of the library exist:

* **AddressUtils**: Internal functions for use within contracts
* **AddressUtilsExternal**: External functions for off-chain or library linking

## AddressUtils (Internal)

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

Internal helper functions for address conversion.

### toBytes32

```solidity theme={null}
function toBytes32(address addr) internal pure returns (bytes32)
```

Converts an EVM address to bytes32 by left-padding with zeros (alignment-preserving cast).

**Parameters:**

* `addr`: The 20-byte EVM address to convert

**Returns:** The address as bytes32 (left-padded with 12 zero bytes)

**Implementation:**

```solidity theme={null}
return bytes32(uint256(uint160(addr)));
```

**Example:**

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

address wallet = 0x1234567890123456789012345678901234567890;
bytes32 walletBytes = AddressUtils.toBytes32(wallet);

// Result: 0x0000000000000000000000001234567890123456789012345678901234567890
//         |<--- 12 zero bytes --->|<------- 20 bytes address -------->|
```

### toAddress

```solidity theme={null}
function toAddress(bytes32 _buf) internal pure returns (address)
```

Converts bytes32 to an EVM address by taking the rightmost 20 bytes (alignment-preserving cast).

**Parameters:**

* `_buf`: The bytes32 value to convert

**Returns:** The rightmost 20 bytes as an EVM address

**Implementation:**

```solidity theme={null}
return address(uint160(uint256(_buf)));
```

<Warning>
  **Important Security Consideration:**

  Different `bytes32` values can map to the same address due to truncation of the leftmost 12 bytes. If address uniqueness is critical for your use case, you MUST validate that the first 12 bytes are zero-padding.

  ```solidity theme={null}
  // Both map to the same address:
  bytes32 value1 = 0x0000000000000000000000001234...7890;
  bytes32 value2 = 0xFFFFFFFFFFFFFFFFFFFFFFFF1234...7890;

  address addr1 = AddressUtils.toAddress(value1); // 0x1234...7890
  address addr2 = AddressUtils.toAddress(value2); // 0x1234...7890 (same!)

  // To enforce uniqueness:
  require(
      uint256(_buf) >> 160 == 0,
      "First 12 bytes must be zero"
  );
  ```
</Warning>

**Example:**

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

bytes32 recipientBytes = 0x0000000000000000000000001234567890123456789012345678901234567890;
address recipient = AddressUtils.toAddress(recipientBytes);

// Result: 0x1234567890123456789012345678901234567890
```

## AddressUtilsExternal (External)

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

External versions of the same functions, intended for:

* Off-chain use (via eth\_call)
* Contract-to-contract library calls
* Deployment as a separate library contract

### addressToBytes32

```solidity theme={null}
function addressToBytes32(address addr) external pure returns (bytes32)
```

External equivalent of `toBytes32()`. Converts address to bytes32.

**Gas Cost:** \~200 gas (external call overhead)

### bytes32ToAddress

```solidity theme={null}
function bytes32ToAddress(bytes32 _buf) external pure returns (address)
```

External equivalent of `toAddress()`. Converts bytes32 to address.

<Warning>
  Same truncation warning applies: different input values can map to the same address. Validate zero-padding if uniqueness is required.
</Warning>

**Gas Cost:** \~200 gas (external call overhead)

## Legacy Message Library Functions

The original Message library also includes conversion functions:

Source: \~/workspace/source/src/messages/Message.sol:146-158

```solidity theme={null}
// Legacy external function
function addressToBytes32(address addr) external pure returns (bytes32) {
    return bytes32(uint256(uint160(addr)));
}

// Legacy public function
function bytes32ToAddress(bytes32 _buf) public pure returns (address) {
    return address(uint160(uint256(_buf)));
}
```

These are functionally identical to AddressUtilsExternal but located in the Message library.

## Usage Examples

### Basic Conversion

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

contract MyContract {
    using AddressUtils for address;
    using AddressUtils for bytes32;

    function convertAddress(address addr) public pure returns (bytes32) {
        return AddressUtils.toBytes32(addr);
    }

    function convertBytes32(bytes32 buf) public pure returns (address) {
        return AddressUtils.toAddress(buf);
    }
}
```

### Secure Conversion with Validation

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

function secureConversion(bytes32 _buf) internal pure returns (address) {
    // Validate first 12 bytes are zero
    require(
        uint256(_buf) >> 160 == 0,
        "Invalid address format: non-zero padding"
    );
    
    return AddressUtils.toAddress(_buf);
}
```

### Cross-Chain Message Construction

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

function createCrossChainTransfer(
    address sender,
    address recipient,
    address token,
    uint256 amount
) internal pure returns (bytes memory) {
    // Convert all addresses to bytes32
    bytes32 senderBytes = AddressUtils.toBytes32(sender);
    bytes32 recipientBytes = AddressUtils.toBytes32(recipient);
    bytes32 tokenBytes = AddressUtils.toBytes32(token);

    // Create burn message
    bytes memory burnMsg = BurnMessage._formatMessage(
        0,              // version
        tokenBytes,
        recipientBytes,
        amount,
        senderBytes
    );

    // Create main message
    return Message._formatMessage(
        0,                      // version
        0,                      // source domain
        1,                      // destination domain
        12345,                  // nonce
        senderBytes,
        recipientBytes,
        bytes32(0),             // any caller
        burnMsg
    );
}
```

### Decoding Received Messages

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

using TypedMemView for bytes;
using Message for bytes29;

function processReceivedMessage(bytes memory message) internal {
    bytes29 messageView = message.ref(0);
    
    // Extract bytes32 addresses
    bytes32 senderBytes = messageView._sender();
    bytes32 recipientBytes = messageView._recipient();
    
    // Convert to EVM addresses
    address sender = AddressUtils.toAddress(senderBytes);
    address recipient = AddressUtils.toAddress(recipientBytes);
    
    // Validate addresses if needed
    require(recipient == expectedRecipient, "Wrong recipient");
    
    // Process message...
}
```

### Off-Chain Address Conversion

Using AddressUtilsExternal via eth\_call:

```javascript theme={null}
const { ethers } = require('ethers');

// Contract ABI
const abi = [
  'function addressToBytes32(address addr) external pure returns (bytes32)',
  'function bytes32ToAddress(bytes32 buf) external pure returns (address)'
];

// Connect to deployed library
const addressUtils = new ethers.Contract(
  '0x...AddressUtilsExternal address...',
  abi,
  provider
);

// Convert address to bytes32
const address = '0x1234567890123456789012345678901234567890';
const bytes32 = await addressUtils.addressToBytes32(address);
console.log(bytes32);
// 0x0000000000000000000000001234567890123456789012345678901234567890

// Convert bytes32 to address
const convertedAddress = await addressUtils.bytes32ToAddress(bytes32);
console.log(convertedAddress);
// 0x1234567890123456789012345678901234567890
```

## Non-EVM Chain Considerations

When integrating with non-EVM chains:

### Solana Example

Solana addresses are 32-byte public keys (already bytes32):

```solidity theme={null}
// Solana address fits perfectly in bytes32
bytes32 solanaAddress = 0x1234...  // 32-byte Solana public key

// No conversion needed - use directly in messages
```

### Other Chain Formats

For chains with different address lengths:

* **Shorter addresses**: Right-pad with zeros
* **Longer addresses**: Hash to 32 bytes (not reversible)
* **Different encoding**: Define chain-specific conversion logic

<Tip>
  For production cross-chain applications, establish clear address encoding standards for each supported chain in your protocol documentation.
</Tip>

## Gas Optimization

Internal functions are more gas-efficient:

```solidity theme={null}
// Internal: ~20 gas (inlined)
AddressUtils.toBytes32(addr);

// External: ~200+ gas (external call)
addressUtilsExternal.addressToBytes32(addr);
```

Use internal functions within contracts, external functions for off-chain reads.

## See Also

* [Message Format](/api/messages/message) - Uses bytes32 for all address fields
* [BurnMessage Format](/api/messages/burn-message) - Uses bytes32 for token and recipient addresses
* [MessageTransmitter](/api/message-transmitter) - Validates address formats in messages
