@1delta/margin-fetcher 5.0.107 → 5.0.109

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
@@ -47989,26 +47989,39 @@ var wstusrFetcher = {
47989
47989
  // src/yields/intrinsic/fetchers/hastra.ts
47990
47990
  var HASTRA_POR_URL = "https://www.hastra.io/hastra-pulse/public/api/v1/por";
47991
47991
  var HASTRA_PRIME_KEY = "Hastra PRIME::PRIME";
47992
- var hastraPrimeFetcher = {
47992
+ var HASTRA_AUTO_KEY = "Hastra AUTO::AUTO";
47993
+ var HASTRA_TOKEN_KEYS = {
47994
+ prime: HASTRA_PRIME_KEY,
47995
+ auto: HASTRA_AUTO_KEY
47996
+ };
47997
+ var MAX_PLAUSIBLE_APR = 50;
47998
+ function parseHastraPor(res) {
47999
+ const tokens = res?.demo_prime_card?.tokens;
48000
+ const out = {};
48001
+ if (!Array.isArray(tokens)) return out;
48002
+ for (const t of tokens) {
48003
+ const key3 = HASTRA_TOKEN_KEYS[String(t?.token ?? "").toLowerCase()];
48004
+ if (!key3) continue;
48005
+ const apr = Number(t?.effective_rate);
48006
+ if (Number.isFinite(apr) && apr > 0 && apr < MAX_PLAUSIBLE_APR)
48007
+ out[key3] = apr;
48008
+ }
48009
+ return out;
48010
+ }
48011
+ var hastraFetcher = {
47993
48012
  label: "Hastra",
47994
48013
  fetch: async () => {
47995
48014
  const res = await fetch(HASTRA_POR_URL, {
47996
48015
  method: "GET",
47997
48016
  headers: { Accept: "application/json" }
47998
- }).then((r) => r.json());
47999
- const card = res?.demo_prime_card ?? {};
48000
- const current = Number(card.current_rate);
48001
- const fee = Number(card.fee);
48002
- const lifetimePct = Number(card.lifetime_average_rate) * 100;
48003
- let apr;
48004
- if (Number.isFinite(current)) {
48005
- apr = current - (Number.isFinite(fee) ? fee : 0);
48006
- } else if (Number.isFinite(lifetimePct)) {
48007
- apr = lifetimePct;
48008
- } else {
48009
- apr = 0;
48010
- }
48011
- return { [HASTRA_PRIME_KEY]: Math.max(0, apr) };
48017
+ }).then((r) => {
48018
+ if (!r.ok) throw new Error(`Hastra PoR answered HTTP ${r.status}`);
48019
+ return r.json();
48020
+ });
48021
+ const out = parseHastraPor(res);
48022
+ if (Object.keys(out).length === 0)
48023
+ console.warn("[hastra] PoR feed carried no usable effective_rate");
48024
+ return out;
48012
48025
  }
48013
48026
  };
48014
48027
  var RAY8 = 10n ** 27n;
@@ -52978,29 +52991,51 @@ var SINGLE_CHAIN_ENTRIES = {
52978
52991
  yieldKey: "SYRUPUSDG"
52979
52992
  },
52980
52993
  {
52981
- // Hastra Democratized PRIME — ERC-4626 over wYLDS (itself ERC-4626 over
52982
- // USDC), so the share/asset ratio accrues on-chain (`convertToAssets`).
52983
- // Solana-primary; the Ethereum deployment exists (verified on-chain:
52984
- // symbol PRIME, 6 decimals, asset() = wYLDS) but carries no user holders
52985
- // yet. Deposits are whitelist-gated, so `isMintable` is false — we list
52986
- // + price it, but don't advertise a permissionless mint that would
52987
- // revert. Two-phase exit (`requestRedeem` → `completeRedeem`). APR from
52988
- // the public Proof-of-Reserve feed via `hastraPrimeFetcher`.
52994
+ // Hastra (Figure / Provenance) PRIME — ERC-4626 over wYLDS (itself a
52995
+ // 4626 over USDC, held 1:1), the same product as the Solana
52996
+ // `vault-stake` pool and priced at the same rate. FORK-PROVEN
52997
+ // 2026-10-06: `deposit` from an arbitrary EOA and an immediate
52998
+ // `redeem` both settle at `convertToAssets` (`maxDeposit` is
52999
+ // uint.max; the only gate is `freezeAccount`). The previous row said
53000
+ // whitelist-gated + request-based, which described an older surface.
53001
+ // The exit pays wYLDS; wYLDS → USDC is Hastra's own queued redemption.
53002
+ // APR = the PoR feed's `effective_rate` (`hastraFetcher`).
52989
53003
  address: "0x19ebb35279a16207ec4ba82799cc64715065f7f6",
52990
53004
  underlying: "0x6ad038ca6c04e885630851278ca0a856ad9a66cc",
52991
53005
  // wYLDS
52992
53006
  symbol: "PRIME",
52993
53007
  solvency: "nav-attested",
52994
53008
  brand: "Hastra",
52995
- description: "Hastra's Democratized PRIME: an ERC-4626 over wYLDS (itself a vault over USDC), with the rate published via Hastra's Proof-of-Reserve feed. Deposits are whitelist-gated; exit is a two-phase request-then-complete redemption.",
53009
+ description: "Hastra's PRIME: wYLDS (Figure's USDC-backed YLDS, 1:1 with USDC) lent into home-equity (HELOC) loans through Figure's Democratized Prime marketplace, paid as a rising share price. Deposit and redeem are instant against wYLDS at the published rate; turning wYLDS back into USDC is a separate queued redemption with Hastra. The price is an operator-attested NAV of off-chain loans.",
52996
53010
  decimals: 6,
52997
53011
  underlyingDecimals: 6,
52998
53012
  isRebasing: false,
52999
- isMintable: false,
53000
- withdrawalMode: "request-based",
53001
- yieldFetcher: hastraPrimeFetcher,
53013
+ isMintable: true,
53014
+ withdrawalMode: "instant",
53015
+ yieldFetcher: hastraFetcher,
53002
53016
  yieldKey: "Hastra PRIME::PRIME"
53003
53017
  },
53018
+ {
53019
+ // Hastra AUTO — PRIME's sibling over the same wYLDS, lending into
53020
+ // consumer auto loans on Figure's Democratized Prime. Same contract family (4626, fork-proven the
53021
+ // same way 2026-10-06), same exit into wYLDS. ~$1M on Ethereum against
53022
+ // ~$70M on Solana, so the Solana row is the one that matters; this one
53023
+ // exists so the EVM share has a rate and an exit.
53024
+ address: "0x997e2efbce91d170b00ea402e35a66c887ee1da9",
53025
+ underlying: "0x6ad038ca6c04e885630851278ca0a856ad9a66cc",
53026
+ // wYLDS
53027
+ symbol: "AUTO",
53028
+ solvency: "nav-attested",
53029
+ brand: "Hastra",
53030
+ description: "Hastra's AUTO: wYLDS (Figure's USDC-backed YLDS, 1:1 with USDC) lent into a pool of consumer auto loans (originated and serviced by a third-party auto lender, offered through Figure's Democratized Prime marketplace), paid as a rising share price. Deposit and redeem are instant against wYLDS at the published rate; turning wYLDS back into USDC is a separate queued redemption with Hastra. The price is an operator-attested NAV of off-chain loans.",
53031
+ decimals: 6,
53032
+ underlyingDecimals: 6,
53033
+ isRebasing: false,
53034
+ isMintable: true,
53035
+ withdrawalMode: "instant",
53036
+ yieldFetcher: hastraFetcher,
53037
+ yieldKey: "Hastra AUTO::AUTO"
53038
+ },
53004
53039
  {
53005
53040
  // 3Jane USD3 — senior tranche of the credit-based money market
53006
53041
  // (docs.3jane.xyz): USDC funds unsecured fintech/crypto credit
@@ -55627,6 +55662,108 @@ var onycFetcher = {
55627
55662
  }
55628
55663
  };
55629
55664
 
55665
+ // src/yields/intrinsic/fetchers/sanctum.ts
55666
+ var KAMINO_STAKING_YIELDS = "https://api.kamino.finance/staking-yields/tokens";
55667
+ var INF_MINT = "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm";
55668
+ var INF_LLAMA_POOL = "3075a746-bdd1-4aac-bcd5-b035abee2622";
55669
+ var INF_KEY = "Infinity::INF::solana";
55670
+ var INF_EPOCHS = 10;
55671
+ var MAX_PLAUSIBLE_APY = 0.3;
55672
+ function meanEpochApy(rows, n = INF_EPOCHS) {
55673
+ if (!Array.isArray(rows)) return void 0;
55674
+ const ok2 = rows.map((r) => ({ epoch: Number(r?.epoch), apy: Number(r?.apy) })).filter(
55675
+ (r) => Number.isFinite(r.epoch) && Number.isFinite(r.apy) && r.apy > 0 && r.apy < MAX_PLAUSIBLE_APY
55676
+ ).sort((a, b) => b.epoch - a.epoch).slice(0, n);
55677
+ if (ok2.length === 0) return void 0;
55678
+ return ok2.reduce((s, r) => s + r.apy, 0) / ok2.length;
55679
+ }
55680
+ async function kaminoInfApy() {
55681
+ const end = /* @__PURE__ */ new Date();
55682
+ const start = new Date(end.getTime() - 30 * 864e5);
55683
+ const d = (x) => x.toISOString().slice(0, 10);
55684
+ const res = await fetch(
55685
+ `${KAMINO_STAKING_YIELDS}/${INF_MINT}/history?start=${d(start)}&end=${d(end)}`,
55686
+ {
55687
+ headers: { accept: "application/json" },
55688
+ signal: AbortSignal.timeout(8e3)
55689
+ }
55690
+ );
55691
+ if (!res.ok) throw new Error(`Kamino staking-yields HTTP ${res.status}`);
55692
+ return meanEpochApy(await res.json());
55693
+ }
55694
+ var infFetcher = {
55695
+ label: "SANCTUM_INF",
55696
+ fetch: async () => {
55697
+ const apy = await kaminoInfApy().catch((e) => {
55698
+ console.warn(`[sanctum] Kamino INF history unavailable: ${e.message}`);
55699
+ return void 0;
55700
+ });
55701
+ if (apy !== void 0) return { [INF_KEY]: apyToAprPercent(apy * 100) };
55702
+ const llama = await fetchDefiLlamaApy(INF_LLAMA_POOL);
55703
+ if (!(llama > 0) || llama >= MAX_PLAUSIBLE_APY * 100) return {};
55704
+ return { [INF_KEY]: apyToAprPercent(llama) };
55705
+ }
55706
+ };
55707
+
55708
+ // src/yields/intrinsic/fetchers/exponentTranching.ts
55709
+ var EXPONENT_APP_API = "https://app.exponent.finance/api/tranching-markets";
55710
+ var EXPONENT_SENIOR_GROUPS = {
55711
+ FvQP1fjox2GPSwkEhENuZisz8UeRURLWf7GYF9n2mURD: "Exponent Senior eHYUSD::srEHYUSD::solana",
55712
+ F17tzaQaFf1x3tC5gQFVvXAF2hcgq1qX6Mc9595zo3FD: "Exponent Senior AUTO::srAUTO::solana",
55713
+ "9J8VvigcjFTkN3jhZH2ieTi2hdGVBVpEXbcA1JDo7QpA": "Exponent Senior ONyc::srONyc::solana",
55714
+ "4tnzVYkaXKwMt7p86wpDzeTyzHSZhj2BvdGwBem7peH5": "Exponent Senior nOPAL::srnOPAL::solana"
55715
+ };
55716
+ var EXPONENT_BASE_GROUPS = {
55717
+ HnnGv3HrSqjRpgdFmx7vQGjntNEoex1SU4e9Lxcxuihz: "Earn Hylo USD::eHYUSD::solana"
55718
+ };
55719
+ var MAX_PLAUSIBLE_APY2 = 0.5;
55720
+ function seniorApy(stats) {
55721
+ const s = stats;
55722
+ for (const k of ["seniorApy30d", "seniorApy7d", "seniorApy1d"]) {
55723
+ const v = Number(s?.[k] ?? NaN);
55724
+ if (s?.[k] != null && Number.isFinite(v) && v > -MAX_PLAUSIBLE_APY2 && v < MAX_PLAUSIBLE_APY2)
55725
+ return v;
55726
+ }
55727
+ return void 0;
55728
+ }
55729
+ var getJson3 = async (url) => {
55730
+ const res = await fetch(url, {
55731
+ headers: { accept: "application/json" },
55732
+ signal: AbortSignal.timeout(8e3)
55733
+ });
55734
+ if (!res.ok) throw new Error(`Exponent HTTP ${res.status} for ${url}`);
55735
+ return res.json();
55736
+ };
55737
+ var exponentSeniorFetcher = {
55738
+ label: "EXPONENT_SENIOR",
55739
+ fetch: async () => {
55740
+ const markets = await getJson3(EXPONENT_APP_API);
55741
+ const wanted = (Array.isArray(markets) ? markets : []).filter(
55742
+ (m) => m.address && m.mintLpSenior && EXPONENT_SENIOR_GROUPS[m.mintLpSenior]
55743
+ );
55744
+ const out = {};
55745
+ for (const m of Array.isArray(markets) ? markets : []) {
55746
+ const group = m.mintBase ? EXPONENT_BASE_GROUPS[m.mintBase] : void 0;
55747
+ const apy = Number(m.underlyingApy7d);
55748
+ if (group && m.underlyingApy7d != null && apy > 0 && apy < MAX_PLAUSIBLE_APY2)
55749
+ out[group] = apyToAprPercent(apy * 100);
55750
+ }
55751
+ await Promise.all(
55752
+ wanted.map(async (m) => {
55753
+ const apy = await getJson3(`${EXPONENT_APP_API}/${m.address}/stats`).then(seniorApy).catch((e) => {
55754
+ console.warn(`[exponent] ${m.address} stats: ${e.message}`);
55755
+ return void 0;
55756
+ });
55757
+ if (apy !== void 0)
55758
+ out[EXPONENT_SENIOR_GROUPS[m.mintLpSenior]] = apyToAprPercent(
55759
+ apy * 100
55760
+ );
55761
+ })
55762
+ );
55763
+ return out;
55764
+ }
55765
+ };
55766
+
55630
55767
  // src/yields/intrinsic/fetchers/superreturn.ts
55631
55768
  var SSUPERUSD_URL = "https://www.superreturn.ai/api/trpc/cmc.getUSDCPrice,rewardBackend.getYield,rewardBackend.getTvlChange?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%2C%221%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%2C%222%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%7D";
55632
55769
  var ssuperusd = "SuperReturn sSuperUSD::SSUPERUSD";
@@ -55742,7 +55879,7 @@ var getGmxApiHost = (chainId) => GMX_API_HOSTS[chainId];
55742
55879
 
55743
55880
  // src/vaults/gmx/api.ts
55744
55881
  var GMX_DEFAULT_APY_PERIOD = "1d";
55745
- var getJson3 = async (url) => {
55882
+ var getJson4 = async (url) => {
55746
55883
  const res = await fetch(url, {
55747
55884
  method: "GET",
55748
55885
  headers: { Accept: "application/json" }
@@ -55754,12 +55891,12 @@ var fetchGmxRawData = async (chainId, period, apiUrlOverride) => {
55754
55891
  const host = apiUrlOverride ?? getGmxApiHost(chainId);
55755
55892
  if (!host) throw new Error(`GMX not supported on chain ${chainId}`);
55756
55893
  const [apy, marketsRes, glvsRes, tokensRes] = await Promise.all([
55757
- getJson3(`${host}/apy?period=${encodeURIComponent(period)}`),
55758
- getJson3(`${host}/markets`).catch(() => ({
55894
+ getJson4(`${host}/apy?period=${encodeURIComponent(period)}`),
55895
+ getJson4(`${host}/markets`).catch(() => ({
55759
55896
  markets: []
55760
55897
  })),
55761
- getJson3(`${host}/glvs`).catch(() => ({ glvs: [] })),
55762
- getJson3(`${host}/tokens`).catch(() => ({
55898
+ getJson4(`${host}/glvs`).catch(() => ({ glvs: [] })),
55899
+ getJson4(`${host}/tokens`).catch(() => ({
55763
55900
  tokens: []
55764
55901
  }))
55765
55902
  ]);
@@ -56381,6 +56518,13 @@ var LENDING_ONLY_FETCHERS = [
56381
56518
  // ONyc (OnRe reinsurance, Solana): NAV-accruing collateral on Loopscale /
56382
56519
  // Kamino / Jupiter Lend, no vault row.
56383
56520
  onycFetcher,
56521
+ // INF (Sanctum Infinity, Solana): the SOL-value accrual of the multi-LST
56522
+ // pool, collateral on Kamino / Jupiter Lend / Project 0 / Save. Its earn
56523
+ // row lives in margin-fetcher-sol, so it is lending-only here.
56524
+ infFetcher,
56525
+ // Exponent senior tranches (srEHYUSD / srAUTO / srONyc / srnOPAL, Solana):
56526
+ // Loopscale loop collateral, no earn row.
56527
+ exponentSeniorFetcher,
56384
56528
  thbillFetcher,
56385
56529
  // sthusdFetcher / scrvusdFetcher are NOT here (and deliberately not
56386
56530
  // imported): both are vault-wired by their savings rows, so they reach
@@ -65036,7 +65180,7 @@ function rescaleExchangeRate(exchangeRate, shareDecimals) {
65036
65180
  const dec2 = Math.max(0, Math.round(Number(shareDecimals) || 0));
65037
65181
  return (r * 10n ** BigInt(dec2) / 10n ** 18n).toString();
65038
65182
  }
65039
- async function getJson4(url) {
65183
+ async function getJson5(url) {
65040
65184
  const controller = new AbortController();
65041
65185
  const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS2);
65042
65186
  try {
@@ -65128,7 +65272,7 @@ async function mapWithConcurrency(items, limit, fn) {
65128
65272
  return out;
65129
65273
  }
65130
65274
  async function fetchEulerEarnVaultsFromApi(chainId, prices = {}, tokenList = {}, multicallRetry) {
65131
- const list = await getJson4(
65275
+ const list = await getJson5(
65132
65276
  `${EULER_DATA_API_BASE2}/earn/vaults?chainId=${chainId}&limit=200&visibility=${VISIBILITY_ALL}`
65133
65277
  );
65134
65278
  if (!list) return void 0;
@@ -65145,7 +65289,7 @@ async function fetchEulerEarnVaultsFromApi(chainId, prices = {}, tokenList = {},
65145
65289
  mapWithConcurrency(
65146
65290
  rows,
65147
65291
  DETAIL_CONCURRENCY,
65148
- (row) => getJson4(
65292
+ (row) => getJson5(
65149
65293
  `${EULER_DATA_API_BASE2}/earn/vaults/${chainId}/${row.address}?include=strategies`
65150
65294
  ).then((d) => d?.data)
65151
65295
  ),
@@ -75575,7 +75719,7 @@ function clearPendleMarketsCache() {
75575
75719
  marketsCache = void 0;
75576
75720
  assetsCache = void 0;
75577
75721
  }
75578
- async function getJson5(url, label) {
75722
+ async function getJson6(url, label) {
75579
75723
  const response = await fetch(url, { headers: { Accept: "application/json" } });
75580
75724
  if (!response.ok) {
75581
75725
  throw new Error(
@@ -75596,7 +75740,7 @@ function cache5(slot, build6, store) {
75596
75740
  function fetchPendleApiMarkets() {
75597
75741
  return cache5(
75598
75742
  marketsCache,
75599
- async () => (await getJson5(PENDLE_MARKETS_URL, "markets"))?.markets ?? [],
75743
+ async () => (await getJson6(PENDLE_MARKETS_URL, "markets"))?.markets ?? [],
75600
75744
  (c) => {
75601
75745
  marketsCache = c;
75602
75746
  }
@@ -75607,7 +75751,7 @@ function fetchPendleApiAssets() {
75607
75751
  return cache5(
75608
75752
  assetsCache,
75609
75753
  async () => {
75610
- const json = await getJson5(PENDLE_ASSETS_URL, "assets");
75754
+ const json = await getJson6(PENDLE_ASSETS_URL, "assets");
75611
75755
  const map = /* @__PURE__ */ new Map();
75612
75756
  for (const a of json?.assets ?? []) {
75613
75757
  if (a?.chainId == null || !a?.address) continue;
@@ -84160,7 +84304,16 @@ var SVM_EARN_VAULT_BUILDERS = {
84160
84304
  nativeWithdraw: true
84161
84305
  },
84162
84306
  // USDC in over CCTP, a request out — settled by Nest, nothing to claim
84163
- "savings:Nest": { verbs: ["deposit", "request-withdraw"] }
84307
+ "savings:Nest": { verbs: ["deposit", "request-withdraw"] },
84308
+ // PRIME / AUTO: the vault-stake pool's own stake / redeem, same
84309
+ // transaction; wYLDS in (or USDC, minted 1:1 first), wYLDS out
84310
+ "savings:Hastra": { verbs: ["deposit", "withdraw"], payAsset: true },
84311
+ // INF: Sanctum Infinity's own add / remove liquidity against wSOL
84312
+ "savings:Sanctum": {
84313
+ verbs: ["deposit", "withdraw"],
84314
+ nativeDeposit: true,
84315
+ nativeWithdraw: true
84316
+ }
84164
84317
  };
84165
84318
  var UNBUILT_REASONS = {
84166
84319
  exponent: "Exponent PTs are not tradable through this API yet",