Skip to content

feat(pools): report estimated net LP returns - #400

Merged
Miracle656 merged 2 commits into
Divinity-Labs:mainfrom
abdulrahmanj383-creator:fix/issue-286
Oct 27, 2026
Merged

Miracle656 merged 2 commits into
Divinity-Labs:mainfrom
abdulrahmanj383-creator:fix/issue-286

Conversation

@abdulrahmanj383-creator

@abdulrahmanj383-creator abdulrahmanj383-creator commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Extends /pools with a 24-hour impermanent-loss estimate, fee APR, and combined net 24-hour return. The response and docs state the constant-product, volume, reserve-value, and data-window assumptions; unavailable history returns null rather than implying zero loss.

Closes #286

@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@abdulrahmanj383-creator Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Miracle656
Miracle656 merged commit bd14228 into Divinity-Labs:main Oct 27, 2026
1 check failed
@Miracle656

Copy link
Copy Markdown
Collaborator

Merged. The maths is right, including the part that is easy to get wrong: impermanentLossPct returns an already-negative value (2√r/(1+r) − 1 is ≤ 0 for all r), so netReturn24hPct correctly adds it. I added a test that pins that — a pool whose price doubled over the window, −5.72% divergence against 0.75% of fees — and it fails if the addition ever becomes a subtraction.

I had to port rather than merge, because #482 landed first and moved /pools out of src/api/rest.ts into src/routes/pools.ts with keyset pagination. Your edits were against a handler that no longer exists:

  • The two window probes are now part of the paginated skip-scan query. I kept them as LEFT JOIN LATERAL for the reason you wrote them that way — a pool with nothing in the window stays in the listing with null estimates rather than vanishing from the page.
  • The computation had to be shared. tests/mcp-lens.test.ts asserts lens_get_pools returns exactly the REST fields, so adding these to the route alone broke that parity. They now come from one function in src/pricing/lpReturns.ts and are reported by both. That module has no pg import on purpose, since lensTools.ts is kept DB-free so it stays testable against a stub.
  • Unknown inputs yield null, never 0. A pool with no trades in the window has an unmeasurable fee return, not a 0% one, and the two rank very differently.
  • I left the estimates as plain numbers rather than routing them through formatDecimal. They come out of a square root and a ×365 annualisation, so handing them back as exact decimal strings under ?decimalFormat=string would overstate what they are — estimate: true makes the same point in the body.

Verified on the merge: tsc clean, readme:check clean, 1913 tests passed across 157 files.

One thing to keep an eye on: price_points is indexed on pairKey, not pool_id, so the volume aggregate has no index supporting its filter. The 24h bound should keep it inside recent hypertable chunks, but if /pools latency regresses at a 200-pool page that is the first place to look.

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.

Impermanent loss is invisible

2 participants