Skip to content

Add Hyperlynx V3 yield adapter (HyperEVM)#2763

Open
isagieth wants to merge 3 commits into
DefiLlama:masterfrom
isagieth:add-hyperlynx-yields
Open

Add Hyperlynx V3 yield adapter (HyperEVM)#2763
isagieth wants to merge 3 commits into
DefiLlama:masterfrom
isagieth:add-hyperlynx-yields

Conversation

@isagieth

@isagieth isagieth commented Jun 28, 2026

Copy link
Copy Markdown

Adds a yields adapter for Hyperlynx, a Uniswap V3 fork DEX on HyperEVM. Per-pool base APY is computed from swap fees (feesUSD × 365 / tvlUsd) using the project subgraph, modeled on the existing hyperswap-v3 adapter. V3 concentrated-liquidity pools only (V2 pools are below the $10k display threshold).

⚠️ Draft — blocked on TVL listing

This is intentionally a draft. yield-server requires protocolId to match Hyperlynx's id in https://api.llama.fi/protocols, which is only assigned once the TVL adapter merges. protocolId is currently a TODO placeholder and will be filled in (and this PR marked ready) as soon as the TVL PR lands.

Related PRs (same protocol)

Details

  • Project / slug: hyperlynx
  • Chain: hyperevm
  • Source: Goldsky subgraph (uniswap-v3-hyperevm)
  • apyBase: from latest-day pool fees; apyBase7d from the trailing 7-day average
  • Pools shown today: 1 (WHYPE-USDC 0.3%, ~$30k TVL); expands automatically as more pools cross $10k TVL

Website: https://hyperlynx.fi · Docs: https://hyperlynx.gitbook.io/hyperlynx-docs/

Summary by CodeRabbit

  • New Features
    • Added support for a new HyperEVM liquidity pool adapter.
    • Displays APY for concentrated-liquidity pools, including base APY and 7-day APY estimates.
    • Includes TVL, 7-day fees, volume, and pool fee tier details for supported pools.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new hyperlynx-v3 adapter module that queries a Goldsky subgraph for HyperEVM Uniswap v3 pool data, paginates results, computes per-pool TVL and APY metrics (base and 7-day), and exports the adapter interface.

Hyperlynx v3 Adapter

Layer / File(s) Summary
Config, GraphQL query, and pagination
src/adaptors/hyperlynx-v3/index.js
Defines project/chain constants, subgraph URL, poolsQuery for fetching pools with token metadata and day data, and fetchAllPools() which paginates via first/skip until exhausted.
APY computation and module export
src/adaptors/hyperlynx-v3/index.js
Implements apy() to derive tvlUsd, apyBase (latest day fees annualized), and apyBase7d (7-day aggregated fees annualized), filters via utils.keepFinite, and exports protocolId, timetravel, apy, and url.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • 0xkr3p

Poem

🐇 A new pool hops onto the chain,
Hyperlynx v3, TVL's the game,
Fees annualized, day by day,
Goldsky graphs light the way,
keepFinite keeps bad data tame! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding a Hyperlynx V3 yield adapter for HyperEVM.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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.

@github-actions

Copy link
Copy Markdown

Error while running hyperlynx adapter:

Test Suites: 1 failed, 1 total
Tests: 2 failed, 9 passed, 11 total
Snapshots: 0 total
Time: 0.304 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬──────────────────┬─────────────┬──────────────┬────────────────────┬────────────────────┬───────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬──────────┬──────────────────────────────────┬───────────────────┬────────────────────┐
│ (index) │ pool                                         │ chain            │ project     │ symbol       │ tvlUsd             │ apyBase            │ apyBase7d         │ underlyingTokens                                                                               │ poolMeta │ url                              │ volumeUsd1d       │ volumeUsd7d        │
├─────────┼──────────────────────────────────────────────┼──────────────────┼─────────────┼──────────────┼────────────────────┼────────────────────┼───────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────────────────────────────┼───────────────────┼────────────────────┤
│ 0       │ '0xe45326a0fd9a4fd5989fd3ce79b5b5ad737f34c7' │ 'Hyperliquid L1' │ 'hyperlynx' │ 'WHYPE-USDC' │ 30081.361971334605 │ 3.1843960947498315 │ 6.227189951410667 │ [ '0x5555555555555555555555555555555555555555', '0xb88339cb7199b77e23db6e890353e22632ba630f' ] │ '0.3%'   │ 'https://hyperlynx.fi/liquidity' │ 874.8033934819543 │ 11974.945068022767 │
└─────────┴──────────────────────────────────────────────┴──────────────────┴─────────────┴──────────────┴────────────────────┴────────────────────┴───────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴──────────┴──────────────────────────────────┴───────────────────┴────────────────────┘

@isagieth isagieth changed the title Add Hyperlynx yield adapter (HyperEVM V3 pools) Add Hyperlynx yield adapter Jun 28, 2026
@github-actions

Copy link
Copy Markdown

Error while running hyperlynx adapter:

Test Suites: 1 failed, 1 total
Tests: 2 failed, 9 passed, 11 total
Snapshots: 0 total
Time: 0.274 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬──────────────────┬─────────────┬──────────────┬────────────────────┬────────────────────┬───────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────┬──────────────────────────────────┬───────────────────┬────────────────────┐
│ (index) │ pool                                         │ chain            │ project     │ symbol       │ tvlUsd             │ apyBase            │ apyBase7d         │ underlyingTokens                                                                               │ poolMeta    │ url                              │ volumeUsd1d       │ volumeUsd7d        │
├─────────┼──────────────────────────────────────────────┼──────────────────┼─────────────┼──────────────┼────────────────────┼────────────────────┼───────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┼──────────────────────────────────┼───────────────────┼────────────────────┤
│ 0       │ '0xe45326a0fd9a4fd5989fd3ce79b5b5ad737f34c7' │ 'Hyperliquid L1' │ 'hyperlynx' │ 'WHYPE-USDC' │ 30081.361971334605 │ 3.1843960947498315 │ 6.227189951410667 │ [ '0x5555555555555555555555555555555555555555', '0xb88339cb7199b77e23db6e890353e22632ba630f' ] │ '0.3% (V3)' │ 'https://hyperlynx.fi/liquidity' │ 874.8033934819543 │ 11974.945068022767 │
└─────────┴──────────────────────────────────────────────┴──────────────────┴─────────────┴──────────────┴────────────────────┴────────────────────┴───────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────┴──────────────────────────────────┴───────────────────┴────────────────────┘

Match merged TVL/dimension structure (Hyperlynx V3 = id 8107). V2 yields
deferred until a pair crosses the $10k display threshold.
@github-actions

Copy link
Copy Markdown

The hyperlynx-v3 adapter exports pools:

Test Suites: 1 passed, 1 total
Tests: 11 passed, 11 total
Snapshots: 0 total
Time: 0.229 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬──────────────────┬────────────────┬──────────────┬────────────────────┬───────────────────┬────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬──────────┬──────────────────────────────────┬───────────────────┬───────────────────┐
│ (index) │ pool                                         │ chain            │ project        │ symbol       │ tvlUsd             │ apyBase           │ apyBase7d          │ underlyingTokens                                                                               │ poolMeta │ url                              │ volumeUsd1d       │ volumeUsd7d       │
├─────────┼──────────────────────────────────────────────┼──────────────────┼────────────────┼──────────────┼────────────────────┼───────────────────┼────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────────────────────────────┼───────────────────┼───────────────────┤
│ 0       │ '0xe45326a0fd9a4fd5989fd3ce79b5b5ad737f34c7' │ 'Hyperliquid L1' │ 'hyperlynx-v3' │ 'WHYPE-USDC' │ 27309.404670824668 │ 7.939068848011914 │ 27.968469115170308 │ [ '0x5555555555555555555555555555555555555555', '0xb88339cb7199b77e23db6e890353e22632ba630f' ] │ '0.3%'   │ 'https://hyperlynx.fi/liquidity' │ 1980.011359633746 │ 48827.54052627883 │
└─────────┴──────────────────────────────────────────────┴──────────────────┴────────────────┴──────────────┴────────────────────┴───────────────────┴────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴──────────┴──────────────────────────────────┴───────────────────┴───────────────────┘

@isagieth isagieth changed the title Add Hyperlynx yield adapter Add Hyperlynx V3 yield adapter (HyperEVM) Jun 30, 2026
@isagieth
isagieth marked this pull request as ready for review June 30, 2026 03:12

@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: 3

🤖 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/adaptors/hyperlynx-v3/index.js`:
- Around line 64-89: The adaptor in hyperlynx-v3 is dropping entire pools when
`poolDayData[0]` is missing because `apyBase` and `apyBase7d` become non-finite
and then `utils.keepFinite()` filters them out. Update the pool mapping logic in
the main return path so pools are still returned even when the daily bucket is
absent, and leave APY fields as non-finite/null-safe values for downstream
handling by `triggerAdaptor` instead of filtering the whole object out.
- Around line 67-71: The trailing APY calculation in the Hyperlynx v3 adaptor is
using the number of available day buckets instead of a fixed 7-day window, so
`apyBase7d` is inflated for newer pools. Update the `apyBase7d` computation in
`src/adaptors/hyperlynx-v3/index.js` to either divide by 7 regardless of
`days.length` or return no value until the `days` array contains seven buckets,
and keep the logic localized near the existing `fees7d`, `volume7d`, and
`apyBase7d` calculations.
- Around line 41-45: The Goldsky GraphQL call in the hyperlynx-v3 adaptor is
missing a timeout/abort path, so a stalled response can block the run. Update
the request in the adaptor’s main fetch logic around the request(SUBGRAPH_URL,
poolsQuery, ...) call to pass a signal from AbortSignal.timeout(...) or an
AbortController with a bounded timeout, and handle the abort path cleanly so the
request fails fast instead of hanging.
🪄 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: 442fd152-32e6-435a-8c21-990ed435ec05

📥 Commits

Reviewing files that changed from the base of the PR and between d8ed6b6 and 32fc1d3.

📒 Files selected for processing (1)
  • src/adaptors/hyperlynx-v3/index.js

Comment on lines +41 to +45
const { pools } = await request(SUBGRAPH_URL, poolsQuery, {
first,
skip,
minTvl: String(MIN_TVL_USD),
});

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the adaptor and request implementation
git ls-files | rg '^src/adaptors/hyperlynx-v3/index\.js$|^src/.*request.*|^src/.*goldsky.*|^src/.*subgraph.*|^src/.*fetch.*'

echo '--- hyperlynx-v3 index.js ---'
cat -n src/adaptors/hyperlynx-v3/index.js | sed -n '1,180p'

echo '--- likely request implementations ---'
rg -n "function request|const request =|export .*request|AbortController|timeout|fetch\(" src --glob '!**/*.map' --glob '!**/dist/**' --glob '!**/build/**'

Repository: DefiLlama/yield-server

Length of output: 17449


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- triggerAdaptor / adaptor runner ---'
rg -n "triggerAdaptor|await apy\(|apy\(\)" src test . --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'

echo '--- graphql-request dependency/version ---'
cat package.json | sed -n '1,220p'
echo '--- lockfile references to graphql-request ---'
rg -n '"graphql-request"|graphql-request@|graphql-request' package-lock.json yarn.lock pnpm-lock.yaml

echo '--- local node_modules check (if present) ---'
if [ -d node_modules/graphql-request ]; then
  find node_modules/graphql-request -maxdepth 2 -type f | sed -n '1,80p'
fi

Repository: DefiLlama/yield-server

Length of output: 14751


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- src/handlers/triggerAdaptor.js ---'
cat -n src/handlers/triggerAdaptor.js | sed -n '1,180p'

echo '--- package.json ---'
cat -n package.json | sed -n '1,220p'

echo '--- graphql-request references in lockfiles ---'
if [ -f package-lock.json ]; then rg -n '"graphql-request"|graphql-request' package-lock.json | sed -n '1,40p'; fi
if [ -f yarn.lock ]; then rg -n '^graphql-request@|graphql-request@' yarn.lock | sed -n '1,40p'; fi
if [ -f pnpm-lock.yaml ]; then rg -n 'graphql-request' pnpm-lock.yaml | sed -n '1,40p'; fi

echo '--- local graphql-request package files (if installed) ---'
if [ -d node_modules/graphql-request ]; then
  find node_modules/graphql-request -maxdepth 2 -type f | sed -n '1,80p'
fi

Repository: DefiLlama/yield-server

Length of output: 10768


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- graphql-request package.json ---'
cat -n node_modules/graphql-request/package.json | sed -n '1,220p'

echo '--- graphql-request README snippets for request/options/signal ---'
rg -n "signal|timeout|request\(|GraphQLClient|fetch" node_modules/graphql-request/README.md | sed -n '1,120p'

echo '--- graphql-request type surface ---'
find node_modules/graphql-request -maxdepth 2 \( -name '*.d.ts' -o -name '*.ts' \) | sed -n '1,120p'

Repository: DefiLlama/yield-server

Length of output: 5581


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- README around request/fetch options ---'
sed -n '60,140p' node_modules/graphql-request/README.md

echo '--- type exports and request signatures ---'
rg -n "export declare function request|type RequestOptions|interface RequestOptions|signal|fetchOptions|RequestDocument" node_modules/graphql-request/build -g '*.d.ts' | sed -n '1,200p'

echo '--- main entrypoint d.ts excerpt ---'
sed -n '1,220p' node_modules/graphql-request/build/entrypoints/main.d.ts

Repository: DefiLlama/yield-server

Length of output: 10306


Add a timeout/abort path to the Goldsky request. graphql-request supports signal, so a bounded AbortSignal.timeout(...) or AbortController here would keep a stalled response from blocking the adaptor run.

🤖 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/adaptors/hyperlynx-v3/index.js` around lines 41 - 45, The Goldsky GraphQL
call in the hyperlynx-v3 adaptor is missing a timeout/abort path, so a stalled
response can block the run. Update the request in the adaptor’s main fetch logic
around the request(SUBGRAPH_URL, poolsQuery, ...) call to pass a signal from
AbortSignal.timeout(...) or an AbortController with a bounded timeout, and
handle the abort path cleanly so the request fails fast instead of hanging.

Comment on lines +64 to +89
const feesUsd = Number(day?.feesUSD);
const apyBase = Number.isFinite(feesUsd) ? ((feesUsd * 365) / tvlUsd) * 100 : NaN;

const fees7d = days.reduce((s, d) => s + (Number(d.feesUSD) || 0), 0);
const volume7d = days.reduce((s, d) => s + (Number(d.volumeUSD) || 0), 0);
const apyBase7d = days.length
? (((fees7d / days.length) * 365) / tvlUsd) * 100
: NaN;

return {
pool: p.id,
chain: utils.formatChain(CHAIN),
project: PROJECT,
symbol: `${p.token0.symbol}-${p.token1.symbol}`,
tvlUsd,
apyBase,
apyBase7d,
underlyingTokens: [p.token0.id, p.token1.id],
poolMeta: `${Number(p.feeTier) / 10000}%`,
url: 'https://hyperlynx.fi/liquidity',
volumeUsd1d: Number(day?.volumeUSD) || 0,
volumeUsd7d: volume7d,
};
})
.filter(Boolean)
.filter((p) => utils.keepFinite(p));

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't drop pools just because the daily bucket is missing.

When poolDayData[0] is absent, apyBase/apyBase7d become non-finite and utils.keepFinite() removes the entire pool. src/handlers/triggerAdaptor.js already nulls non-finite APY fields downstream, so this turns subgraph lag or brand-new pools into missing pool rows instead of incomplete APY data.

🤖 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/adaptors/hyperlynx-v3/index.js` around lines 64 - 89, The adaptor in
hyperlynx-v3 is dropping entire pools when `poolDayData[0]` is missing because
`apyBase` and `apyBase7d` become non-finite and then `utils.keepFinite()`
filters them out. Update the pool mapping logic in the main return path so pools
are still returned even when the daily bucket is absent, and leave APY fields as
non-finite/null-safe values for downstream handling by `triggerAdaptor` instead
of filtering the whole object out.

Comment on lines +67 to +71
const fees7d = days.reduce((s, d) => s + (Number(d.feesUSD) || 0), 0);
const volume7d = days.reduce((s, d) => s + (Number(d.volumeUSD) || 0), 0);
const apyBase7d = days.length
? (((fees7d / days.length) * 365) / tvlUsd) * 100
: NaN;

@coderabbitai coderabbitai Bot Jun 30, 2026

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

apyBase7d is overstated for pools with fewer than 7 day buckets.

The PR objective says this field is a trailing 7-day average, but dividing by days.length makes a 1-day-old pool report its 1-day APY as apyBase7d. Divide by a fixed 7 days, or suppress the metric until seven buckets exist.

🤖 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/adaptors/hyperlynx-v3/index.js` around lines 67 - 71, The trailing APY
calculation in the Hyperlynx v3 adaptor is using the number of available day
buckets instead of a fixed 7-day window, so `apyBase7d` is inflated for newer
pools. Update the `apyBase7d` computation in
`src/adaptors/hyperlynx-v3/index.js` to either divide by 7 regardless of
`days.length` or return no value until the `days` array contains seven buckets,
and keep the logic localized near the existing `fees7d`, `volume7d`, and
`apyBase7d` calculations.

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.

@isagieth pls implement this fix to only compute if > 7 days

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.

@0xkr3p, sounds good — tagging @isagieth for visibility. Here's a suggested implementation for the fix (suppressing apyBase7d until 7 full day buckets are available):

const fees7d = days.reduce((s, d) => s + (Number(d.feesUSD) || 0), 0);
const volume7d = days.reduce((s, d) => s + (Number(d.volumeUSD) || 0), 0);
const apyBase7d = days.length === 7
  ? ((fees7d / 7) * 365 / tvlUsd) * 100
  : NaN;

This way, pools with fewer than 7 day buckets simply won't report apyBase7d (it'll be filtered out later by utils.keepFinite), avoiding the overstatement for newer pools. Let me know once it's implemented and I'll take another look.

return pools
.map((p) => {
const days = p.poolDayData || [];
const day = days[0];

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.

i would opt to use the last full day as I believe days[0] could be a partial day. So opt for days[1] which would be the last full day

apyBase7d,
underlyingTokens: [p.token0.id, p.token1.id],
poolMeta: `${Number(p.feeTier) / 10000}%`,
url: 'https://hyperlynx.fi/liquidity',

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.

@0xkr3p 0xkr3p 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.

hi @isagieth, thanks for the PR - a couple of comments to resolve before we can merge!

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.

2 participants