Skip to content

feat(hyperlane): integrate hyperlane-cosmos v1.1.0 bridge modules#301

Merged
angelorc merged 9 commits into
mainfrom
feat-hyperlane
Jun 23, 2026
Merged

feat(hyperlane): integrate hyperlane-cosmos v1.1.0 bridge modules#301
angelorc merged 9 commits into
mainfrom
feat-hyperlane

Conversation

@angelorc

@angelorc angelorc commented Feb 19, 2026

Copy link
Copy Markdown
Collaborator
  • Add Hyperlane Core and Warp modules to enable cross-chain messaging and token bridging between BitSong and EVM chains
  • Register hyperlane and warp store keys, module accounts, and keepers
  • Wire WarpKeeper with CoreKeeper dependency for mailbox access
  • Add begin/end/init blocker ordering after IBC modules
  • Grant Minter+Burner permissions to warp module for synthetic tokens
  • Add hyperlane-cosmos v1.1.0 dependency

Summary by CodeRabbit

  • New Features
    • Integrated Hyperlane and Warp modules into the app, including keeper wiring, module registration, and updated module account setup via the v024 upgrade.
    • Added local Hyperlane tooling: chain init, bridge setup, EVM deployment, agent/relayer orchestration, Fantoken route lifecycle, and end-to-end transfer test scripts—plus shared status, run-all, and stop scripts.
  • Documentation
    • Added a Hyperlane localnet .env.example to help bootstrap required environment variables.
  • Chores
    • Expanded .gitignore for local Hyperlane/dev artifacts and build outputs.
    • Updated Docker image publishing to support branch pushes with dynamic multi-tags.
    • Bumped Go dependencies and added the Hyperlane Cosmos dependency.

- Add Hyperlane Core and Warp modules to enable cross-chain messaging and token bridging between BitSong and EVM chains
- Register hyperlane and warp store keys, module accounts, and keepers
 - Wire WarpKeeper with CoreKeeper dependency for mailbox access
 - Add begin/end/init blocker ordering after IBC modules
 - Grant Minter+Burner permissions to warp module for synthetic tokens
 - Add hyperlane-cosmos v1.1.0 dependency
@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Integrates Hyperlane and Warp modules into the Bitsong app by registering them in module basics, configuring their block execution order, implementing a v024 chain upgrade handler, and updating dependencies to support the new modules; extends .gitignore for development artifacts.

Changes

Core Module Integration

Layer / File(s) Summary
Module registration and block execution ordering
app/modules.go
Registered Hyperlane and Warp modules in AppModuleBasics and app module instantiation; inserted both module names into orderBeginBlockers, orderEndBlockers, and orderInitBlockers sequences to define block execution flow.
Chain upgrade handler (v024)
app/app.go, app/upgrades/v024/constants.go, app/upgrades/v024/upgrades.go
Added v024 upgrade to registered upgrades list; defined upgrade configuration with store migrations for Hyperlane and Warp; implemented CreateV024UpgradeHandler to validate module absence, execute migrations via mm.RunMigrations, and initialize module accounts at upgrade height via AccountKeeper.GetModuleAccount.
Dependency updates
go.mod
Upgraded core Cosmos SDK, CosmWasm, and chain dependencies; added github.com/bcp-innovations/hyperlane-cosmos as direct requirement; added Ethereum support via github.com/ethereum/go-ethereum and github.com/holiman/uint256; updated numerous indirect dependencies across OpenTelemetry, Google Cloud, and utility libraries.

Build Configuration

Layer / File(s) Summary
Development artifact ignores
.gitignore
Extended ignore patterns to exclude local Hyperlane devnet state (.localbitsong-hyperlane/), EVM toolchain artifacts (evm/out/, evm/cache/, evm/broadcast/, evm/node_modules/), secrets and environment files (scripts/hyperlane/.env, infra/.env.secrets), and workspace directories (.docs-to-agent/).

Sequence Diagram(s)

sequenceDiagram
    participant App as Bitsong App Init
    participant ModuleRegistry as Module Registry
    participant HyperlaneModule as Hyperlane Module
    participant WarpModule as Warp Module
    participant Blockchain as Blockchain Runtime
    
    rect rgba(0, 100, 150, 0.5)
    Note over App,ModuleRegistry: Application Startup
    App->>ModuleRegistry: Register AppModuleBasics
    ModuleRegistry->>HyperlaneModule: Register basics
    ModuleRegistry->>WarpModule: Register basics
    App->>ModuleRegistry: Instantiate AppModules
    ModuleRegistry->>HyperlaneModule: Create module instance
    ModuleRegistry->>WarpModule: Create module instance
    end
    
    rect rgba(150, 100, 0, 0.5)
    Note over Blockchain: Block Execution
    Blockchain->>HyperlaneModule: BeginBlock
    Blockchain->>WarpModule: BeginBlock
    Blockchain->>HyperlaneModule: EndBlock
    Blockchain->>WarpModule: EndBlock
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Two modules hop into the chain,
Hyperlane weaves and Warp maintains the lane.
With v024's steady hands they bloom,
block by block, through the quantum room! 🌟💫

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly describes the main feature: integrating Hyperlane bridge modules (v1.1.0) into the BitSong blockchain, which is the central change across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-hyperlane

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/modules.go (1)

188-222: ⚠️ Potential issue | 🔴 Critical

Remove duplicate module names in orderInitBlockers—they cause double InitGenesis calls.

authtypes.ModuleName appears at lines 191 and 206, and ibcwasmtypes.ModuleName appears at lines 207 and 216. In Cosmos SDK's module.Manager, duplicate names in the initialization order list cause that module's InitGenesis to be called twice, which violates the intended initialization contract and can corrupt chain state. These duplicates are introduced in this PR and must be removed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/modules.go` around lines 188 - 222, In orderInitBlockers(), remove the
duplicate module names so each ModuleName appears only once: drop the second
occurrence of authtypes.ModuleName and the second occurrence of
ibcwasmtypes.ModuleName to prevent double InitGenesis calls; update the returned
slice in orderInitBlockers() so every module constant (e.g.,
capabilitytypes.ModuleName, authtypes.ModuleName, ibcwasmtypes.ModuleName, etc.)
is unique while preserving the intended initialization order.
🧹 Nitpick comments (1)
.gitignore (1)

66-68: Consider a broader .env* pattern to guard against accidental secret commits.

The specific paths scripts/hyperlane/.env and infra/.env.secrets are good, but any new .env file added elsewhere won't be caught. A catch-all pattern like **/.env* (with explicit exceptions via ! if needed) would be more defensive.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore around lines 66 - 68, Replace the two explicit secret-file
entries with a broader catch-all pattern to prevent accidental commits of any
environment files: remove or supersede the specific lines
"scripts/hyperlane/.env" and "infra/.env.secrets" and add a recursive pattern
like "**/.env*" to .gitignore (optionally add explicit negate patterns with "!"
if you need to allow particular committed example env files).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Line 111: Your go.mod references an indirect dependency
github.com/ethereum/go-ethereum v1.14.12 which has a HIGH-severity
vulnerability; update to a patched release by either updating the upstream
consumer (hyperlane-cosmos v1.1.0) to a version that depends on go-ethereum
v1.14.13 or v1.16.7+, or add a go.mod replace directive to pin
github.com/ethereum/go-ethereum to v1.14.13 (or v1.16.7+) to override the
indirect version; after upgrading, ensure any Ethereum node key is rotated
(delete <datadir>/geth/nodekey before restart) as recommended.

---

Outside diff comments:
In `@app/modules.go`:
- Around line 188-222: In orderInitBlockers(), remove the duplicate module names
so each ModuleName appears only once: drop the second occurrence of
authtypes.ModuleName and the second occurrence of ibcwasmtypes.ModuleName to
prevent double InitGenesis calls; update the returned slice in
orderInitBlockers() so every module constant (e.g., capabilitytypes.ModuleName,
authtypes.ModuleName, ibcwasmtypes.ModuleName, etc.) is unique while preserving
the intended initialization order.

---

Nitpick comments:
In @.gitignore:
- Around line 66-68: Replace the two explicit secret-file entries with a broader
catch-all pattern to prevent accidental commits of any environment files: remove
or supersede the specific lines "scripts/hyperlane/.env" and
"infra/.env.secrets" and add a recursive pattern like "**/.env*" to .gitignore
(optionally add explicit negate patterns with "!" if you need to allow
particular committed example env files).

Comment thread go.mod

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (15)
.github/workflows/push-docker-image.yml (2)

73-75: Quote $GITHUB_OUTPUT to satisfy SC2086.

Static analysis flags unquoted $GITHUB_OUTPUT on all three lines. While the GHA-provided path is unlikely to contain spaces, quoting is a good defensive habit.

Proposed fix
-          echo "IMAGE_TAGS<<EOF" >> $GITHUB_OUTPUT
-          echo "$IMAGE_TAGS" >> $GITHUB_OUTPUT
-          echo "EOF" >> $GITHUB_OUTPUT
+          {
+            echo "IMAGE_TAGS<<EOF"
+            echo "$IMAGE_TAGS"
+            echo "EOF"
+          } >> "$GITHUB_OUTPUT"

This also addresses the SC2129 style hint by consolidating the three redirects into a single grouped redirect.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/push-docker-image.yml around lines 73 - 75, The three echo
lines that append IMAGE_TAGS to the GHA output use an unquoted $GITHUB_OUTPUT
and multiple redirects; change them to a single grouped append that redirects
once to the quoted "$GITHUB_OUTPUT" and echo the IMAGE_TAGS content (use the
IMAGE_TAGS variable quoted as "$IMAGE_TAGS" inside the group) so the path is
quoted (satisfying SC2086) and you avoid repeated redirects (addresses SC2129).

28-29: Hardcoded branch name will keep triggering builds after merge.

Once this PR merges to main, the feat-hyperlane branch filter will either become a no-op (if the branch is deleted) or keep building stale images. Consider replacing with a wildcard pattern or removing before merge if branch-based images are only needed during development.

     branches:
-      - 'feat-hyperlane'
+      - 'main'

Or, if multiple feature branches should produce images:

     branches:
-      - 'feat-hyperlane'
+      - 'feat-*'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/push-docker-image.yml around lines 28 - 29, The workflow
currently hardcodes a branch filter value 'feat-hyperlane' under the branches
key which will keep triggering builds after merge; update the branches filter
(in the push trigger section where branches: ['feat-hyperlane'] is defined) to
either remove the branches filter entirely if you want builds on all branches,
replace the literal with a wildcard pattern such as 'feat-*' to capture multiple
feature branches, or parameterize it via a repository secret or environment
variable so it won't become stale after merging.
scripts/hyperlane/03-evm-deploy.sh (1)

61-116: Implicit global variables DEPLOYED_EVM and TOKEN_ID couple functions.

DEPLOYED_EVM (Line 64) and TOKEN_ID (Line 123) are set without local, making them implicitly global. enroll_cosmos_side and enroll_evm_side depend on these globals being set by prior function calls. This works but is fragile — consider either documenting the contract or passing values via state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/03-evm-deploy.sh` around lines 61 - 116, deploy_hyp_erc20
and the token enrollment functions rely on implicitly global variables
(DEPLOYED_EVM, TOKEN_ID); make these locals and/or use the existing
save_state/load_state to avoid fragile globals: declare DEPLOYED_EVM as local
inside deploy_hyp_erc20 (it’s already saved with save_state "evm_hyp_erc20"),
declare TOKEN_ID local where it’s assigned, and update enroll_cosmos_side and
enroll_evm_side to read values via load_state ("evm_hyp_erc20" and the token
state key) or accept them as parameters instead of depending on globals; ensure
references to evm_to_bytes32, save_state, and load_state remain consistent.
scripts/hyperlane/04-agents.sh (2)

444-453: State cleanup runs jq per key — consolidate into a single call.

The loop runs 7 separate jq read-write cycles on the state file. A single jq invocation deleting all keys is more efficient and atomic.

Proposed fix
-  for key in validator_addr bitsong_multisig_ism_id basesepolia_multisig_ism \
-             validator_bitsong_announced validator_basesepolia_announced \
-             ism_updated_cosmos_side ism_updated_evm_side; do
-    [[ -f "$STATE_FILE" ]] && jq --arg k "$key" 'del(.[$k])' "$STATE_FILE" > "${STATE_FILE}.tmp" \
-      && mv "${STATE_FILE}.tmp" "$STATE_FILE"
-  done
+  if [[ -f "$STATE_FILE" ]]; then
+    jq 'del(.validator_addr, .bitsong_multisig_ism_id, .basesepolia_multisig_ism,
+            .validator_bitsong_announced, .validator_basesepolia_announced,
+            .ism_updated_cosmos_side, .ism_updated_evm_side)' \
+      "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
+  fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/04-agents.sh` around lines 444 - 453, The loop that runs jq
once per key is inefficient; replace it with a single jq invocation that deletes
all seven keys at once to be atomic and faster: check [[ -f "$STATE_FILE" ]] and
then run jq with a del() call that removes .validator_addr,
.bitsong_multisig_ism_id, .basesepolia_multisig_ism,
.validator_bitsong_announced, .validator_basesepolia_announced,
.ism_updated_cosmos_side, and .ism_updated_evm_side in one expression, writing
to "${STATE_FILE}.tmp" and mv-ing it back (preserve the existing temp-file
atomic write pattern used elsewhere).

70-124: Inline Python bech32 encoder lacks dependency pre-check and leaks key via process args.

The ecdsa package is required but only mentioned in the error message (Line 107). A pre-check (python3 -c "import ecdsa") would fail fast with a clear message. Also, $COSMOS_SIGNER_KEY is interpolated into the Python command string (Line 103), making it visible in /proc/PID/cmdline. For a devnet script this is acceptable, but consider piping via stdin for better hygiene.

Proposed improvement
 fund_cosmos_signer() {
   log_step "Step 1b: Fund Cosmos Signer"
 
+  python3 -c "import ecdsa" 2>/dev/null || { log_err "Python ecdsa package missing: pip3 install ecdsa"; return 1; }
+
   local cosmos_signer_addr
-  cosmos_signer_addr=$(python3 -c "
+  cosmos_signer_addr=$(python3 - "$COSMOS_SIGNER_KEY" << 'PYEOF'
+import sys
 from ecdsa import SigningKey, SECP256k1
 import hashlib
 def to_bech32(hex_key, prefix='bitsong'):
     pk = bytes.fromhex(hex_key.replace('0x',''))
     ...
-print(to_bech32('$COSMOS_SIGNER_KEY'))
-" 2>/dev/null)
+print(to_bech32(sys.argv[1]))
+PYEOF
+)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/04-agents.sh` around lines 70 - 124, The embedded Python
call in fund_cosmos_signer both omits a pre-check for the ecdsa dependency and
leaks COSMOS_SIGNER_KEY on the process command line; add an upfront check (e.g.,
run a short python3 -c "import ecdsa" check and fail with a clear log_err if it
raises) and change the python invocation that derives the bech32 address to read
the private key from stdin or an environment-safe source instead of
interpolating $COSMOS_SIGNER_KEY into the command string (update the python3
call used in fund_cosmos_signer and related logging to reflect this safer input
method and surface dependency failures clearly).
scripts/hyperlane/status.sh (1)

34-43: date -d is GNU-only — will fail on macOS.

date -d "$started" (Line 36) is a GNU coreutils extension not available on macOS's BSD date. If cross-platform use is intended, consider date portability or document the Linux requirement.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/status.sh` around lines 34 - 43, The script uses GNU-only
date parsing (date -d "$started") inside the block handling status/started
(variables status, started, start_epoch), which fails on macOS; replace this
with a portable approach: detect GNU date vs BSD date (e.g., check if date -d
works) and if unavailable parse the timestamp using a macOS-compatible command
(date -j -f or a small portable fallback using python/perl) to compute
start_epoch, preserving the rest of the uptime calculation logic; ensure the
change keeps the same variable names (start_epoch, now_epoch, diff, uptime) and
behavior for Linux while providing the BSD/date-compatible branch for macOS.
scripts/hyperlane/run-all.sh (1)

58-77: Unquoted $CLEAN_FLAG is intentional but fragile.

The unquoted $CLEAN_FLAG on Lines 61, 63, 64, 73 relies on word-splitting to pass zero arguments when empty. This works but is unconventional under set -euo pipefail. Using an array would be more robust and idiomatic.

Alternative using array
-CLEAN_FLAG=""
-[[ "$CLEAN" == "true" ]] && CLEAN_FLAG="--clean"
+CLEAN_ARGS=()
+[[ "$CLEAN" == "true" ]] && CLEAN_ARGS=(--clean)
 
-run_phase 1 "01-chain.sh" $CLEAN_FLAG
+run_phase 1 "01-chain.sh" "${CLEAN_ARGS[@]+"${CLEAN_ARGS[@]}"}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/run-all.sh` around lines 58 - 77, The script currently uses
a string CLEAN_FLAG and an unquoted expansion which relies on word-splitting;
replace this with a shell array (e.g. CLEAN_ARGS) that is empty by default and
set to contain --clean when CLEAN is true, then pass that array to run_phase
invocations instead of CLEAN_FLAG (update the calls that reference CLEAN_FLAG
and the run_phase invocations for 01-chain.sh, 03-evm-deploy.sh, 04-agents.sh,
06-fantoken-route.sh to expand the array), ensuring the array is expanded
properly so no spurious empty arguments are passed.
scripts/hyperlane/06-fantoken-route.sh (5)

608-617: --clean loop runs jq | mv per key — N sequential file rewrites.

For a small fixed set of suffixes this is fine, but it could be a single jq call with multiple del() operations. Minor efficiency nit.

♻️ Single jq pass to delete all keys
 if [[ "$CLEAN" == "true" ]]; then
   log "Cleaning state for symbol '$FT_KEY'..."
-  for suffix in denom minted token_id evm_hyp_erc20 evm_hyp_erc20_bytes32 \
-               router_enrolled evm_router_enrolled evm_ism_set relayer_restarted; do
-    jq --arg k "ft_${FT_KEY}_${suffix}" 'del(.[$k])' "$STATE_FILE" > "${STATE_FILE}.tmp" \
-      && mv "${STATE_FILE}.tmp" "$STATE_FILE"
-  done
+  local prefix="ft_${FT_KEY}_"
+  jq --arg p "$prefix" 'with_entries(select(.key | startswith($p) | not))' \
+    "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE"
   unregister_route
   log_ok "State cleaned for '$FT_KEY'"
 fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/06-fantoken-route.sh` around lines 608 - 617, The CLEAN
branch currently rewrites STATE_FILE once per suffix; instead build the list of
suffixes (same set used now) and perform a single jq invocation that deletes all
"ft_${FT_KEY}_${suffix}" keys in one pass (use jq del with an array or chained
del() calls generated from the suffix list) and then mv the single temporary
file back to STATE_FILE; keep the surrounding log calls and the unregister_route
call and reference CLEAN, FT_KEY, STATE_FILE and unregister_route so you only
perform one jq | mv instead of N sequential rewrites.

86-95: unregister_route uses grep -v with unescaped regex from FT_KEY.

grep -v "^${FT_KEY}$" treats FT_KEY as a regex. If a symbol ever contains ., *, or other metacharacters, it could unintentionally remove other routes. Use grep -Fxv for a fixed-string exact-line match.

♻️ Use fixed-string matching
-  new_list=$(echo "$list" | tr ',' '\n' | grep -v "^${FT_KEY}$" | paste -sd ',' -) || true
+  new_list=$(echo "$list" | tr ',' '\n' | grep -Fxv "$FT_KEY" | paste -sd ',' -) || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/06-fantoken-route.sh` around lines 86 - 95,
unregister_route currently uses grep -v with an unescaped regex ("grep -v
\"^${FT_KEY}$\"") so metas in FT_KEY can match unexpectedly; update the pipeline
in unregister_route (which calls load_state and save_state) to use fixed-string
exact-line matching (e.g., replace the grep invocation with grep -Fxv or
equivalent) so the removal compares FT_KEY as a literal exact line and won’t
treat characters like . or * as regex metacharacters.

465-481: Private keys passed as CLI arguments to docker run are visible via docker inspect and ps.

Lines 477 and 480 pass COSMOS_SIGNER_KEY and EVM_RELAYER_KEY directly on the command line. Any user on the host can read these via ps aux or docker inspect. For a local devnet script this is acceptable, but if this pattern is reused for testnet/mainnet, secrets should be passed via Docker secrets, a mounted file, or environment variables (-e flag, which is still visible in docker inspect but not in ps).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/06-fantoken-route.sh` around lines 465 - 481, The script
exposes private keys by passing COSMOS_SIGNER_KEY and EVM_RELAYER_KEY directly
on the docker run command line (used for --chains.bitsong.signer.key and
--chains.basesepolia.signer.key); change this to load secrets from a safer
source such as Docker secrets or mounted files and reference those inside the
container (e.g., mount $BITSONG_HOME/cosmos_key:/run/secrets/cosmos_key:ro and
use the file path inside the relayer config or set an env var reading that
file), or at minimum export them as environment variables via -e (noting they
remain visible in docker inspect) and update the CLI flags to read from the
secret file paths or env vars rather than embedding the raw keys on the command
line.

182-212: build_whitelist constructs JSON via string concatenation — fragile.

Hand-assembling a JSON array with string interpolation is error-prone (unescaped characters, stray commas, etc.). Consider using jq to build the array incrementally, which inherently produces valid JSON.

♻️ Use jq to build the whitelist
 build_whitelist() {
-  local whitelist="["
+  local whitelist="[]"
 
   # Always include ubtsg route
   local token_id evm_hyp_erc20
   token_id=$(load_state "token_id")
   evm_hyp_erc20=$(load_state "evm_hyp_erc20")
   if [[ -n "$token_id" && -n "$evm_hyp_erc20" ]]; then
-    whitelist+="{\"senderAddress\":\"${token_id}\",\"destinationDomain\":\"${REMOTE_DOMAIN}\"},"
-    whitelist+="{\"senderAddress\":\"$(evm_to_bytes32 "$evm_hyp_erc20")\",\"destinationDomain\":\"${DOMAIN_ID}\"},"
+    whitelist=$(echo "$whitelist" | jq --arg sa "$token_id" --arg dd "$REMOTE_DOMAIN" \
+      '. + [{"senderAddress": $sa, "destinationDomain": $dd}]')
+    whitelist=$(echo "$whitelist" | jq --arg sa "$(evm_to_bytes32 "$evm_hyp_erc20")" --arg dd "$DOMAIN_ID" \
+      '. + [{"senderAddress": $sa, "destinationDomain": $dd}]')
   fi
   # ... same pattern for fantoken routes ...
-  whitelist="${whitelist%,}]"  # Remove trailing comma
   echo "$whitelist"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/06-fantoken-route.sh` around lines 182 - 212, The
build_whitelist function currently constructs JSON by concatenating strings
which is fragile; change it to build the array using jq so items are appended as
real JSON objects. Replace the manual string assembly in build_whitelist
(including the blocks that add ubtsg using token_id/evm_hyp_erc20 and the loop
that adds each fantoken using ft_${sym}_token_id and ft_${sym}_evm_hyp_erc20)
with calls that pipe object literals to jq --arg to set senderAddress and
destinationDomain and use jq -s to produce the final array; keep using
evm_to_bytes32(token) and load_state(...) to read values but pass them via jq
arguments so escaping is handled and you never manually trim trailing commas.

57-60: ft_save / ft_load assume FT_KEY is non-empty — no guard.

If ft_save or ft_load is accidentally called before FT_KEY is set, the state key degenerates to ft__<suffix> (double underscore), silently writing/reading the wrong key. The main flow does enforce FT_KEY is set, but a guard or assertion would make this more robust against future refactors.

♻️ Add a guard
-ft_save() { save_state "ft_${FT_KEY}_$1" "$2"; }
-ft_load() { load_state "ft_${FT_KEY}_$1"; }
+ft_save() { [[ -n "$FT_KEY" ]] || { log_err "BUG: ft_save called with empty FT_KEY"; return 1; }; save_state "ft_${FT_KEY}_$1" "$2"; }
+ft_load() { [[ -n "$FT_KEY" ]] || { log_err "BUG: ft_load called with empty FT_KEY"; return 1; }; load_state "ft_${FT_KEY}_$1"; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/06-fantoken-route.sh` around lines 57 - 60, ft_save and
ft_load currently assume FT_KEY is set and will silently use "ft__<suffix>" if
empty; add a guard in both helper functions (ft_save and ft_load) that asserts
FT_KEY is non-empty before calling save_state/load_state, and fail fast with an
explanatory error message (and non-zero exit) if FT_KEY is empty so you don't
read/write the wrong state key.
scripts/hyperlane/07-fantoken-test.sh (2)

117-121: Inline bytes32 padding duplicates evm_to_bytes32 from lib.sh.

Lines 120–121 replicate the same address-to-bytes32 conversion that evm_to_bytes32 already provides. Use the library function to stay DRY and avoid divergence.

♻️ Use library helper
-  local hex="${evm_signer_addr#0x}"; hex=$(echo "$hex" | tr '[:upper:]' '[:lower:]')
-  evm_signer_bytes32=$(printf "0x%064s" "$hex" | tr ' ' '0')
+  evm_signer_bytes32=$(evm_to_bytes32 "$evm_signer_addr")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/07-fantoken-test.sh` around lines 117 - 121, The inline
bytes32 padding duplicates existing helper evm_to_bytes32; replace the manual
conversion of evm_signer_addr -> evm_signer_bytes32 (the hex
trimming/lowercasing and printf padding) with a call to evm_to_bytes32 from
lib.sh, e.g. evm_signer_bytes32=$(evm_to_bytes32 "$evm_signer_addr"), keeping
the preceding derivation and error check for evm_signer_addr intact and ensuring
the resulting evm_signer_bytes32 variable is used as before.

214-221: totalSupply is used as a proxy for signer balance — works only in single-user devnet.

Line 216 checks totalSupply to determine if the EVM signer has tokens to burn via transferRemote. If multiple users have minted tokens, totalSupply > 0 doesn't guarantee the signer holds any. For the current single-user devnet flow this works, but a balanceOf(signer) check would be more correct.

♻️ Check actual signer balance
-  evm_balance=$(cast call "$ft_evm_hyp_erc20" "totalSupply()(uint256)" --rpc-url "$EVM_RPC" 2>/dev/null) || evm_balance="0"
+  local evm_signer_addr
+  evm_signer_addr=$(cast wallet address --private-key "$EVM_RELAYER_KEY" 2>/dev/null)
+  evm_balance=$(cast call "$ft_evm_hyp_erc20" "balanceOf(address)(uint256)" "$evm_signer_addr" --rpc-url "$EVM_RPC" 2>/dev/null) || evm_balance="0"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/07-fantoken-test.sh` around lines 214 - 221, The script
wrongly uses totalSupply() to infer the signer's token holdings; update the
check to call balanceOf(<signer_address>) instead. Replace the cast call on
ft_evm_hyp_erc20 from "totalSupply()(uint256)" to "balanceOf(address)(uint256)"
and pass the runtime signer address variable used elsewhere in the script (e.g.,
the EVM signer variable like EVM_SIGNER or EVM_FROM) while keeping EVM_RPC;
store the result back into evm_balance and keep the existing error logging path
if the balance is "0". Ensure the balanceOf call targets the same contract
variable ft_evm_hyp_erc20.
scripts/hyperlane/lib.sh (1)

119-129: Concurrent save_state calls can corrupt the state file.

If two scripts (or backgrounded subshells) call save_state concurrently, the read-modify-write on the same STATE_FILE can race: both read the same version, one overwrites the other's write. For a sequential orchestration script this is fine in practice, but the library is designed for general reuse. Consider using flock around the read-modify-write.

♻️ Optional: wrap with flock
 save_state() {
   local key="$1" value="$2"
   [[ ! -f "$STATE_FILE" ]] && echo '{}' > "$STATE_FILE"
-  local tmp="${STATE_FILE}.tmp"
-  jq --arg k "$key" --arg v "$value" '.[$k] = $v' "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
+  (
+    flock -x 200
+    local tmp="${STATE_FILE}.tmp"
+    jq --arg k "$key" --arg v "$value" '.[$k] = $v' "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
+  ) 200>"${STATE_FILE}.lock"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/hyperlane/lib.sh` around lines 119 - 129, The save_state function is
vulnerable to concurrent writes; wrap its read-modify-write against STATE_FILE
with an exclusive flock to prevent races: acquire an exclusive lock on
STATE_FILE (or a lockfd derived from STATE_FILE) before reading, running jq to
update into a temp file, and mv the temp into STATE_FILE, then release the lock;
also apply a shared flock in load_state when reading STATE_FILE to avoid torn
reads. Update the save_state and load_state functions to use flock (fall back to
a safe error if flock is unavailable) while keeping the existing behavior of
creating STATE_FILE if missing and preserving atomic mv.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/push-docker-image.yml:
- Around line 22-29: The workflow currently uses both the release and push.tags
triggers (the YAML keys "release" and "push: tags: - 'v[0-9]+.[0-9]+.[0-9]+'")
which can fire for the same release; remove or disable one of these triggers to
avoid duplicate runs—e.g., delete the entire "push: tags:" block (or
alternatively remove the "release:" block) so only a single trigger (either
"release" or the tag-based "push") remains, keeping the branch filter "branches:
- 'feat-hyperlane'" untouched if branch-scoped pushes are required.

In `@app/keepers/keepers.go`:
- Around line 123-124: Add the hyperlane and warp module store keys to the v023
upgrade's StoreUpgrades so their KV stores are created during migration: update
the StoreUpgrades.Added slice (the v023 upgrade definition that contains
StoreUpgrades) to include hyperlanetypes.ModuleName and warptypes.ModuleName
(follow the same pattern used in v021/v022), leaving Deleted empty; ensure you
reference the existing StoreUpgrades variable/struct in the v023 upgrade block
so the stores are initialized at upgrade time.

In `@scripts/hyperlane/02-hyperlane.sh`:
- Around line 170-195: The update_enrollment function saves
evm_enrollment_updated but doesn't update the router_enrolled flag, so reruns
still think enrollment is pending; modify update_enrollment (the function that
calls save_state "evm_hyp_erc20" / "evm_hyp_erc20_bytes32" /
"evm_enrollment_updated") to also call save_state "router_enrolled" "true" after
a successful submit_tx (use the same success path where log_ok "Enrollment
updated" is invoked) so the existing setup_hyperlane check for router_enrolled
will recognize the enrollment has completed.
- Around line 199-208: The --update-enrollment case currently reads
UPDATE_EVM_ADDR="$2" and does shift 2 without validating $2; add a guard in the
case branch for --update-enrollment that checks whether $2 is present and not
another flag (e.g., [[ -z "$2" || "$2" =~ ^- ]] ), and if missing print a clear
error and exit; otherwise set UPDATE_EVM_ADDR="$2" and shift 2. This fix targets
the --update-enrollment branch handling of UPDATE_EVM_ADDR and the use of
$2/shift 2.

In `@scripts/hyperlane/03-evm-deploy.sh`:
- Around line 238-260: The script mixes "Phase 3" and "Phase 4" labels: update
the internal messages and state handling to match the orchestrator's phase
numbering (or vice versa) so they are consistent; specifically, change the text
strings and log messages that mention "Phase 4" (the jq cleanup log at the CLEAN
block, the banner call banner "Phase 4: Deploy Warp Route", and any other log_ok
messages referencing Phase 4) to "Phase 3" (or change the prerequisite check
that says "Phase 3 state not found" to "Phase 4 state not found" if you prefer
moving the whole script to Phase 4), and ensure STATE_FILE usage, DEPLOYER_ADDR
output (log_ok "EVM deployer: $DEPLOYER_ADDR"), and load_state mailbox_id
messages all use the same phase label; keep symbol names (STATE_FILE, CLEAN,
banner, log_ok, load_state) intact and only alter the human-facing strings so
the orchestrator and script labels align.

In `@scripts/hyperlane/05-test.sh`:
- Around line 296-301: The summary shows blank values because load_state returns
an empty string with exit code 0 for missing keys, so the "|| echo 'not run'"
fallback never runs; change the print logic to capture load_state's output (for
cosmos_to_evm_test_passed and evm_to_cosmos_test_passed) and explicitly test for
an empty string, printing "not run" when empty and the actual value otherwise
(or alter load_state to return non‑zero on missing keys and keep the existing ||
fallback). Target the echo lines that reference
load_state(cosmos_to_evm_test_passed) and load_state(evm_to_cosmos_test_passed).

In `@scripts/hyperlane/07-fantoken-test.sh`:
- Around line 236-238: The variable initial_height is assigned but never used
(ShellCheck SC2034); remove the unused assignment or use it for diagnostics.
Locate the block that sets initial_height (the call to "$BINARY" status --node
"$NODE" --home "$BITSONG_HOME" piped to jq) and either delete the initial_height
variable entirely or log it (e.g., echo or processLogger-style message) when
waiting for the relay so you can report the block range scanned; ensure any
downstream logic that referenced initial_height is updated accordingly.
- Around line 354-360: The script currently allows EVM_ONLY and COSMOS_ONLY to
both be true which silently skips all tests; add a mutual-exclusion check after
flag parsing that detects if both EVM_ONLY and COSMOS_ONLY are set and then
prints a clear error (e.g., "Cannot set both --evm-only and --cosmos-only") and
exits non-zero, or alternatively treat both-as-run-both by changing logic—modify
the flag handling around EVM_ONLY/COSMOS_ONLY so you either (A) validate and
exit when both variables are true, or (B) change the test invocation conditions
(test_ft_cosmos_to_evm and test_ft_evm_to_cosmos) to run when either flag is
unset rather than skip both; implement option A (exit on both) by adding an if
[[ "$EVM_ONLY" == "true" && "$COSMOS_ONLY" == "true" ]]; then echo "error..."
>&2; exit 1; fi immediately after flag parsing.

In `@scripts/hyperlane/lib.sh`:
- Around line 241-264: The Python fallback in bech32_to_bytes32 interpolates
$bech32_addr directly into a single-quoted Python string, enabling shell/Python
injection; instead pass the address via an environment variable and read it
inside Python to avoid interpolation. Update the call so the address is passed
as BECH32_ADDR="$bech32_addr" to python3 and change the Python snippet in the
bech32_to_bytes32 function to import os and use os.environ['BECH32_ADDR']
(remove the direct '$bech32_addr' literal), preserving the same decoding logic
and exit/status handling.

In `@scripts/hyperlane/run-all.sh`:
- Around line 5-6: Update the stale usage comment in run-all.sh: change the line
reading "#   bash run-all.sh                  # Run phases 1-5" to reflect that
the script runs phases 1-7 (or list the actual phase range/run behavior). Edit
the top-of-file usage block in run-all.sh so the comment accurately documents
the executed phases (e.g., "# Run phases 1-7" or an explicit brief description
of phases).
- Around line 20-43: The --from case handling must guard against missing or
non-numeric values for FROM_PHASE to avoid unbound-variable and failed numeric
comparisons: in the case branch that sets FROM_PHASE, first ensure $2 is present
and non-empty, then validate it matches a positive-integer pattern (e.g., regex
^[0-9]+$) before assigning FROM_PHASE="$2" and shifting; on failure print a
clear usage/error and exit non-zero. Update the parsing logic around the
FROM_PHASE variable and ensure subsequent numeric comparisons (the -le check
later) operate on a guaranteed numeric value.

In `@scripts/hyperlane/stop.sh`:
- Around line 14-28: The script currently allows both CHAIN_ONLY and AGENTS_ONLY
to be true which results in no services being stopped; after argument parsing
check the combination and reject it: if both CHAIN_ONLY and AGENTS_ONLY are
true, print a clear error message and exit non‑zero. Reference the existing flag
variables CHAIN_ONLY and AGENTS_ONLY and the agent-stop and chain-stop blocks so
the check runs before those blocks execute; this enforces mutual exclusivity
rather than silently doing nothing.

---

Nitpick comments:
In @.github/workflows/push-docker-image.yml:
- Around line 73-75: The three echo lines that append IMAGE_TAGS to the GHA
output use an unquoted $GITHUB_OUTPUT and multiple redirects; change them to a
single grouped append that redirects once to the quoted "$GITHUB_OUTPUT" and
echo the IMAGE_TAGS content (use the IMAGE_TAGS variable quoted as "$IMAGE_TAGS"
inside the group) so the path is quoted (satisfying SC2086) and you avoid
repeated redirects (addresses SC2129).
- Around line 28-29: The workflow currently hardcodes a branch filter value
'feat-hyperlane' under the branches key which will keep triggering builds after
merge; update the branches filter (in the push trigger section where branches:
['feat-hyperlane'] is defined) to either remove the branches filter entirely if
you want builds on all branches, replace the literal with a wildcard pattern
such as 'feat-*' to capture multiple feature branches, or parameterize it via a
repository secret or environment variable so it won't become stale after
merging.

In `@scripts/hyperlane/03-evm-deploy.sh`:
- Around line 61-116: deploy_hyp_erc20 and the token enrollment functions rely
on implicitly global variables (DEPLOYED_EVM, TOKEN_ID); make these locals
and/or use the existing save_state/load_state to avoid fragile globals: declare
DEPLOYED_EVM as local inside deploy_hyp_erc20 (it’s already saved with
save_state "evm_hyp_erc20"), declare TOKEN_ID local where it’s assigned, and
update enroll_cosmos_side and enroll_evm_side to read values via load_state
("evm_hyp_erc20" and the token state key) or accept them as parameters instead
of depending on globals; ensure references to evm_to_bytes32, save_state, and
load_state remain consistent.

In `@scripts/hyperlane/04-agents.sh`:
- Around line 444-453: The loop that runs jq once per key is inefficient;
replace it with a single jq invocation that deletes all seven keys at once to be
atomic and faster: check [[ -f "$STATE_FILE" ]] and then run jq with a del()
call that removes .validator_addr, .bitsong_multisig_ism_id,
.basesepolia_multisig_ism, .validator_bitsong_announced,
.validator_basesepolia_announced, .ism_updated_cosmos_side, and
.ism_updated_evm_side in one expression, writing to "${STATE_FILE}.tmp" and
mv-ing it back (preserve the existing temp-file atomic write pattern used
elsewhere).
- Around line 70-124: The embedded Python call in fund_cosmos_signer both omits
a pre-check for the ecdsa dependency and leaks COSMOS_SIGNER_KEY on the process
command line; add an upfront check (e.g., run a short python3 -c "import ecdsa"
check and fail with a clear log_err if it raises) and change the python
invocation that derives the bech32 address to read the private key from stdin or
an environment-safe source instead of interpolating $COSMOS_SIGNER_KEY into the
command string (update the python3 call used in fund_cosmos_signer and related
logging to reflect this safer input method and surface dependency failures
clearly).

In `@scripts/hyperlane/06-fantoken-route.sh`:
- Around line 608-617: The CLEAN branch currently rewrites STATE_FILE once per
suffix; instead build the list of suffixes (same set used now) and perform a
single jq invocation that deletes all "ft_${FT_KEY}_${suffix}" keys in one pass
(use jq del with an array or chained del() calls generated from the suffix list)
and then mv the single temporary file back to STATE_FILE; keep the surrounding
log calls and the unregister_route call and reference CLEAN, FT_KEY, STATE_FILE
and unregister_route so you only perform one jq | mv instead of N sequential
rewrites.
- Around line 86-95: unregister_route currently uses grep -v with an unescaped
regex ("grep -v \"^${FT_KEY}$\"") so metas in FT_KEY can match unexpectedly;
update the pipeline in unregister_route (which calls load_state and save_state)
to use fixed-string exact-line matching (e.g., replace the grep invocation with
grep -Fxv or equivalent) so the removal compares FT_KEY as a literal exact line
and won’t treat characters like . or * as regex metacharacters.
- Around line 465-481: The script exposes private keys by passing
COSMOS_SIGNER_KEY and EVM_RELAYER_KEY directly on the docker run command line
(used for --chains.bitsong.signer.key and --chains.basesepolia.signer.key);
change this to load secrets from a safer source such as Docker secrets or
mounted files and reference those inside the container (e.g., mount
$BITSONG_HOME/cosmos_key:/run/secrets/cosmos_key:ro and use the file path inside
the relayer config or set an env var reading that file), or at minimum export
them as environment variables via -e (noting they remain visible in docker
inspect) and update the CLI flags to read from the secret file paths or env vars
rather than embedding the raw keys on the command line.
- Around line 182-212: The build_whitelist function currently constructs JSON by
concatenating strings which is fragile; change it to build the array using jq so
items are appended as real JSON objects. Replace the manual string assembly in
build_whitelist (including the blocks that add ubtsg using
token_id/evm_hyp_erc20 and the loop that adds each fantoken using
ft_${sym}_token_id and ft_${sym}_evm_hyp_erc20) with calls that pipe object
literals to jq --arg to set senderAddress and destinationDomain and use jq -s to
produce the final array; keep using evm_to_bytes32(token) and load_state(...) to
read values but pass them via jq arguments so escaping is handled and you never
manually trim trailing commas.
- Around line 57-60: ft_save and ft_load currently assume FT_KEY is set and will
silently use "ft__<suffix>" if empty; add a guard in both helper functions
(ft_save and ft_load) that asserts FT_KEY is non-empty before calling
save_state/load_state, and fail fast with an explanatory error message (and
non-zero exit) if FT_KEY is empty so you don't read/write the wrong state key.

In `@scripts/hyperlane/07-fantoken-test.sh`:
- Around line 117-121: The inline bytes32 padding duplicates existing helper
evm_to_bytes32; replace the manual conversion of evm_signer_addr ->
evm_signer_bytes32 (the hex trimming/lowercasing and printf padding) with a call
to evm_to_bytes32 from lib.sh, e.g. evm_signer_bytes32=$(evm_to_bytes32
"$evm_signer_addr"), keeping the preceding derivation and error check for
evm_signer_addr intact and ensuring the resulting evm_signer_bytes32 variable is
used as before.
- Around line 214-221: The script wrongly uses totalSupply() to infer the
signer's token holdings; update the check to call balanceOf(<signer_address>)
instead. Replace the cast call on ft_evm_hyp_erc20 from "totalSupply()(uint256)"
to "balanceOf(address)(uint256)" and pass the runtime signer address variable
used elsewhere in the script (e.g., the EVM signer variable like EVM_SIGNER or
EVM_FROM) while keeping EVM_RPC; store the result back into evm_balance and keep
the existing error logging path if the balance is "0". Ensure the balanceOf call
targets the same contract variable ft_evm_hyp_erc20.

In `@scripts/hyperlane/lib.sh`:
- Around line 119-129: The save_state function is vulnerable to concurrent
writes; wrap its read-modify-write against STATE_FILE with an exclusive flock to
prevent races: acquire an exclusive lock on STATE_FILE (or a lockfd derived from
STATE_FILE) before reading, running jq to update into a temp file, and mv the
temp into STATE_FILE, then release the lock; also apply a shared flock in
load_state when reading STATE_FILE to avoid torn reads. Update the save_state
and load_state functions to use flock (fall back to a safe error if flock is
unavailable) while keeping the existing behavior of creating STATE_FILE if
missing and preserving atomic mv.

In `@scripts/hyperlane/run-all.sh`:
- Around line 58-77: The script currently uses a string CLEAN_FLAG and an
unquoted expansion which relies on word-splitting; replace this with a shell
array (e.g. CLEAN_ARGS) that is empty by default and set to contain --clean when
CLEAN is true, then pass that array to run_phase invocations instead of
CLEAN_FLAG (update the calls that reference CLEAN_FLAG and the run_phase
invocations for 01-chain.sh, 03-evm-deploy.sh, 04-agents.sh,
06-fantoken-route.sh to expand the array), ensuring the array is expanded
properly so no spurious empty arguments are passed.

In `@scripts/hyperlane/status.sh`:
- Around line 34-43: The script uses GNU-only date parsing (date -d "$started")
inside the block handling status/started (variables status, started,
start_epoch), which fails on macOS; replace this with a portable approach:
detect GNU date vs BSD date (e.g., check if date -d works) and if unavailable
parse the timestamp using a macOS-compatible command (date -j -f or a small
portable fallback using python/perl) to compute start_epoch, preserving the rest
of the uptime calculation logic; ensure the change keeps the same variable names
(start_epoch, now_epoch, diff, uptime) and behavior for Linux while providing
the BSD/date-compatible branch for macOS.

Comment thread .github/workflows/push-docker-image.yml
Comment thread app/keepers/keepers.go
Comment thread scripts/hyperlane/02-hyperlane.sh
Comment thread scripts/hyperlane/02-hyperlane.sh
Comment thread scripts/hyperlane/03-evm-deploy.sh
Comment thread scripts/hyperlane/07-fantoken-test.sh
Comment thread scripts/hyperlane/lib.sh
Comment thread scripts/hyperlane/run-all.sh
Comment thread scripts/hyperlane/run-all.sh
Comment thread scripts/hyperlane/stop.sh
angelorc added 3 commits June 22, 2026 11:19
Adds the hyperlane (x/core) and warp (x/warp) module stores and
initializes them via RunMigrations. Materializes both module accounts
at the upgrade height and removes duplicate init-genesis entries.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@go.mod`:
- Line 117: Update the github.com/go-jose/go-jose/v4 dependency in go.mod from
v4.1.1 to v4.1.4 or higher to address the JWE decryption panic vulnerability.
Change the version number in the line containing "github.com/go-jose/go-jose/v4
v4.1.1 // indirect" to v4.1.4 or a later compatible version, then run "go mod
tidy" to update the go.sum file with the new dependency versions.
- Line 49: Update the google.golang.org/grpc dependency in the go.mod file from
version v1.75.0 to v1.79.3 or any newer stable version to address the
authorization bypass vulnerability (GHSA-p77j-4mvh-x3m3). After updating the
dependency version number for google.golang.org/grpc, run go mod tidy to ensure
all transitive dependencies are properly resolved. Additionally, verify that
authorization middleware is properly configured on all gRPC service definitions
throughout the codebase to prevent unauthorized access attempts.
- Line 20: The hyperlane-cosmos dependency at line 20 in go.mod transitively
pulls in a vulnerable version of go-ethereum (v1.14.12) that contains the RLPx
handshake vulnerability CVE-2026-26315. Add a replace directive in go.mod after
the existing module declarations to explicitly pin
github.com/ethereum/go-ethereum to version v1.16.9 or any v1.17.0 or later
version, which contains the security patch. After adding the replace directive
and running go mod tidy, you must also rotate the node key by deleting the
nodekey file from your data directory before restarting the service to prevent
potential private key exposure from the vulnerability.
- Around line 211-213: Update the versions of go.opentelemetry.io/otel and
go.opentelemetry.io/otel/sdk from v1.37.0 to v1.43.0 or later in the go.mod
file. This will address the HIGH-severity vulnerabilities including excessive
memory allocation via malformed baggage headers, arbitrary code execution via
PATH hijacking on BSD systems, and PATH hijacking vulnerabilities on
macOS/Darwin. Change both the go.opentelemetry.io/otel and
go.opentelemetry.io/otel/sdk module versions to the patched release to ensure
all security issues are resolved before production deployment.
- Line 191: The shamaton/msgpack/v2 dependency at version v2.2.2 contains a
denial-of-service vulnerability related to buffer validation for truncated
fixext data. Update the github.com/shamaton/msgpack/v2 dependency from v2.2.2 to
v2.4.1 or later in the go.mod file to fix the vulnerability. After updating the
version string, run go mod tidy to ensure the dependency tree is properly
resolved and validated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f614696a-4d2b-4700-98b8-d872ed1c2bca

📥 Commits

Reviewing files that changed from the base of the PR and between f6dafa0 and b3f8cf9.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (1)
  • go.mod

Comment thread go.mod
Comment thread go.mod
Comment thread go.mod
Comment thread go.mod
Comment thread go.mod
@angelorc angelorc merged commit 7207c48 into main Jun 23, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant