Skip to content

Add Wormhole bridge auto-tracker#791

Open
aliersh wants to merge 7 commits into
DefiLlama:masterfrom
aliersh:wormhole-auto-tracker
Open

Add Wormhole bridge auto-tracker#791
aliersh wants to merge 7 commits into
DefiLlama:masterfrom
aliersh:wormhole-auto-tracker

Conversation

@aliersh

@aliersh aliersh commented May 18, 2026

Copy link
Copy Markdown
Contributor

This PR adds an auto-tracker for Wormhole Portal Token Bridge wrapped assets covering USDC, USDT, DAI, and EURC.

Reason

peggedassets-server already auto-tracks LayerZero (#762) and Hyperlane (#790) bridged supply via per-asset config files generated from each bridge's registry, both using single-source attribution. Wormhole's Portal Token Bridge uses permissionless attestation: an asset with multi-native deployment (USDC is minted natively by Circle on 8+ chains) gets multiple wormhole-wrapped variants per destination chain, one per source chain it was bridged from, each as a distinct ERC20 address. A single-source config can't capture this faithfully. This PR generalizes the bridge framework to admit multi-source attribution via BridgeAttribution[] and adds a Wormhole generator + per-asset configs for the four assets. As Wormhole or future permissionless bridges add new attestations, re-running the generator picks them up without further code changes.

Design notes

Wormhole's Portal Token Bridge uses permissionless attestation: an asset with multi-native deployment (USDC is minted natively by Circle on 8+ chains) gets multiple wormhole-wrapped variants per destination chain, one per source chain it was bridged from, each as a distinct ERC20 address. Faithful attribution requires modeling each (source, destination) pair.

To accommodate this, the bridge framework receives a small generalization: the shared attribution shape that LayerZero and Hyperlane already use (single source per asset) is extended so that a bridge can declare an array of attributions when its data is multi-source. The runtime groups contributions by (destChain, sourceChain) pair, so #790's dedup and guard logic apply naturally per pair. To keep all bridge types coherent, LayerZeroConfig and HyperlaneConfig are now aliases of a shared BridgeAttribution shape; topology is encoded at the consumer site (single-source bridges use BridgeAttribution, multi-source uses BridgeAttribution[]).

Applied behavior on the 4 wired assets: 3 net-new tracked (chain, source) slots emerge (USDT.base, DAI.base, DAI.celo). USDC's wormhole-wrapped variants collide with native minted status on each destination chain (Circle issues USDC natively across the major chains where wormhole-wrapped variants exist), so the runtime's logNativeMintedSkip correctly suppresses them, accounting for preserved, no double-counting introduced. EURC is wired with an empty wormholeConfig: {} for forward compatibility; Wormhole currently has no EURC attestations, so regeneration picks up future ones without code changes.

Changes

  • Introduce BridgeAttribution shared shape in bridgeConfig.ts; alias LayerZeroConfig and HyperlaneConfig to it; rename enrollBridge to enrollAttribution and add enrollSingleSource guard wrapper
  • Add WormholeConfig = BridgeAttribution[], extend BridgeConfigs.wormhole, add enrollMultiSource enroller, add wormholeConfig knobs to BridgeConfig (symbols, excludeChains, excludeSources, chainMap), and add dispatch branch in importAdapter.ts
  • Add generateWormholeConfig.ts — a build-time generator that reads @wormhole-foundation/sdk-base via its public token API, filters per asset symbol with EVM-only destinations, sane decimals, chain resolution, exclude lists, address dedup, and emits per-asset config files (~620 LOC)
  • Add @wormhole-foundation/sdk-base 4.20.0 (pinned exact, in devDependencies — generator is build-time only) and generate-wormhole-config npm script
  • Wire wormholeConfig: {} on USDC, USDT, DAI, and EURC in peggedData.ts
  • Generate per-asset config files: USDC (8 source chains, 61 token entries), USDT (ethereum-source, 7 entries), DAI (ethereum-source, 8 entries), EURC (empty [], forward-compat)

Summary by CodeRabbit

  • New Features

    • Added Wormhole bridge support for major stablecoins (DAI, USDT, USDC, EURC) with cross-chain token mappings across multiple destination chains
    • Enhanced bridge configuration system to support Wormhole topology alongside existing bridge options
  • Chores

    • Introduced automated tooling for generating Wormhole configuration files

Review Change Stack

aliersh added 6 commits May 18, 2026 11:48
- add shared `BridgeAttribution` type for per-bridge per-source attributions
- alias `LayerZeroConfig` and `HyperlaneConfig` to `BridgeAttribution`
- rename `enrollBridge` to `enrollAttribution`
- add `enrollSingleSource` guard wrapper
- add `WormholeConfig` (`BridgeAttribution[]`) and `BridgeConfigs.wormhole`
- declare `BridgeConfigs` single-source members with literal `BridgeAttribution` shape
- add `enrollMultiSource` enroller wired in `collectContributionsByDestination`
- add `wormholeConfig` knobs to `BridgeConfig` and dispatch branch in `importAdapter`
- add `@wormhole-foundation/sdk-base` exact-pin `devDependencies` entry
- add `generate-wormhole-config` npm script
- add generator script with registry loader, cli parsing, asset orchestration, and stub `generateForAsset`
- implement `generateForAsset`: match by symbol on wormhole-wrapped tokens, filter on self-reference, evm-address shape, decimals bounds, llamakey resolution, exclude lists, and address dedup
- apply bilateral `chainMap` with warn-once on unknown-target remappings; flag decimals diverging from the per-asset modal
- group hits by source chain, sort outer and inner alphabetical, and emit `WormholeConfig` files (or stdout when `--dry`) with auto-doc header
- extend `main` with end-of-run aggregate summary; add `Hit`, `AssetResult` types and `EVM_ADDRESS_RE` constant
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@aliersh has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 49 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b9c95473-ed31-44a9-b6c7-986f438185dc

📥 Commits

Reviewing files that changed from the base of the PR and between 0eeb037 and ce96088.

📒 Files selected for processing (1)
  • src/adapters/peggedAssets/helper/scripts/generateWormholeConfig.ts
📝 Walkthrough

Walkthrough

This PR extends the pegged assets bridge configuration system to support Wormhole, a cross-chain messaging protocol. It introduces a unified type schema, a code-generating script that reads the Wormhole registry and outputs per-asset configuration files, and runtime integration to load and apply those configurations alongside existing LayerZero and Hyperlane bridges.

Changes

Wormhole Bridge Integration

Layer / File(s) Summary
Bridge Configuration Types and Schema
src/adapters/peggedAssets/helper/bridgeConfig.ts, src/peggedData/types.ts
Introduces shared BridgeAttribution type unifying source chain and token lists across topologies; LayerZeroConfig and HyperlaneConfig become aliases; new WormholeConfig type added as BridgeAttribution[]; BridgeConfigs expands to include optional wormhole field with per-asset symbol/exclusion/chainMap configuration.
Enrollment Refactoring for Multi-Source Support
src/adapters/peggedAssets/helper/bridgeConfig.ts
Refactors collectContributionsByDestination to enroll single-source configs (LayerZero, Hyperlane) and multi-source configs (Wormhole) via separate enrollSingleSource/enrollMultiSource helpers, both delegating to shared enrollAttribution routine.
Wormhole Config Generator Script
src/adapters/peggedAssets/helper/scripts/generateWormholeConfig.ts
New 621-line generator loads @wormhole-foundation/sdk-base registry, filters tokens by wrapped status/EVM validity/chain mappings, deduplicates by destination/source/address, flags decimal outliers, groups by source chain, generates or prints per-adapter wormholeConfig.ts files, and syncs helper/chains.json with DefiLlama allowlist. Supports --asset flag to filter targets and --dry mode to preview output.
Package Configuration and Dependencies
package.json
Adds @wormhole-foundation/sdk-base to devDependencies and registers generate-wormhole-config npm script running the generator via ts-node --transpile-only.
Generated Wormhole Configuration Files
src/adapters/peggedAssets/{dai,eurc,tether,usd-coin}/wormholeConfig.ts
Auto-generated modules exporting WormholeConfig arrays; Dai, Tether, and USD Coin export token mappings from ethereum (and additional sources for USDC); EURC exports empty array with note that no Wormhole entries exist in registry.
Runtime Integration and Configuration Wiring
src/peggedAssets/utils/importAdapter.ts, src/peggedData/peggedData.ts
importAdapter now dynamically imports and merges wormholeConfig modules via addBridgeConfigs when bridgeConfig.wormholeConfig is present, logging warnings on missing modules; peggedData.ts wires wormholeConfig: {} entries into Tether, USD Coin, Dai, and EURC asset definitions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • DefiLlama/peggedassets-server#790: Modifies the same bridge configuration pipeline (bridgeConfig.ts and importAdapter.ts), extending the unified LayerZero/Hyperlane approach to add Wormhole as a new topology.

Poem

🐰 A rabbit hops through chains with glee,
Wormholes map from sea to sea,
Dai and USDC dance across the night,
Config-generated, bridges burn bright! ✨🌉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% 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
Title check ✅ Passed The title 'Add Wormhole bridge auto-tracker' directly and clearly summarizes the main change: adding automatic tracking of Wormhole Portal Token Bridge wrapped assets.
Description check ✅ Passed The PR description is comprehensive and well-structured, explaining the reason, design rationale, and detailed changes; however, it does not follow the provided template format for new asset listings.
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

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/peggedData/types.ts (1)

82-87: 💤 Low value

Consider documenting the chainMap key naming difference.

The chainMap key type differs across bridge configs:

  • lzConfig.chainMap and hyperlaneConfig.chainMap use [llamaKey: string]
  • wormholeConfig.chainMap uses [whLowerName: string]

This inconsistency likely reflects different input formats (Wormhole registry names vs DefiLlama keys), but adding a brief comment explaining why the key type differs would help future maintainers understand the design choice.

🤖 Prompt for 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.

In `@src/peggedData/types.ts` around lines 82 - 87, Update the type comment for
wormholeConfig.chainMap to explain the naming difference: note that
wormholeConfig.chainMap keys are the Wormhole registry names
(normalized/lowercased, hence whLowerName) while lzConfig.chainMap and
hyperlaneConfig.chainMap expect DefiLlama chain keys (llamaKey), and clarify
that the mapping is applied bilaterally to source and destination; place this
explanatory comment next to the wormholeConfig.chainMap declaration in types.ts
so future maintainers can see why the key naming differs.
🤖 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 `@src/adapters/peggedAssets/helper/scripts/generateWormholeConfig.ts`:
- Around line 131-139: The CLI currently allows `--asset` without a value
because the generic parser treats missing next tokens as flags; modify the
parser so that when `key === "asset"` and `next` is undefined or
`next.startsWith("--")` you do NOT set `args.asset = true` but instead surface
an error (throw or call process.exit(1) with a clear message like "Missing value
for --asset") so the run fails rather than defaulting to processing all assets;
also keep the downstream logic that computes `const asset = typeof args.asset
=== "string" ? args.asset : undefined` so it receives only a real string or the
program exits.
- Around line 376-380: The current validation for token.decimals uses typeof and
range checks which let NaN through; update the guard in the loop that handles
token/peggedAsset to explicitly reject non-finite values by using
Number.isFinite(token.decimals) combined with the existing range checks (e.g.,
ensure Number.isFinite(token.decimals) && token.decimals >= 0 && token.decimals
<= 77) so that NaN and Infinite values are rejected and the existing stderr
warning/continue behavior is preserved for invalid decimals.

---

Nitpick comments:
In `@src/peggedData/types.ts`:
- Around line 82-87: Update the type comment for wormholeConfig.chainMap to
explain the naming difference: note that wormholeConfig.chainMap keys are the
Wormhole registry names (normalized/lowercased, hence whLowerName) while
lzConfig.chainMap and hyperlaneConfig.chainMap expect DefiLlama chain keys
(llamaKey), and clarify that the mapping is applied bilaterally to source and
destination; place this explanatory comment next to the wormholeConfig.chainMap
declaration in types.ts so future maintainers can see why the key naming
differs.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89bb4697-50eb-4ad2-86e1-eebd2f2dd8cb

📥 Commits

Reviewing files that changed from the base of the PR and between c2a87a9 and 0eeb037.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • package.json
  • src/adapters/peggedAssets/dai/wormholeConfig.ts
  • src/adapters/peggedAssets/eurc/wormholeConfig.ts
  • src/adapters/peggedAssets/helper/bridgeConfig.ts
  • src/adapters/peggedAssets/helper/scripts/generateWormholeConfig.ts
  • src/adapters/peggedAssets/tether/wormholeConfig.ts
  • src/adapters/peggedAssets/usd-coin/wormholeConfig.ts
  • src/peggedAssets/utils/importAdapter.ts
  • src/peggedData/peggedData.ts
  • src/peggedData/types.ts

Comment thread src/adapters/peggedAssets/helper/scripts/generateWormholeConfig.ts
Comment thread src/adapters/peggedAssets/helper/scripts/generateWormholeConfig.ts Outdated
- throw when `--asset` has no value
- reject `NaN` and `±Infinity` in the decimals guard via `Number.isFinite`
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