@1delta/margin-fetcher 5.0.83 → 5.0.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -48765,8 +48765,129 @@ var sthusdFetcher = {
48765
48765
  };
48766
48766
  }
48767
48767
  };
48768
+ var CHAIN_ID13 = Chain.ETHEREUM_MAINNET;
48769
+ var HUMA_PST_FEED = "0x4be50be32db1510240d542f77c5b36ca0d0965e6";
48770
+ var HUMA_PST_KEY = "HUMA::PST";
48771
+ var HUMA_PST_GROUP_KEY = "PayFi Strategy Token::PST";
48772
+ var HUMA_PST_WINDOW_SECONDS = 30 * 86400;
48773
+ var MIN_WINDOW_SECONDS = 7 * 86400;
48774
+ var MAX_STALENESS_SECONDS = 14 * 86400;
48775
+ var PROBE_OFFSETS = [560, 620, 680, 720, 760, 820, 900, 1e3, 1200];
48776
+ var YEAR_SECONDS12 = 365 * 86400;
48777
+ var PHASE_SHIFT = 64n;
48778
+ var ROUND_MASK = (1n << PHASE_SHIFT) - 1n;
48779
+ var FEED_ABI = [
48780
+ {
48781
+ name: "latestRoundData",
48782
+ type: "function",
48783
+ stateMutability: "view",
48784
+ inputs: [],
48785
+ outputs: [
48786
+ { name: "roundId", type: "uint80" },
48787
+ { name: "answer", type: "int256" },
48788
+ { name: "startedAt", type: "uint256" },
48789
+ { name: "updatedAt", type: "uint256" },
48790
+ { name: "answeredInRound", type: "uint80" }
48791
+ ]
48792
+ },
48793
+ {
48794
+ name: "getRoundData",
48795
+ type: "function",
48796
+ stateMutability: "view",
48797
+ inputs: [{ name: "roundId", type: "uint80" }],
48798
+ outputs: [
48799
+ { name: "roundId", type: "uint80" },
48800
+ { name: "answer", type: "int256" },
48801
+ { name: "startedAt", type: "uint256" },
48802
+ { name: "updatedAt", type: "uint256" },
48803
+ { name: "answeredInRound", type: "uint80" }
48804
+ ]
48805
+ }
48806
+ ];
48807
+ var parseRound = (raw) => {
48808
+ if (!raw) return void 0;
48809
+ const tuple = Array.isArray(raw) ? raw : [
48810
+ raw.roundId,
48811
+ raw.answer,
48812
+ raw.startedAt,
48813
+ raw.updatedAt
48814
+ ];
48815
+ const answer = tuple[1];
48816
+ const updatedAt = tuple[3];
48817
+ if (typeof answer !== "bigint" || typeof updatedAt !== "bigint")
48818
+ return void 0;
48819
+ if (answer <= 0n || updatedAt <= 0n) return void 0;
48820
+ return { answer, updatedAt: Number(updatedAt) };
48821
+ };
48822
+ var windowAprFromRounds = (latest, candidates, nowSeconds, windowSeconds = HUMA_PST_WINDOW_SECONDS) => {
48823
+ if (nowSeconds - latest.updatedAt > MAX_STALENESS_SECONDS) {
48824
+ throw new Error(
48825
+ `Huma PST: feed stale \u2014 last update ${nowSeconds - latest.updatedAt}s ago`
48826
+ );
48827
+ }
48828
+ const cutoff = latest.updatedAt - windowSeconds;
48829
+ const older = candidates.filter((c) => c.updatedAt < latest.updatedAt).sort((a, b) => b.updatedAt - a.updatedAt);
48830
+ if (older.length === 0) throw new Error("Huma PST: no historical round");
48831
+ const start = older.find((c) => c.updatedAt <= cutoff) ?? older[older.length - 1];
48832
+ const dt = latest.updatedAt - start.updatedAt;
48833
+ if (dt < MIN_WINDOW_SECONDS) {
48834
+ throw new Error(`Huma PST: window too short (${dt}s)`);
48835
+ }
48836
+ const growth = Number(latest.answer * 10n ** 18n / start.answer) / 1e18 - 1;
48837
+ const apr = growth * YEAR_SECONDS12 * 100 / dt;
48838
+ if (!Number.isFinite(apr) || Math.abs(apr) > 100) {
48839
+ throw new Error(`Huma PST: implausible rate ${apr}`);
48840
+ }
48841
+ return apr;
48842
+ };
48843
+ var fetchPstAprOnChain = async () => {
48844
+ const [latestRaw] = await multicallRetryUniversal({
48845
+ chain: CHAIN_ID13,
48846
+ abi: FEED_ABI,
48847
+ calls: [{ address: HUMA_PST_FEED, name: "latestRoundData", params: [] }],
48848
+ allowFailure: false
48849
+ });
48850
+ const latestTuple = Array.isArray(latestRaw) ? latestRaw : [latestRaw?.roundId];
48851
+ const latestRoundId = latestTuple[0];
48852
+ const latest = parseRound(latestRaw);
48853
+ if (typeof latestRoundId !== "bigint" || !latest) {
48854
+ throw new Error("Huma PST: latestRoundData unreadable");
48855
+ }
48856
+ const phase = latestRoundId >> PHASE_SHIFT;
48857
+ const aggRound = latestRoundId & ROUND_MASK;
48858
+ const probeRounds = [
48859
+ ...new Set(
48860
+ PROBE_OFFSETS.map((off) => {
48861
+ const r = aggRound - BigInt(off);
48862
+ return r < 1n ? 1n : r;
48863
+ })
48864
+ )
48865
+ ];
48866
+ const results = await multicallRetryUniversal({
48867
+ chain: CHAIN_ID13,
48868
+ abi: FEED_ABI,
48869
+ calls: probeRounds.map((r) => ({
48870
+ address: HUMA_PST_FEED,
48871
+ name: "getRoundData",
48872
+ params: [phase << PHASE_SHIFT | r]
48873
+ })),
48874
+ allowFailure: true
48875
+ });
48876
+ const candidates = results.map(parseRound).filter((r) => r !== void 0);
48877
+ return windowAprFromRounds(latest, candidates, Math.floor(Date.now() / 1e3));
48878
+ };
48879
+ var humaPstFetcher = {
48880
+ label: "HUMA_PST",
48881
+ fetch: async () => {
48882
+ const apr = await fetchPstAprOnChain();
48883
+ return {
48884
+ [HUMA_PST_KEY]: apr,
48885
+ [HUMA_PST_GROUP_KEY]: apr
48886
+ };
48887
+ }
48888
+ };
48768
48889
  var RAY9 = 10n ** 27n;
48769
- var YEAR_SECONDS12 = 31536e3;
48890
+ var YEAR_SECONDS13 = 31536e3;
48770
48891
  var DSR_ABI = [
48771
48892
  {
48772
48893
  name: "dsr",
@@ -48794,7 +48915,7 @@ var SUSDD_GROUP_KEY = "Savings Usdd::sUSDD";
48794
48915
  var aprFromDsr = (dsr) => {
48795
48916
  if (dsr <= RAY9) return 0;
48796
48917
  const perSecond = Number(dsr - RAY9) / 1e27;
48797
- return perSecond * YEAR_SECONDS12 * 100;
48918
+ return perSecond * YEAR_SECONDS13 * 100;
48798
48919
  };
48799
48920
  var fetchChainDsr = async (chainId, pot) => {
48800
48921
  const [dsr] = await multicallRetryUniversal({
@@ -52675,6 +52796,72 @@ var SINGLE_CHAIN_ENTRIES = {
52675
52796
  withdrawalCooldownSeconds: 432e3,
52676
52797
  yieldFetcher: sthusdFetcher,
52677
52798
  yieldKey: STHUSD_KEY
52799
+ },
52800
+ {
52801
+ // Huma **PST** (PayFi Strategy Token), bridged. Huma 2.0 is a
52802
+ // SOLANA product: a permissionless USDC pool (no KYC) funding
52803
+ // short-dated cross-border payment receivables — originated almost
52804
+ // entirely by Arf, a Huma affiliate — whose yield is paid as a rising
52805
+ // PST price. 306.6M PST exist ($347M at 1.1325); **148.2M of them are
52806
+ // on Ethereum** through Chainlink CCIP, and 125.8M of THOSE sit as
52807
+ // collateral in Morpho Blue (84.4M, three listed markets at 86 % LLTV)
52808
+ // and Fluid (41.4M, vaults 165/166/169) — the Ethereum book is a
52809
+ // loop book, ~22M floats. Assessed + built 2026-09-16; see HUMA.md.
52810
+ //
52811
+ // This address is NOT a vault. It is Chainlink's `BurnMintERC20`,
52812
+ // whose only minter and burner is the CCIP `BurnMintTokenPool 1.6.1`
52813
+ // (`0xbe776c85…`, one lane, Solana): no `asset()`, no
52814
+ // `convertToAssets()`, no `owner()`, not verified on Sourcify. So there
52815
+ // is **no primary mint and no redemption on this chain at all** — the
52816
+ // ways in and out are the market (Fluid DEX PST-USDC: a $1M round trip
52817
+ // quoted ~4 bps total on KyberSwap at integration) or the bridge back
52818
+ // to Solana. Hence `secondaryMarketOnly`: the Re shape, but with an
52819
+ // even plainer reason — Re's mint is KYC-gated, this one does not
52820
+ // exist. `isMintable: false` states that fact, not a permission.
52821
+ //
52822
+ // Priced by Chainlink's **"PST-USDC Exchange Rate (Calculated)"**
52823
+ // proxy `0x4be50be3…` — the same feed both Morpho PST oracles wrap as
52824
+ // `BASE_FEED_1`, so the earn row and the lending rows cannot disagree
52825
+ // about what a PST is worth. It answers in **6 decimals** (hence
52826
+ // `priceOracleDecimals`), hourly, and — unlike Re's feeds — keeps its
52827
+ // FULL round history, which is where `humaPstFetcher` measures the
52828
+ // realized rate (7.7 % APR on every window since 2026-05-25). TRAP: the
52829
+ // feed's AGGREGATOR reverts `No access` for a contract caller, so any
52830
+ // multicall must target the PROXY, which is what this pins.
52831
+ //
52832
+ // `nav-attested`, asserted: the price is produced by Huma's own
52833
+ // off-chain Price Oracle and relayed by Chainlink — an operator-
52834
+ // published NAV over an off-chain receivables book with a "modest"
52835
+ // first-loss cover and no on-chain solvency invariant (the Theo /
52836
+ // Maple / Native trust class). Every consequence the label earns —
52837
+ // `nav-accrual` as the rate kind, `nav-drawdown` in the risks — is
52838
+ // true here.
52839
+ //
52840
+ // `withdrawalMode` / cooldown describe the exit a holder who BRIDGES
52841
+ // BACK gets on Solana: a redemption request the operator's autotask
52842
+ // settles "typically within 1 business day", SLA 7 days, under a global
52843
+ // daily cap that rejects further requests once hit. The pin is the SLA
52844
+ // worst case (the Re call); a bridge hop each way is on top. For a
52845
+ // holder on this chain the exit is the `market` route.
52846
+ reader: "nav-oracle",
52847
+ solvency: "nav-attested",
52848
+ address: "0x22ae3d9a738471f405169af055d31c687087d4c7",
52849
+ underlying: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
52850
+ // USDC
52851
+ priceOracle: HUMA_PST_FEED,
52852
+ priceOracleDecimals: 6,
52853
+ symbol: "PST",
52854
+ brand: "Huma",
52855
+ description: "Huma's PayFi Strategy Token, bridged from Solana over Chainlink CCIP: a share of Huma 2.0's USDC pool, funding short-dated cross-border payment receivables nearly all originated by Arf, a Huma affiliate; the fee is paid as a rising PST price set by Huma's oracle and relayed by Chainlink. There is no mint and no redemption on Ethereum: you enter and exit by TRADING PST (venue: Fluid DEX PST-USDC) against that NAV, or by bridging back to Solana, where redemption is an operator-settled request under a daily cap. Backing is unsecured receivables credit with a small first-loss cover.",
52856
+ decimals: 6,
52857
+ underlyingDecimals: 6,
52858
+ isRebasing: false,
52859
+ isMintable: false,
52860
+ secondaryMarketOnly: true,
52861
+ withdrawalMode: "request-based",
52862
+ withdrawalCooldownSeconds: 7 * 86400,
52863
+ yieldFetcher: humaPstFetcher,
52864
+ yieldKey: HUMA_PST_KEY
52678
52865
  }
52679
52866
  ],
52680
52867
  "100": [
@@ -52964,6 +53151,53 @@ var SINGLE_CHAIN_ENTRIES = {
52964
53151
  yieldKey: STHUSD_KEY
52965
53152
  }
52966
53153
  ],
53154
+ // ---------------------------------------------------------------------
53155
+ // Arc (5042) — Circle's USDC-gas L1, mainnet 2026-09-16. One row: Huma's
53156
+ // PST, bridged in over Chainlink CCIP the same day.
53157
+ // ---------------------------------------------------------------------
53158
+ "5042": [
53159
+ {
53160
+ // Huma **PST**, bridged to Arc. Same asset and same trust story as the
53161
+ // chain-1 row (see it for the product); what differs is the SHAPE of
53162
+ // the exit. On Ethereum PST has $16M of DEX depth, so the row is
53163
+ // `secondaryMarketOnly`. Here it has NONE: KyberSwap answers
53164
+ // `route not found` for PST on Arc while routing USDC→WETH fine, and
53165
+ // at integration the whole bridged supply (441,548 PST, ≈ $500k) sat
53166
+ // inside the one listed Morpho Blue PST/USDC market — the Theo-on-
53167
+ // Stable shape, where a `via: 'swap'` route would advertise depth that
53168
+ // does not exist. So `isMintable: false` (a CCIP `BurnMintERC20` has
53169
+ // no mint function) and NOT `secondaryMarketOnly`: the only way in or
53170
+ // out is the bridge back to Solana. Flip the flag when a venue appears.
53171
+ //
53172
+ // Priced by Chainlink's **"PSTUSDC / USDC Exchange Rate"** proxy
53173
+ // `0x1abf15e8…` on Arc — the feed the Morpho market's oracle wraps as
53174
+ // `BASE_FEED_1`, so the earn row and the lending row agree. 6 decimals
53175
+ // TODAY; TRAP: its round history is NOT uniformly scaled — rounds 1
53176
+ // to ~100 (2026-06-19 → 06-23) answered at 12 decimals
53177
+ // (`1111266641610`) before the feed settled at 6 — so never derive a
53178
+ // rate from this feed's history. The rate is `humaPstFetcher`, which
53179
+ // measures the Ethereum feed; PST accrues identically on every chain
53180
+ // (1.132518 here vs 1.132511 on Ethereum at the same hour).
53181
+ reader: "nav-oracle",
53182
+ solvency: "nav-attested",
53183
+ address: "0xa6db07ebf438d91aa653746fc05523e435645525",
53184
+ underlying: "0x3600000000000000000000000000000000000000",
53185
+ // USDC (ERC-20)
53186
+ priceOracle: "0x1abf15e82566d274bf8722ac3e42fc3c79304051",
53187
+ priceOracleDecimals: 6,
53188
+ symbol: "PST",
53189
+ brand: "Huma",
53190
+ description: "Huma's PayFi Strategy Token, bridged to Arc over Chainlink CCIP: a share of Huma 2.0's USDC pool on Solana, funding short-dated cross-border payment receivables nearly all originated by Arf, a Huma affiliate; the fee is paid as a rising PST price set by Huma's oracle and relayed by Chainlink. There is no mint, no redemption and no trading venue on Arc: the only way in or out is bridging back to Solana, where redemption is an operator-settled request under a daily cap. Backing is unsecured receivables credit with a small first-loss cover.",
53191
+ decimals: 6,
53192
+ underlyingDecimals: 6,
53193
+ isRebasing: false,
53194
+ isMintable: false,
53195
+ withdrawalMode: "request-based",
53196
+ withdrawalCooldownSeconds: 7 * 86400,
53197
+ yieldFetcher: humaPstFetcher,
53198
+ yieldKey: HUMA_PST_KEY
53199
+ }
53200
+ ],
52967
53201
  "4663": [
52968
53202
  {
52969
53203
  // Spark Vaults V2 spUSDG on Robinhood Chain — the first V2 vault
@@ -73206,7 +73440,7 @@ var readVaultSharePrices = async (chainId, addresses, multicallRetry) => {
73206
73440
  };
73207
73441
 
73208
73442
  // src/vaults/yield/annualize.ts
73209
- var YEAR_SECONDS13 = 365 * 24 * 60 * 60;
73443
+ var YEAR_SECONDS14 = 365 * 24 * 60 * 60;
73210
73444
  var SCALE = 10n ** 18n;
73211
73445
  var appendSnapshot = (points, snap, options) => {
73212
73446
  const maxPoints = options?.maxPoints ?? 90;
@@ -73235,7 +73469,7 @@ var computeVaultApr = (points, options) => {
73235
73469
  if (pThen === 0n) return void 0;
73236
73470
  const ratioScaled = BigInt(now.p) * SCALE / pThen;
73237
73471
  const ratio = Number(ratioScaled) / 1e18;
73238
- const apr = (ratio - 1) * (YEAR_SECONDS13 / windowSeconds);
73472
+ const apr = (ratio - 1) * (YEAR_SECONDS14 / windowSeconds);
73239
73473
  return {
73240
73474
  apr,
73241
73475
  sharePriceNow: now.p,