Skip to content

feat: first-class Midnight support - #1

Draft
ctoyan wants to merge 8 commits into
midnight-v1from
feat/34-midnight-explorer
Draft

feat: first-class Midnight support#1
ctoyan wants to merge 8 commits into
midnight-v1from
feat/34-midnight-explorer

Conversation

@ctoyan

@ctoyan ctoyan commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

First-class Midnight support, shaped so every commit maps onto an upstream submission. One commit per concern:

  1. build: pnpm override of @hyperlane-xyz/utils with a build carrying ProtocolType.Midnight + its 32-byte-hex codecs. The canonical changeset is equilibriumco/hyperlane-monorepo branch feat/midnight-protocol-type (based on upstream main — the ready-to-send upstream PR, incl. the sdk/widgets maps and TokenStandard.MidnightHyp*); the vendored tarball is built from its 33.0.2 backport because this app pins 33.0.2. utils resolves once in the dependency graph, so sdk/widgets inherit it and protocol: 'midnight' survives ChainMetadataSchema (its forwardCompatibleEnum reads the enum at runtime). The override and both branches disappear once upstream ships the protocol.
  2. feat: chain data comes from the registry: NEXT_PUBLIC_REGISTRY_URL/BRANCHequilibriumco/hyperlane-registry (PR feat: add midnight chain and the NIGHT/midnight-sepolia warp route hyperlane-registry#1) — the existing custom-registry mechanism, no chain data in this repo. config.apiUrl reads NEXT_PUBLIC_API_URL. One genuine fix supports it: chain logos were hardcoded to the canonical registry's CDN path, so custom-registry chains rendered iconless — logos now resolve through the configured registry (upstream-proposable on its own).
  3. feat: status timeline for midnight messages. Upstream gates the card on protocol === ethereum for both ends and never passes multiProvider into useMessageStage, so the widget is inert even for EVM (delivered = steps forced complete without timings, pending = stuck at "Sent"). Delivered messages now compute real per-stage timings; the pending-message probes fail soft.
  4. fix: postgresByteaToAddress tolerates NULL bytea (the scraper's transaction.recipient is nullable and is NULL for midnight; upstream throws and the parse helpers drop the whole row as "Message not found"); MidnightHypNative/MidnightHypCollateral recognized for collateral badges Starknet-workaround-style until the SDK dependency carries the midnight standards.

The NULL-bytea fix, the useMessageStage/multiProvider fix, and the custom-registry logo fix are all upstream-proposable to hyperlane-xyz/hyperlane-explorer independently of Midnight.

Verified: typecheck, oxlint, next build green; live fetch against the registry fork confirms the midnight chain (protocol preserved through the explorer's zod path), the logo URI (CSP-allowed host), and the NIGHT/midnight-sepolia route with MidnightHypNative. The 8 pre-existing test failures (scheduleWhenIdle, fetchPiChainMessages) fail identically on the unmodified base commit. Live per-card verification against scraped stagenet+sepolia traffic is tracked in the midnight integration.

The canonical midnight protocol changeset (ProtocolType.Midnight, address
codecs, sdk/widgets maps, TokenStandard.MidnightHyp*) lives on
equilibriumco/hyperlane-monorepo branch feat/midnight-protocol-type, based
on upstream main - the future upstream PR. This app pins
@hyperlane-xyz/*@33.0.2, so the vendored tarball is built from that
changeset's 33.0.2 backport (branch midnight-utils-33.0.2). utils resolves
exactly once in this dependency graph, so the override propagates into
sdk/widgets, and the SDK's forwardCompatibleEnum reads the enum at runtime
- protocol: 'midnight' survives ChainMetadataSchema without an sdk
override. Everything here disappears once upstream ships the protocol.
@ctoyan
ctoyan force-pushed the feat/34-midnight-explorer branch from c624d0c to 70e2a1e Compare July 28, 2026 16:20
ctoyan added 3 commits July 28, 2026 21:39
Chain metadata, addresses, logos, and the NIGHT warp route come from the
registry configured via NEXT_PUBLIC_REGISTRY_URL/BRANCH
(equilibriumco/hyperlane-registry) - the existing custom-registry
mechanism, no chain data in this repo. config.apiUrl reads
NEXT_PUBLIC_API_URL so the app can point at a local scraper Hasura.

One real fix supports it: chain logos were hardcoded to the canonical
registry's CDN path, so custom-registry chains rendered iconless (404) -
resolve logos through the configured registry instead.
Upstream gates the timeline card on protocol === ethereum for both ends and
never passes multiProvider into useMessageStage, so the widget is inert even
for EVM chains (delivered messages get no per-stage timings; pending ones
sit at Sent). Delivered-message stage timings are protocol-agnostic
arithmetic over DB timestamps and blocks metadata, and the pending-message
probes fail soft, so midnight qualifies alongside EVM once the provider is
actually passed.
- postgresByteaToAddress returns '' for NULL/short bytea instead of
  throwing: the scraper's transaction.recipient is nullable and IS null for
  midnight, and the parse helpers swallow the exception and drop the whole
  message ('Message not found' for a row the API already returned).
- MidnightHypNative/MidnightHypCollateral drive the collateral banner and
  graph badges the same way the existing Starknet workaround does, until
  this app's SDK version carries the midnight token standards.
@ctoyan
ctoyan force-pushed the feat/34-midnight-explorer branch from 70e2a1e to 0d99893 Compare July 28, 2026 18:39
ctoyan added 4 commits July 29, 2026 13:04
The Warp Route Overview card showed no balance for the Midnight leg:
balance fetching has exactly two paths (EVM adapters in the browser,
and a server-side API route for Sealevel), and MidnightHypNative fell
through both. Mirror the Sealevel pattern: a
/api/midnight-warp-route-balance route validates the request against
the registry, then reads the warp contract's locked native NIGHT from
the chain's indexer GraphQL endpoint (contractAction.unshieldedBalances,
all-zeros token type). Native only: a collateral variant would need a
token-type mapping first.
TokenIcon resolves relative logoURIs against the canonical registry's
CDN, so custom-registry routes rendered letter fallbacks. Rewrite
relative token logo paths to absolute URLs on the configured registry
when warp route data loads (companion to the chain-logo fix in
loadChainMetadata). The published-configs fallback keeps canonical
relative paths, which the CDN serves.
A pending transfer into a Midnight collateral leg crashed the
collateral query: fetchCollateralBalance resolves undefined on every
skip path, and react-query v5 treats an undefined resolution as an
error ('data is undefined'). Resolve null instead (any non-EVM
collateral destination hits this upstream too), and give Midnight a
real check: read the locked balance through the shared
/api/midnight-warp-route-balance client, same path as the Warp Route
Overview balances.
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