ISS
← Field Notes
WEB3
April 1, 2026 · Web3 · 2 min read

Normalizing Cross-Chain Bridge Data Into One Comparable API

A plugin-based monorepo that aggregates volume, liquidity, and rate data from cross-chain bridges into a canonical format so providers can actually be compared side by side.

Cross-chain bridge users and analysts have a data problem that nobody wants to own: every bridge exposes its numbers differently. Across, LayerZero, Circle CCTP, Wormhole, and the rest each have their own APIs, asset formats, and data structures. If you want to compare volume, liquidity, or rates across them, you first have to make them speak the same language. This dashboard is my attempt to do exactly that.

A Canonical Format Under a Plugin Architecture

The core design decision was to normalize everything into one canonical format. Each bridge becomes a plugin that knows how to talk to its own API and how to translate its output into the shared shape. The rest of the system, the aggregation and the comparison UI, only ever sees canonical data. Adding a new provider means writing a new plugin, not rewiring the whole pipeline.

Structurally it is a Turborepo monorepo. There is a Hono API server that aggregates across all the plugins, and a standalone canonical-asset-service that handles the asset listing and the canonical ID transformation. The RPC API is type-safe via oRPC, which matters when the whole value of the project is that the data lines up, because a type error is a data mismatch caught early. Volume data comes from DUNE Analytics, covering all 26 providers.

Being Honest About What Does Not Work Yet

This is MVP-stage contract work, and the README is blunt about the open issues, which I think is the right way to run a build in the open. The volume table does not populate on production because the DUNE API key is not deployed there. Volume-by-asset filtering is not implemented. Liquidity queries are slow, around 45 seconds, and unreliable. Rate quotes are shaky for some providers. Five providers, including lifi and axelar, exist in the code but are commented out because of module resolution issues.

Four providers are active and working end to end: near_intents, across, layerzero, and circle_cctp. That is enough to prove the architecture, which was the point of the MVP.

The Takeaway

The lesson from this one is that the plugin boundary is where the real design work lives. Once you commit to a canonical format and force every provider through the same translation layer, adding coverage becomes mechanical and the hard problems become visible and specific. The known issues list reads like a punch list precisely because the architecture already isolated each failure to a single plugin or a single missing key, rather than smearing it across the whole system.

Have something that needs building, or stabilizing?

These notes are the work log. The paid work runs through Moonshine Labs, my product and engineering studio. Tell us what you're building, or grab a call.

Work with us →
the studio: moonshinelabs.io