Uses the Hyperlane CLI to manually deliver (self-relay) a message between chains that are Ethereum protocol type.
Manually deliver a Hyperlane message using the CLI's status --relay command.
| Parameter | Required | Default | Description |
|---|---|---|---|
origin_chain |
No | Derived from Explorer API | Name of the origin chain (auto-derived if not provided) |
dispatch_tx |
No* | - | Transaction hash of the dispatch (when message was sent) |
message_id |
No* | - | The Hyperlane message ID (alternative to dispatch_tx) |
registry_path |
No | CLI default | Path to a local registry (overridden if private_rpcs is true) |
key |
No | $(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey) |
Private key for signing the relay transaction |
private_rpcs |
No | true |
If true, use private RPCs via local http-registry |
* Either dispatch_tx OR message_id must be provided, but not both.
The working directory may not be the monorepo root. Find it by looking for CLAUDE.md or package.json with "name": "hyperlane-monorepo":
git rev-parse --show-toplevel
Store this path as MONOREPO_ROOT. All subsequent commands must be prefixed with cd $MONOREPO_ROOT && to ensure correct execution.
Validate dispatch_tx / message_id:
dispatch_tx nor message_id is provided โ Error: "Must provide either dispatch_tx or message_id"dispatch_tx and message_id are provided โ Error: "Provide only one of dispatch_tx or message_id, not both"If private_rpcs is true:
registry_path to http://localhost:3333Query the Hyperlane Explorer GraphQL API to resolve any missing values (dispatch_tx, origin_chain).
If message_id was provided:
query {
message_view(
where: { msg_id: { _eq: "\\x<message_id_without_0x>" } }
limit: 1
) {
origin_tx_hash
origin_domain
is_delivered
}
}
If dispatch_tx was provided but origin_chain is missing:
query {
message_view(
where: { origin_tx_hash: { _eq: "\\x<dispatch_tx_without_0x>" } }
limit: 1
) {
origin_domain
is_delivered
}
}
Use the mcp__hyperlane-explorer__query-graphql tool. Note: bytea fields use \\x prefix without 0x.
Extract values:
origin_tx_hash โ convert \\x... to 0x... format โ set as dispatch_txorigin_domain โ set as origin_chain (e.g., "ethereum", "citrea")is_delivered โ if true, inform user message is already delivered (no relay needed)If no message found: Error "Message not found in Hyperlane Explorer"
key was provided, use that value directlykey was NOT provided, use the default: $(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)hypkey directly. Only use it as an environment variable value when running the relay command.Run the following command (append --registry <registry_path> if registry_path is set):
cd $MONOREPO_ROOT && \
LOG_FORMAT=pretty LOG_LEVEL=debug HYP_KEY="<key>" \
pnpm -C typescript/cli hyperlane status --relay --origin <origin_chain> --dispatchTx <dispatch_tx>
If private_rpcs was true:
Surface the output to the user, including:
cd $MONOREPO_ROOT && \
LOG_FORMAT=pretty LOG_LEVEL=debug HYP_KEY="$(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)" \
pnpm -C typescript/cli hyperlane status --relay --origin ethereum --dispatchTx 0xabc123...
MONOREPO_ROOT=$(git rev-parse --show-toplevel)0xdef456... โ get origin_tx_hash and origin_domainis_delivered - if already delivered, inform user and skip relaycd $MONOREPO_ROOT && \
LOG_FORMAT=pretty LOG_LEVEL=debug HYP_KEY="$(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)" \
pnpm -C typescript/cli hyperlane status --relay --origin <origin_domain> --dispatchTx <origin_tx_hash> --registry http://localhost:3333