Skip to content

feat(web): segment bridge dependencies by model; add AggLayer bridge#323

Open
spalen0 wants to merge 17 commits into
masterfrom
bridge-model
Open

feat(web): segment bridge dependencies by model; add AggLayer bridge#323
spalen0 wants to merge 17 commits into
masterfrom
bridge-model

Conversation

@spalen0

@spalen0 spalen0 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #321, addressing review feedback:

"would also be good to segment between versions that are just bridged versions, or things that allow the bridge to mint the native version"

Why it matters

That distinction is the blast radius of a bridge compromise. A bridged representation (canonical escrowed on origin) bounds losses to remote supply + locked collateral. A bridge holding mint authority on the native token can mint unbacked supply and dilute every holder, including on mainnet. The page previously flattened both into one list.

Change

New required model per dependency, rendered as a badge column and enforced by scripts/check_bridges.mjs:

Model Meaning Colour
mint Bridge holds mint authority on the native token red
lock Canonical escrowed on origin; remote is a bridged representation blue
transport Bridges an underlying to remote strategies; assessed token isn't bridged purple
unknown Not verified — renders TODO and warns grey

Plus a fourth bridge: AggLayer (LxLy), surfaced during verification.

Final: 4 bridges, 22 dependencies — 9 lock, 5 mint, 8 transport, 0 unknown.

mint — the high-risk class (verified)

  • Paxos USDG — LayerZero OFTWrapper is Supply Controller SC3 with 45M USDG mint capacity.
  • Midas mHYPER — OFT adapter 0x148c…81a0 holds M_HYPER_MINT_OPERATOR_ROLE ("no onchain backing check") + burn role.
  • Re reUSDReMintBurnAdapter retains a live cross-chain mint path.
  • Centrifuge JAAA (LZ + CCIP) — Spoke 0xEC35…25aB holds wards, mints on cross-chain message. Mitigated by a 2-of-2 LZ+CCIP quorum.

lock — bridged representations (verified onchain)

Asset Adapter Escrowed
Cap stcUSD 0x983a…4137 25,311,191 (~52% of supply)
Sky USDS ~48.7M; adapter holds no wards
Resolv wstUSR 0xab17…1978 406,723 (~22%)
Resolv RLP 0x234c…d06c 133,516
KernelDAO hgETH / Fluid rsETH 0x85d4…8Ef3 46,254 rsETH (~9.6%)
InfiniFi siUSD 0x5f21…c3c0, iUSD 0xdd1c…3005 29,340 siUSD
Apyx apxUSD CCIP pool 0x0e9c…5BB5 LockReleaseTokenPool 1.6.1
Maple syrupUSDC CCIP pool 0x20B7…6491 LockReleaseTokenPool 1.5.1

New: AggLayer (LxLy)

PolygonZkEVMBridgeV2 (network 0 on Ethereum / 20 on Katana), verified onchain. All transport:

  • yvUSDKatanaStrategy ("Katana yvUSDC Compounder", ~$1.92M) wraps USDC into vbUSDC 0x53E8…a765e.
  • Spectra Finance — vbUSDC MetaVault on Katana (~$1.26M).
  • Flex — indirect via yvUSD's Katana leg.

Data-quality corrections

Removed (did not survive verification):

  • midas-mglobal — no non-Ethereum deployment; OFT adapter holds no mint/burn role (re-verified).
  • fx-fxusd — f(x) uses ProxyOFT for fETH/xETH/FXN/arUSD, not fxUSD; not an OFT on mainnet or Katana. Two fxUSD ERC-20s do exist on Katana via an unidentified route — recorded as TODO, not cleared.

Reports patched: fx-fxusd.md (LayerZero claim withdrawn; Katana route TODO), infinifi.md (verified adapters + CCIP-not-live, with reassessment triggers).

Method fix (reports/skill.md)

Pass 1.6 item 4 now requires segmenting the model and documents how to find the adapter. Three checks that look authoritative but miss the common plain mainnet ERC-20 + separate OFT Adapter + remote native OFT shape:

  • "mainnet token isn't an OFT" — expected under this shape;
  • LayerZero's public OFT registry — incomplete (has Resolv, not Cap/InfiniFi);
  • DeFiLlama chainsprotocol TVL, not token deployments (said "Ethereum only" for tokens live on Katana).

Correct approach: work backwards from the remote chain → confirm oftVersion()/endpoint()peers(30101) → mainnet adapter → verify token(), endpoint(), escrowed balance. Also records the CCIP TokenAdminRegistry and AggLayer bridge lookups, and requires recording the adapter address (no report had one).

Validation

npm run build passes — 4 bridges, 22 dependencies, 0 warnings.

Notes for reviewers

  • No scores or assessment dates changed — Cap/InfiniFi gaining a documented lock dependency, and fxUSD losing its LayerZero one, may warrant score review. Left as a maintainer call.
  • fxUSD's Katana route is an open TODO — it is not LayerZero and not an LxLy wrapper.

🤖 Generated with Claude Code

Addresses review feedback: distinguish bridged representations from
bridges that can mint the native token.

Adds a required 'model' per dependency, shown as a badge column:
- mint      bridge holds mint authority on the NATIVE token; a compromise
            mints unbacked supply and dilutes every holder (red)
- lock      canonical token escrowed on origin; remote is only a bridged
            representation; blast radius bounded (blue)
- transport bridges an underlying (USDC via CCTP) to remote strategies;
            the assessed token isn't bridged (purple)
- unknown   not yet verified; renders TODO and warns in check_bridges

Verified from reports: Paxos USDG (OFTWrapper = Supply Controller SC3,
45M mint capacity) and Midas mHYPER (adapter holds MINT+BURN operator
roles) are 'mint'; Sky USDS is 'lock' (adapter locks, no  on
USDS); Maple syrupUSDC is 'lock' (CCIP LockReleaseTokenPool).

Also removes midas-mglobal: its report states no non-Ethereum deployment
exists and the OFT adapter holds no mint/burn role, so it is not a live
bridge dependency (moved to LayerZero's ignore list).

skill.md Pass 1.6 now requires segmenting the model with worked examples
and how to verify (wards / hasRole(MINTER_ROLE) / supply-controller table).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
risk-score Ready Ready Preview, Comment Jul 16, 2026 7:22pm

Request Review

Verified via LayerZero's OFT registry + onchain reads (adapter.token(),
endpoint(), and escrowed balance). All four are OFT_ADAPTER on Ethereum
(canonical escrowed, remotes are bridged OFTs) — none can mint native:

- Resolv RLP      adapter 0x234c..d06c locks 133,516 RLP of 14.64M
- Resolv wstUSR   adapter 0xab17..1978 locks 406,723 wstUSR (~22%)
- KernelDAO hgETH rsETH adapter 0x85d4..8Ef3 locks 46,254 rsETH (~9.6%)
- Fluid           inherits rsETH's adapter model

Each adapter's endpoint() is the canonical LZ V2 EndpointV2 0x1a44..728c.

Unknowns: 12 -> 8. Note fxUSD is absent from LayerZero's OFT registry and
is not a native OFT, so its LayerZero dependency needs re-verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…solve all models

Reassessment scoped to confirming or dropping the bridge dependency.

fx-fxusd — claim was wrong, corrected in place. f(x) uses LayerZero
ProxyOFT for fETH/xETH/FXN/arUSD, NOT fxUSD. Verified: docs list fxUSD
with a single Ethereum address and no bridging entry; DefiLlama reports
Ethereum only; endpoint()/oftVersion() revert (not a native OFT); absent
from LayerZero's OFT registry; CCIP TokenAdminRegistry.getPool == 0x0.

infinifi — deployed but dormant, documented in place. The Outland stack
(PORTAL_HUB 0x1149..c6b8, CONNECTOR_LZ 0x54cB..0ee5, CONNECTOR_CCIP
0x4119..dd24) is deployed, but all hold 0 iUSD vs 62.4M supply, no bridge
holds RECEIPT_TOKEN_MINTER, no CCIP pool, absent from the LZ registry, and
DefiLlama reports Ethereum only. OFTCore is imported by GovernanceToken,
not iUSD. Added a reassessment trigger for activation.

Also resolves the last models:
- apyx-apxusd -> lock (TokenAdminRegistry pool 0x0e9c..5BB5 =
  LockReleaseTokenPool 1.6.1); syrupUSDC independently confirmed 'lock'
- centrifuge-jaaa -> mint (Spoke holds wards and mints on cross-chain
  message; mitigated by a 2-of-2 LZ+CCIP quorum)
- across-protocol -> transport (assessed asset is the V2 LP token, not
  bridged)
- cap-stcusd removed: sole LayerZero mention is an audit-scope string

Unknowns 12 -> 0. Bridges page: 17 deps (7 lock, 5 mint, 5 transport).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Corrects two wrong removals. My earlier verification only checked whether
the MAINNET token was a native OFT, plus LayerZero's public OFT registry
and DefiLlama chains. That misses the common pattern of a separate mainnet
OFT Adapter paired with a native OFT on the remote chain, and DefiLlama
'chains' tracks protocol TVL, not token deployments. Both assets bridge to
Katana, which those checks never covered.

Correct method (used here): find the remote OFT and read peers(30101) to
get the mainnet adapter, then verify token()/endpoint() and the escrowed
balance.

- cap-stcusd: RESTORED, model=lock. Adapter 0x983a..4137 escrows
  25,311,191 stcUSD (~52% of supply — the largest locked share on the
  page). The Electisec 'LayerZero vault' audit was a real signal, not an
  audit-string artifact as I claimed.
- infinifi: RESTORED, model=lock. siUSD adapter 0x5f21..c3c0 escrows
  29,340 siUSD; iUSD adapter 0xdd1c..3005 escrows 4.33 iUSD. The
  dependency is on siUSD/iUSD OFT adapters, not the Outland connectors,
  which is why the iUSD-only checks came up empty. Report claim of
  'deployed but dormant' was wrong and is replaced with verified facts.
  CCIP remains not live (no TokenAdminRegistry pool).
- fx-fxusd: LayerZero removal stands (verified not an OFT on either
  chain), but the report's 'no cross-chain bridge dependency' was too
  strong: two fxUSD ERC-20s exist on Katana via an unidentified route,
  now marked TODO.
- midas-mglobal: removal re-verified and stands (not on Katana, not an
  OFT).

Bridges page: 19 deps (9 lock, 5 mint, 5 transport), 0 unknown.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a fourth bridge, surfaced while correcting the Cap/InfiniFi errors:
AggLayer's LxLy unified bridge (PolygonZkEVMBridgeV2, network 0 on
Ethereum / 20 on Katana), verified onchain.

Dependencies (all transport — the assessed token is not itself bridged):
- yearn-yvusd    KatanaStrategy 'Katana yvUSDC Compounder' (~.92M USDC)
                 wraps USDC into vbUSDC 0x53E8..a765e and bridges to Katana
- spectra-finance vbUSDC MetaVault on Katana (~.26M TVL)
- flex           indirect: collateral is yvUSD, whose Katana leg sits
                 behind this bridge

Reports mentioning Katana whose route is LayerZero (midas-mhyper,
re-reusd, infinifi) or unidentified (fx-fxusd) are in the ignore list.

skill.md: documents the adapter-discovery method that my earlier
verification got wrong — a plain mainnet ERC-20 + separate OFT Adapter +
remote native OFT is the common shape, so 'mainnet token isn't an OFT',
LayerZero's public registry (incomplete), and DefiLlama 'chains' (protocol
TVL, not token deployments) all miss it. Work backwards from the remote
chain via peers(30101). Also records the CCIP TokenAdminRegistry and
AggLayer bridge lookups, and requires recording the adapter address.

Bridges page: 4 bridges, 22 deps (9 lock, 5 mint, 8 transport), 0 unknown.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@spalen0 spalen0 changed the title feat(web): segment bridge dependencies by mint/lock/transport model feat(web): segment bridge dependencies by model; add AggLayer bridge Jul 15, 2026
Addresses reviewer request: surface each LayerZero route's DVN
(Decentralized Verifier Network) quorum — how many independent verifiers
must attest a message — so a 1-of-1 single-point-of-failure (the April
2026 rsETH failure mode) is visible at a glance.

New 'dvn' field per LayerZero dependency, read onchain from each route's
ULN config (EndpointV2.getConfig type 2) with DVN addresses mapped to
provider names via LayerZero's metadata API. Rendered as a badge column:
green for a healthy quorum, red for a 1-of-1 'weak' config, links to the
config source. CCIP/CCTP/AggLayer rows show '—' (DVN is LZ-specific).

Verified onchain (mint-relevant receive side; 2026-07-16):
- 4-of-4: rsETH/hgETH + Fluid (conf 64), Midas mHYPER (Katana), InfiniFi
          siUSD/iUSD (Katana)
- 3-of-3: Cap stcUSD (Katana), Paxos USDG (Solana route)
- 2-of-2: Sky USDS, Re reUSD
- 2-of-3: Resolv RLP, Resolv wstUSR (optional-DVN threshold)
No 1-of-1 found on any current dependency.

TODO (issue #324): Centrifuge JAAA (LZ leg of a 2-of-2 MultiAdapter, not a
plain OFT) and Across Protocol (per-asset OFT routes, no single OApp).

check_bridges.mjs now warns if a LayerZero row omits 'dvn'. skill.md
documents the onchain read.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Zero

Reviewer flagged that USDS bridges via native L2 bridges. The sky-usds
report confirms two independent SkyLink systems, and the page only showed
the minor one:
- Native canonical L2 bridges (OP Stack: Base/Optimism/Unichain +
  Arbitrum Nitro) carry ~$0.45B USDS + ~812M sUSDS — the bulk.
- LayerZero carries only Solana + Avalanche (~$48.7M, <0.7%).

Adds a 'Native Rollup Bridges' category (canonical L2 bridges; lock model,
inherits rollup security, no DVN) and puts Sky USDS there as the primary
route. Scoped the existing LayerZero row to 'Solana + Avalanche only' so
it no longer reads as USDS's main bridge.

5 bridges, 23 deps, 0 warnings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…wrap fix

Reviewer feedback on the bridges page:
- Rename the 'dvn' field/column to 'security' so it can be reused by other
  bridges' verifier models later (CCIP RMN, etc.). Content unchanged — for
  LayerZero it's still the DVN quorum badge.
- Render the Security column ONLY for bridges that populate it (LayerZero
  today) via a per-bridge hasSecurity flag — CCIP/CCTP/AggLayer/native
  tables no longer carry an empty column.
- Add a Model legend at the top of the page explaining mint/lock/transport.
- Fix Details rendering: give Details and Integration proper min-widths and
  looser line-height so long text no longer wraps awkwardly (the table
  scrolls horizontally instead).

check_bridges + skill.md updated to the 'security' key.

5 bridges, 23 deps, 0 warnings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove the 'Model' title from the legend box (labels + explanations only).
- Rewrite the three explanations to be concise and parallel, per feedback
  that 'transport' was unclear:
    Mints native — bridge can mint the native token (unbacked supply dilutes every holder)
    Bridged      — token is locked at home; only a bridged copy exists on remote chains
    Transport    — token is not bridged, only the underlying asset is bridged (e.g. USDC)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reviewer asked whether CCTP has a security config like LayerZero's DVN set.
It does: Circle's MessageTransmitter has an on-chain signatureThreshold +
enabled-attester set. Verified onchain (2026-07-16), both V1
(0x0a99..8F81) and V2 (0x81D4..4B64) are 2-of-2.

Key difference surfaced in the tooltip/note: unlike LayerZero's independent
DVNs (LayerZero Labs, Nethermind, ...), BOTH CCTP attesters are
Circle-operated keys, and Circle's attesterManager can add/remove attesters
and change the threshold — so the 2-of-2 is redundancy within Circle, not
independent verification. Trust reduces to Circle.

Generalizes the reusable Security column: securityTitle() now uses a
per-row 'note' for the lead sentence and a 'providersLabel' (Attesters vs
DVNs). Security column now renders for CCTP + LayerZero.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per feedback: CCTP's attester set is always Circle-managed (no per-protocol
config), so a badge adds no signal — removed. CCIP is where the protocol
owns and configures its own token pool, so surface that instead.

CCIP Security = the protocol-defined token-pool config (verified onchain,
2026-07-16). Message verification itself is Chainlink's DON + RMN (not
protocol-set); what the protocol controls is the pool's rate limits, lanes
and ownership:
- apyx-apxusd  LockReleaseTokenPool 0x0e9c..5BB5: rate limiting ENABLED,
               ~5M apxUSD/lane; owner 0xf986..3cE2
- maple-syrupusdc LockReleaseTokenPool 0x20B7..6491: ENABLED, ~9.5M in /
               ~8.6M out per lane; rateLimitAdmin 0xCe1c..34E8
- centrifuge-jaaa: TODO — no standard TokenAdminRegistry pool (getPool=0x0),
               routes through the 2-of-2 MultiAdapter (issue #324)

Security column now renders for CCIP + LayerZero.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…olumn

The Security badge fit LayerZero (a single verifier-quorum number) but not
CCIP, whose security is two-layered: Chainlink-run verification (DON + RMN,
not protocol-configurable) plus a protocol-owned token pool (rate limits +
ownership). That nuance reads better as prose than a badge.

- Remove the 'security' fields from the CCIP rows (column now renders for
  LayerZero only).
- Rewrite the CCIP bridge description to explain both layers, contrast the
  Chainlink-operated verification with the protocol-configured pool, and
  cite the onchain-verified rate limits (apxUSD ~5M/lane; syrupUSDC ~9.5M
  in / ~8.6M out per lane).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tighten and align all five bridge blurbs to one shape (what it is → where
the trust/risk sits → special note):

- Chainlink CCIP: cut ~30%; keep the two-layer framing (Chainlink DON+RMN
  verification vs protocol-owned token pool); drop the onchain rate-limit
  figures from the blurb.
- Circle CCTP: name the concrete config (2-of-2 attesters, both
  Circle-operated and swappable) while still landing on 'trust reduces to
  Circle'.
- AggLayer: drop network-id annotations and the 'same address' aside; add
  the failure mode (bridge exploit or Vault Bridge vault fault).
- Native Rollup Bridges: de-emphasize the risk pile-up and focus on the
  real one — upgradeability; clarify 'lowest-trust' as lowest ADDED
  third-party trust (no external verifier network).
- LayerZero: unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@spalen0
spalen0 marked this pull request as ready for review July 16, 2026 18:04
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