Skip to content

Commit b7cdfc5

Browse files
tkporterclaude
andauthored
feat(claude): add self-relay-hyperlane-message skill (hyperlane-xyz#7857)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4880cf8 commit b7cdfc5

File tree

2 files changed

+157
-8
lines changed

2 files changed

+157
-8
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
name: self-relay-hyperlane-message
3+
description: Uses the Hyperlane CLI to manually deliver (self-relay) a message between chains that are Ethereum protocol type.
4+
---
5+
6+
# Self-Relay Hyperlane Message
7+
8+
Manually deliver a Hyperlane message using the CLI's `status --relay` command.
9+
10+
## Input Parameters
11+
12+
| Parameter | Required | Default | Description |
13+
| --------------- | -------- | --------------------------------------------------------------- | --------------------------------------------------------------- |
14+
| `origin_chain` | No | Derived from Explorer API | Name of the origin chain (auto-derived if not provided) |
15+
| `dispatch_tx` | No\* | - | Transaction hash of the dispatch (when message was sent) |
16+
| `message_id` | No\* | - | The Hyperlane message ID (alternative to dispatch_tx) |
17+
| `registry_path` | No | CLI default | Path to a local registry (overridden if `private_rpcs` is true) |
18+
| `key` | No | `$(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)` | Private key for signing the relay transaction |
19+
| `private_rpcs` | No | `true` | If true, use private RPCs via local http-registry |
20+
21+
**\*** Either `dispatch_tx` OR `message_id` must be provided, but not both.
22+
23+
## Instructions
24+
25+
### Step 0: Find Monorepo Root
26+
27+
The working directory may not be the monorepo root. Find it by looking for `CLAUDE.md` or `package.json` with `"name": "hyperlane-monorepo"`:
28+
29+
```bash
30+
git rev-parse --show-toplevel
31+
```
32+
33+
Store this path as `MONOREPO_ROOT`. All subsequent commands must be prefixed with `cd $MONOREPO_ROOT &&` to ensure correct execution.
34+
35+
### Step 1: Validate Inputs
36+
37+
**Validate dispatch_tx / message_id:**
38+
39+
- If NEITHER `dispatch_tx` nor `message_id` is provided → **Error:** "Must provide either dispatch_tx or message_id"
40+
- If BOTH `dispatch_tx` and `message_id` are provided → **Error:** "Provide only one of dispatch_tx or message_id, not both"
41+
42+
### Step 2: Start Private RPC Registry (if needed)
43+
44+
If `private_rpcs` is `true`:
45+
46+
1. **Force override** `registry_path` to `http://localhost:3333`
47+
2. **Start the http-registry** with /start-http-registry
48+
49+
### Step 3: Query Explorer API for Missing Data
50+
51+
Query the Hyperlane Explorer GraphQL API to resolve any missing values (`dispatch_tx`, `origin_chain`).
52+
53+
**If `message_id` was provided:**
54+
55+
```graphql
56+
query {
57+
message_view(
58+
where: { msg_id: { _eq: "\\x<message_id_without_0x>" } }
59+
limit: 1
60+
) {
61+
origin_tx_hash
62+
origin_domain
63+
is_delivered
64+
}
65+
}
66+
```
67+
68+
**If `dispatch_tx` was provided but `origin_chain` is missing:**
69+
70+
```graphql
71+
query {
72+
message_view(
73+
where: { origin_tx_hash: { _eq: "\\x<dispatch_tx_without_0x>" } }
74+
limit: 1
75+
) {
76+
origin_domain
77+
is_delivered
78+
}
79+
}
80+
```
81+
82+
Use the `mcp__hyperlane-explorer__query-graphql` tool. Note: bytea fields use `\\x` prefix without `0x`.
83+
84+
**Extract values:**
85+
86+
- `origin_tx_hash` → convert `\\x...` to `0x...` format → set as `dispatch_tx`
87+
- `origin_domain` → set as `origin_chain` (e.g., "ethereum", "citrea")
88+
- `is_delivered` → if `true`, inform user message is already delivered (no relay needed)
89+
90+
**If no message found:** Error "Message not found in Hyperlane Explorer"
91+
92+
### Step 4: Determine the Key Value
93+
94+
- If `key` was provided, use that value directly
95+
- If `key` was NOT provided, use the default: `$(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)`
96+
- **Important:** The default key value is a command substitution. Do NOT execute `hypkey` directly. Only use it as an environment variable value when running the relay command.
97+
98+
### Step 5: Run the Self-Relay Command
99+
100+
Run the following command (append `--registry <registry_path>` if `registry_path` is set):
101+
102+
```bash
103+
cd $MONOREPO_ROOT && \
104+
LOG_FORMAT=pretty LOG_LEVEL=debug HYP_KEY="<key>" \
105+
pnpm -C typescript/cli hyperlane status --relay --origin <origin_chain> --dispatchTx <dispatch_tx>
106+
```
107+
108+
### Step 6: Cleanup
109+
110+
If `private_rpcs` was `true`:
111+
112+
1. **Kill the http-registry** using the saved shell/task ID from Step 2
113+
2. Confirm cleanup was successful
114+
115+
### Step 7: Report Results
116+
117+
Surface the output to the user, including:
118+
119+
- Whether the relay was successful
120+
- Any errors encountered
121+
- The destination transaction hash if successful
122+
123+
## Examples
124+
125+
### Example 1: Using dispatch_tx
126+
127+
```bash
128+
cd $MONOREPO_ROOT && \
129+
LOG_FORMAT=pretty LOG_LEVEL=debug HYP_KEY="$(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)" \
130+
pnpm -C typescript/cli hyperlane status --relay --origin ethereum --dispatchTx 0xabc123...
131+
```
132+
133+
### Example 2: Using message_id only (origin_chain auto-derived)
134+
135+
1. Find monorepo root: `MONOREPO_ROOT=$(git rev-parse --show-toplevel)`
136+
2. Start http-registry in background via /start-http-registry
137+
3. Query GraphQL for message `0xdef456...` → get `origin_tx_hash` and `origin_domain`
138+
4. Check `is_delivered` - if already delivered, inform user and skip relay
139+
5. Run:
140+
```bash
141+
cd $MONOREPO_ROOT && \
142+
LOG_FORMAT=pretty LOG_LEVEL=debug HYP_KEY="$(HYPERLANE_MONOREPO=$(git rev-parse --show-toplevel) hypkey)" \
143+
pnpm -C typescript/cli hyperlane status --relay --origin <origin_domain> --dispatchTx <origin_tx_hash> --registry http://localhost:3333
144+
```
145+
6. Kill http-registry process

.claude/skills/start-http-registry/SKILL.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ description: Start the local HTTP registry server for development. Use when test
55

66
# Start HTTP Registry Server
77

8-
Start the http-registry server in the background:
9-
10-
```bash
11-
pnpm -C typescript/infra start:http-registry
12-
```
8+
Start the http-registry server in the background.
139

1410
**Instructions:**
1511

16-
1. Run the command with `run_in_background: true` so it doesn't block the conversation
17-
2. After starting, report the task/shell ID to the user
18-
3. Remind the user they can stop it later with `KillShell` using that ID
12+
1. First, find the monorepo root (working directory may have drifted):
13+
```bash
14+
git rev-parse --show-toplevel
15+
```
16+
2. Run the command with `run_in_background: true`, prefixing with `cd` to the monorepo root:
17+
```bash
18+
cd <MONOREPO_ROOT> && pnpm -C typescript/infra start:http-registry
19+
```
20+
3. After starting, report the task/shell ID to the user
21+
4. Remind the user they can stop it later with `KillShell` using that ID
22+
5. Note the URL that the registry is running on, which would be `http://localhost:<port>`, where the port can be found in the logs.
1923

2024
**Example output:**
2125

0 commit comments

Comments
 (0)