feat: add LI.FI Earn API types - #561
Open
FarseenSh wants to merge 3 commits into
Open
Conversation
@lifi/types has no Earn types today, so every TypeScript integration of the Earn Data API writes them by hand from earn-openapi.yaml — which disagrees with the live service in several places. These are derived from the live API and verified against 710 vaults across 19 chains and 27 protocols (Aug 2026). Each place the spec and the service disagree is documented inline at the field it affects, so the correction travels with the type.
FarseenSh
added a commit
to FarseenSh/earnforge
that referenced
this pull request
Aug 4, 2026
Converted to lifinance/types' own prettier config (semi: false, singleQuote: true) — the draft carried semicolons because it was derived from the published tarball, which is tsc output rather than their source. Two counts were also still measured against the 609-vault fleet: 139 vaults yielding under 1% is now 161, and descriptions are on 23% rather than 16%. Submitted as lifinance/types#561.
LI.FI de-indexed every vault on Unichain (130) and Scroll (534352) since this was opened, so /v1/chains reports 17 rather than 19 and the fleet is 703. Also replaces the analytics-freshness note. It claimed an "observed floor of 87 minutes", which was never a property of the API — only how far into the refresh cycle that sample happened to land, so it read differently on every run. The fleet refreshes in one hourly batch (338 of 703 vaults share a single updatedAt minute) with a tail to ~97 hours; that is the structural claim and it holds.
The previous commit quoted "338 of 703 vaults share a single updatedAt minute". Four walks across today returned 328, 338, 522 and 526 — the batch fires at :01-:03 and fills progressively, so that count measures how far into the hour the sample landed rather than anything about the API. Same defect as the "observed floor of 87 minutes" line this file already replaced once. The mechanism is the durable part, so it states that and stops putting a number on it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds types for the Earn Data API (
earn.li.fi) —src/earn.ts, plus one line insrc/index.ts. No imports, no runtime dependency, no changes to existing types.Why
@lifi/typescovers chains, tokens, bridges, exchanges, steps and balances, but has no Earn types. So every TypeScript integration of the Earn API writes them by hand fromearn-openapi.yaml— and the spec disagrees with the live service in several places, each of which silently produces wrong values rather than a type error.Provenance
Derived from the live API and cross-checked against it — 710 vaults across 19 chains and 27 protocols, Aug 2026 — rather than transcribed from the spec. Where the two disagree, the correction is documented inline at the field it affects, so it travels with the type instead of living in a changelog:
apy.*is a decimal (0.0534= 5.34%)* 100overstates every yield 100×tvl.usdis a stringcaps,timeLock,kyc,lpTokensrewardTokens[].symbol/.decimalsrequired400and404400carrieserrors[]Plus three behaviours that appear in no spec:
verificationStatus— undocumented, present on every vault,flaggedon ~9.3% (66/710). It looks like an internal vault-quality signal and is genuinely useful to consumers.nextCursoris absent from the JSON on the final page — notnull, not empty — so it must be optional and nullable to paginate correctly.apy.rewardis three-valued:null(protocol reported nothing),0(reported no incentives), or positive. The split varies within a protocol, so?? 0collapses the only signal separating organic yield from a temporary emission./v1/portfolioalso renamed its arraypositions→datarecently; both are declared so consumers can migrate without a break.Checks
Run against this repo's own toolchain on this branch:
pnpm typecheck— cleanpnpm build— emits to_types,_esmand_cjsprettier --check— cleaneslint— cleanNotes
Names are prefixed
Earn*to avoid collisions with existing exports. Happy to rename, reshape, split intosrc/earn/, or drop the inline commentary if you'd rather keep the type files terse — the field shapes are the substance and the rest is easy to trim.These come out of EarnForge, where the equivalent Zod schemas are exercised by a live integration suite and a three-way drift check against the live API, the OpenAPI spec, and the schemas themselves — which is how the discrepancies above were found.