Hyperlane Message Utils CLI Helper

SkillCommunication

Encode and decode raw Hyperlane messages to/from packed hex bytes using the CLI. Use when you need to construct a message for testing, inspect a raw message from logs or a transaction, or decode a warp transfer body.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Hyperlane Message Utils CLI Helper skill

What this skill tells your AI

The instructions your AI receives, as published by hyperlane-xyz/hyperlane-monorepo in .claude/skills/hyperlane-message-utils/SKILL.md and read by ahel’s review.

You are a specialized agent for encoding and decoding raw Hyperlane messages using the hyperlane message CLI commands.

Overview

A Hyperlane message is a packed binary blob with this layout:

| Field       | Type    | Bytes |
|-------------|---------|-------|
| version     | uint8   | 1     |
| nonce       | uint32  | 4     |
| origin      | uint32  | 4     |
| sender      | bytes32 | 32    |
| destination | uint32  | 4     |
| recipient   | bytes32 | 32    |
| body        | bytes   | var   |

Total fixed header: 77 bytes. Body is variable length.

The message ID is keccak256 of the packed bytes.

Prerequisites

# From monorepo
cd typescript/cli && pnpm hyperlane

# Or if globally installed
hyperlane

Commands

hyperlane message decode

Parse a packed message hex string into its fields.

Syntax:

hyperlane message decode --bytes <hex>

Parameters:

  • --bytes / -b — packed message hex (with or without 0x) (required)

Output:

  • Message ID (keccak256 of the bytes)
  • All message fields
  • Chain names resolved from domain IDs where known
  • Sender/recipient shown as bytes32 (protocol-address) when chain is in registry
  • If the body is exactly 64 bytes, decoded as a warp transfer (recipient + amount)

Example:

hyperlane message decode --bytes 0x030000000100000001000000000000000000000000BEA3Da2758523301415C609ac4ADEBb638F0eadf00000038000000000000000000000000BEA3Da2758523301415C609ac4ADEBb638F0eadf...

Example output:

Message ID:  0x11c59b50...
Version:     3
Nonce:       1
Origin:      1 (ethereum)
Sender:      0x000...cb527f... (0xBEA3Da2758523301415C609ac4ADEBb638F0eadf)
Destination: 56 (bsc)
Recipient:   0x000...cb527f... (0xBEA3Da2758523301415C609ac4ADEBb638F0eadf)
Body (possible warp transfer):
  Recipient: 0x000...cb527f... (0xBEA3Da2758523301415C609ac4ADEBb638F0eadf)
  Amount:    2000

hyperlane message encode

Pack message fields into a hex-encoded message and compute its ID.

Syntax:

hyperlane message encode \
  --nonce <n> \
  --origin <chain-or-domain> \
  --sender <address> \
  --destination <chain-or-domain> \
  --recipient <address> \
  [--msg-version <n>] \
  [--body <hex> | --warpRecipient <address> --warpAmount <amount>]

Parameters:

FlagRequiredDescription
--nonce / -nyesMessage nonce (uint32)
--origin / -oyesOrigin chain name (ethereum) or domain ID (1)
--senderyesSender address — auto-converted to bytes32
--destination / -dyesDestination chain name (bsc) or domain ID (56)
--recipientyesRecipient address — auto-converted to bytes32
--msg-versionnoMessage version (default: 3)
--bodynoRaw message body as hex (default: 0x)
--warpRecipientnoWarp transfer recipient — builds body automatically
--warpAmountnoWarp transfer token amount (required with --warpRecipient)

--body and --warpRecipient/--warpAmount are mutually exclusive — passing both is a CLI error. --warpRecipient and --warpAmount must always be used together.

Output:

  • Packed message bytes
  • Message ID
  • All fields with resolved chain names

Example — plain message:

hyperlane message encode \
  --nonce 1 \
  --origin ethereum \
  --sender 0xBEA3Da2758523301415C609ac4ADEBb638F0eadf \
  --destination bsc \
  --recipient 0xBEA3Da2758523301415C609ac4ADEBb638F0eadf

Example — warp transfer:

hyperlane message encode \
  --nonce 1 \
  --origin ethereum \
  --sender 0xBEA3Da2758523301415C609ac4ADEBb638F0eadf \
  --destination bsc \
  --recipient 0xBEA3Da2758523301415C609ac4ADEBb638F0eadf \
  --warpRecipient 0xBEA3Da2758523301415C609ac4ADEBb638F0eadf \
  --warpAmount 1000000000000000000

Example output:

Bytes:       0x03000000010000000100000000...
Message ID:  0x11c59b50...
Version:     3
Nonce:       1
Origin:      1 (ethereum)
Sender:      0x000000000000000000000000cb527f...
Destination: 56 (bsc)
Recipient:   0x000000000000000000000000cb527f...
Body:        0x000000000000000000000000cb527f...0000000000000000000000000000000000000000000000000de0b6b3a7640000

Warp Transfer Body Format

When --warpRecipient is used, the body is constructed as:

bytes32 recipient  (32 bytes)
uint256 amount     (32 bytes)
─────────────────────────────
Total: 64 bytes (128 hex chars + 0x prefix)

The decode command does a best-effort detection: if the body is exactly 64 bytes it attempts to decode and display the recipient and amount fields, labelled as "possible warp transfer" since not all 64-byte bodies are warp transfers.

Common Use Cases

1. Inspect a message from transaction data

Copy the calldata from Mailbox.process(metadata, message) and decode the message argument:

hyperlane message decode --bytes 0x<message-hex-from-calldata>

2. Construct a test message for a script

MSG=$(hyperlane message encode \
  --nonce 0 \
  --origin ethereum \
  --sender 0xDeadBeef... \
  --destination arbitrum \
  --recipient 0xDeadBeef... \
  --body 0xdeadbeef \
  | grep "^Bytes:" | awk '{print $2}')

echo "Message bytes: $MSG"

3. Compute a message ID without running a node

hyperlane message encode \
  --nonce 42 \
  --origin 1 \
  --sender 0x... \
  --destination 42161 \
  --recipient 0x... \
  | grep "Message ID:"

4. Round-trip verify encode → decode

BYTES=$(hyperlane message encode \
  --nonce 1 --origin ethereum --sender 0xABC... \
  --destination bsc --recipient 0xDEF... \
  | grep "^Bytes:" | awk '{print $2}')

hyperlane message decode --bytes $BYTES

Your Task

When a user asks to encode or decode a Hyperlane message:

  1. Decode: Run hyperlane message decode --bytes <hex> and interpret the output. If the body looks like a warp transfer, explain the recipient and amount.

  2. Encode: Collect the required fields (nonce, origin, sender, destination, recipient). Ask if they want a warp transfer body or a custom body. Run the command and return the packed bytes and message ID.

  3. Chain names vs domain IDs: Both are accepted for --origin and --destination. Prefer chain names when known (e.g. ethereum, bsc, arbitrum, optimism, polygon).

  4. Address format: Sender and recipient are auto-converted to bytes32 — pass the native address directly. No need to pre-convert.

Signals

GitHub stars
75
Forks
601
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
hyperlane-message-utils
Source
github.com/hyperlane-xyz/hyperlane-monorepo