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
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:
Example:
toAddress
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:
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.
Example:
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
External equivalent of toBytes32(). Converts address to bytes32.
Gas Cost: ~200 gas (external call overhead)
bytes32ToAddress
External equivalent of toAddress(). Converts bytes32 to address.
Same truncation warning applies: different input values can map to the same address. Validate zero-padding if uniqueness is required.
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
These are functionally identical to AddressUtilsExternal but located in the Message library.
Usage Examples
Basic Conversion
Secure Conversion with Validation
Cross-Chain Message Construction
Decoding Received Messages
Off-Chain Address Conversion
Using AddressUtilsExternal via eth_call:
Non-EVM Chain Considerations
When integrating with non-EVM chains:
Solana Example
Solana addresses are 32-byte public keys (already bytes32):
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
For production cross-chain applications, establish clear address encoding standards for each supported chain in your protocol documentation.
Gas Optimization
Internal functions are more gas-efficient:
Use internal functions within contracts, external functions for off-chain reads.
See Also