@1delta/margin-fetcher 0.0.283 → 0.0.285

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
@@ -9021,6 +9021,7 @@ var INIT_POOL_NAME_OVERRIDES = {
9021
9021
  "0x592c91ac727da556dc90ddf5630e1901efcd0c92": "Init FBTC Isolated"
9022
9022
  };
9023
9023
  var INIT_DEFAULT_LIQUIDATION_PENALTY = 0.05;
9024
+ var INIT_POOLS_FROZEN = true;
9024
9025
  var INIT_EMODE_LABELS = {
9025
9026
  [1]: "Default",
9026
9027
  [2]: "Blue Chip Volatile",
@@ -9095,8 +9096,12 @@ var getInitReservesDataConverter = (lender, chainId, prices, additionalYields, t
9095
9096
  rewards: [],
9096
9097
  config: {},
9097
9098
  closeFactor: 1,
9098
- borrowingEnabled: totalDebt !== "0",
9099
- depositsEnabled: true,
9099
+ // Reserve still exists (positions must remain visible & withdrawable);
9100
+ // only new deposits/borrows are blocked → active but frozen.
9101
+ isActive: true,
9102
+ isFrozen: INIT_POOLS_FROZEN,
9103
+ borrowingEnabled: false ,
9104
+ depositsEnabled: !INIT_POOLS_FROZEN,
9100
9105
  params
9101
9106
  };
9102
9107
  });
@@ -22004,68 +22009,100 @@ function createCompoundV2Entry(i, data, key, assetsIn, vToken, meta, claimableRe
22004
22009
  };
22005
22010
  }
22006
22011
 
22012
+ // src/lending/user-data/euler/eulerDataApi.ts
22013
+ var EULER_DATA_API_BASE = "https://v3.euler.finance/v3";
22014
+ var EULER_API_REQUEST_TIMEOUT_MS = 1e4;
22015
+ var EULER_API_CHAINS = /* @__PURE__ */ new Set([
22016
+ "1",
22017
+ // Ethereum
22018
+ "56",
22019
+ // BSC
22020
+ "130",
22021
+ // Unichain
22022
+ "146",
22023
+ // Sonic
22024
+ "239",
22025
+ // TAC
22026
+ "999",
22027
+ // HyperEVM
22028
+ "1923",
22029
+ // Swell
22030
+ "8453",
22031
+ // Base
22032
+ "9745",
22033
+ // Plasma
22034
+ "42161",
22035
+ // Arbitrum
22036
+ "43114",
22037
+ // Avalanche
22038
+ "60808",
22039
+ // BOB
22040
+ "80094"
22041
+ // Berachain
22042
+ ]);
22043
+ var eulerApiSupportsChain = (chainId) => EULER_API_CHAINS.has(chainId);
22044
+ async function fetchEulerPositionsFromApi(chainId, owner, forceFresh = true) {
22045
+ if (!eulerApiSupportsChain(chainId)) return void 0;
22046
+ const controller = new AbortController();
22047
+ const timeout = setTimeout(
22048
+ () => controller.abort(),
22049
+ EULER_API_REQUEST_TIMEOUT_MS
22050
+ );
22051
+ try {
22052
+ const positions = [];
22053
+ const limit = 100;
22054
+ let offset = 0;
22055
+ for (let page = 0; page < 10; page++) {
22056
+ const url = `${EULER_DATA_API_BASE}/accounts/${owner.toLowerCase()}/positions?chainId=${chainId}&forceFresh=${forceFresh}&limit=${limit}&offset=${offset}`;
22057
+ const response = await fetch(url, { signal: controller.signal });
22058
+ if (!response.ok) return offset === 0 ? void 0 : positions;
22059
+ const body = await response.json();
22060
+ const page_ = body?.data ?? [];
22061
+ positions.push(...page_);
22062
+ const total = body?.meta?.total;
22063
+ offset += limit;
22064
+ if (page_.length < limit || typeof total === "number" && offset >= total)
22065
+ break;
22066
+ }
22067
+ return positions;
22068
+ } catch {
22069
+ return void 0;
22070
+ } finally {
22071
+ clearTimeout(timeout);
22072
+ }
22073
+ }
22074
+
22007
22075
  // src/lending/user-data/euler/userCallBuild.ts
22008
- Array.from(
22076
+ var ALL_EULER_SUB_ACCOUNT_INDEXES = Array.from(
22009
22077
  { length: 256 },
22010
22078
  (_3, i) => i
22011
22079
  );
22012
- var EULER_SUBGRAPH_BASE = "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs";
22013
- var EULER_SUBGRAPH_URLS = {
22014
- "1": `${EULER_SUBGRAPH_BASE}/euler-v2-mainnet/latest/gn`,
22015
- "10": `${EULER_SUBGRAPH_BASE}/euler-v2-optimism/latest/gn`,
22016
- "56": `${EULER_SUBGRAPH_BASE}/euler-v2-bsc/latest/gn`,
22017
- "100": `${EULER_SUBGRAPH_BASE}/euler-v2-gnosis/latest/gn`,
22018
- "130": `${EULER_SUBGRAPH_BASE}/euler-v2-unichain/latest/gn`,
22019
- "146": `${EULER_SUBGRAPH_BASE}/euler-v2-sonic/latest/gn`,
22020
- "239": `${EULER_SUBGRAPH_BASE}/euler-v2-tac/latest/gn`,
22021
- "480": `${EULER_SUBGRAPH_BASE}/euler-v2-worldchain/latest/gn`,
22022
- "999": `${EULER_SUBGRAPH_BASE}/euler-v2-hyperevm/latest/gn`,
22023
- "1923": `${EULER_SUBGRAPH_BASE}/euler-v2-swell/latest/gn`,
22024
- "5000": `${EULER_SUBGRAPH_BASE}/euler-v2-mantle/latest/gn`,
22025
- "8453": `${EULER_SUBGRAPH_BASE}/euler-v2-base/latest/gn`,
22026
- "9745": `${EULER_SUBGRAPH_BASE}/euler-v2-plasma/latest/gn`,
22027
- "42161": `${EULER_SUBGRAPH_BASE}/euler-v2-arbitrum/latest/gn`,
22028
- "43114": `${EULER_SUBGRAPH_BASE}/euler-v2-avalanche/latest/gn`,
22029
- "57073": `${EULER_SUBGRAPH_BASE}/euler-v2-ink/latest/gn`,
22030
- "60808": `${EULER_SUBGRAPH_BASE}/euler-v2-bob/latest/gn`,
22031
- "80094": `${EULER_SUBGRAPH_BASE}/euler-v2-berachain/latest/gn`
22032
- };
22033
- var SUBGRAPH_CACHE_TTL_MS = 3e4;
22034
- var subgraphCache = /* @__PURE__ */ new Map();
22035
- function fetchEulerSubAccountIndexes(chainId, owner) {
22080
+ var ACCOUNT_CACHE_TTL_MS = 5e3;
22081
+ var accountCache = /* @__PURE__ */ new Map();
22082
+ function indexesFromApiPositions(positions, owner) {
22083
+ const set = /* @__PURE__ */ new Set();
22084
+ for (const p of positions) {
22085
+ if (p.account) set.add(getSubAccountIndex(p.account, owner));
22086
+ }
22087
+ if (set.size === 0) set.add(0);
22088
+ return [...set];
22089
+ }
22090
+ function fetchEulerActiveIndexesViaApi(chainId, owner) {
22036
22091
  const key = `${chainId}:${owner.toLowerCase()}`;
22037
- const cached = subgraphCache.get(key);
22092
+ const cached = accountCache.get(key);
22038
22093
  if (cached) return cached.promise;
22039
- const promise = fetchSubAccountsFromSubgraph(chainId, owner).then((idxs) => idxs.length > 0 ? idxs : [0]).catch(() => [0]);
22040
- const timer = setTimeout(
22041
- () => subgraphCache.delete(key),
22042
- SUBGRAPH_CACHE_TTL_MS
22043
- );
22044
- subgraphCache.set(key, { promise, timer });
22094
+ const promise = fetchEulerPositionsFromApi(chainId, owner).then(
22095
+ (positions) => positions === void 0 ? void 0 : indexesFromApiPositions(positions, owner)
22096
+ ).catch(() => void 0);
22097
+ const timer = setTimeout(() => accountCache.delete(key), ACCOUNT_CACHE_TTL_MS);
22098
+ accountCache.set(key, { promise, timer });
22045
22099
  return promise;
22046
22100
  }
22047
- async function fetchSubAccountsFromSubgraph(chainId, owner) {
22048
- const url = EULER_SUBGRAPH_URLS[chainId];
22049
- if (!url) return [0];
22050
- const query3 = `{
22051
- accounts(first: 100, where: { owner: "${owner.toLowerCase()}" }) {
22052
- id
22053
- subAccount
22054
- }
22055
- }`;
22056
- const response = await fetch(url, {
22057
- method: "POST",
22058
- headers: { "Content-Type": "application/json" },
22059
- body: JSON.stringify({ query: query3 })
22060
- });
22061
- if (!response.ok) return [0];
22062
- const data = await response.json();
22063
- const accounts = data?.data?.accounts;
22064
- if (!accounts || accounts.length === 0) return [0];
22065
- return accounts.map((a) => {
22066
- const addr = a.subAccount || a.id;
22067
- return getSubAccountIndex(addr, owner);
22068
- });
22101
+ async function fetchEulerSubAccountIndexes(chainId, owner) {
22102
+ return await fetchEulerActiveIndexesViaApi(chainId, owner) ?? [0];
22103
+ }
22104
+ async function resolveEulerBuildIndexes(chainId, owner) {
22105
+ return await fetchEulerActiveIndexesViaApi(chainId, owner) ?? ALL_EULER_SUB_ACCOUNT_INDEXES;
22069
22106
  }
22070
22107
  var RESOLVED_STORE_TTL_MS = 6e4;
22071
22108
  var resolvedIndexesStore = /* @__PURE__ */ new Map();
@@ -22107,7 +22144,7 @@ var buildEulerUserCall = async (chainId, lender, account, subAccountIndexes) =>
22107
22144
  const accountLensAddress = config.accountLens;
22108
22145
  const evcAddress = config.evc;
22109
22146
  if (!accountLensAddress || !evcAddress) return [];
22110
- const indexes = subAccountIndexes ?? await fetchEulerSubAccountIndexes(chainId, account);
22147
+ const indexes = subAccountIndexes ?? await resolveEulerBuildIndexes(chainId, account);
22111
22148
  const sortedIndices = resolveSubAccountIndexes(account, indexes);
22112
22149
  storeResolvedIndexes(chainId, account, indexes);
22113
22150
  return sortedIndices.map((i) => ({
@@ -22311,16 +22348,16 @@ var buildGearboxV3UserCall = (chainId, _lender, account) => {
22311
22348
  };
22312
22349
 
22313
22350
  // src/lending/user-data/dolomite/userCallBuild.ts
22314
- var SUBGRAPH_CACHE_TTL_MS2 = 3e4;
22351
+ var SUBGRAPH_CACHE_TTL_MS = 3e4;
22315
22352
  var SUBGRAPH_TIMEOUT_MS2 = 1e4;
22316
- var subgraphCache2 = /* @__PURE__ */ new Map();
22353
+ var subgraphCache = /* @__PURE__ */ new Map();
22317
22354
  function fetchDolomiteAccountNumbers(chainId, owner) {
22318
22355
  const key = `${chainId}:${owner.toLowerCase()}`;
22319
- const cached = subgraphCache2.get(key);
22356
+ const cached = subgraphCache.get(key);
22320
22357
  if (cached) return cached.promise;
22321
22358
  const promise = fetchAccountNumbersFromSubgraph(chainId, owner).then((ns) => dedupeWithDefault(ns)).catch(() => ["0"]);
22322
- const timer = setTimeout(() => subgraphCache2.delete(key), SUBGRAPH_CACHE_TTL_MS2);
22323
- subgraphCache2.set(key, { promise, timer });
22359
+ const timer = setTimeout(() => subgraphCache.delete(key), SUBGRAPH_CACHE_TTL_MS);
22360
+ subgraphCache.set(key, { promise, timer });
22324
22361
  return promise;
22325
22362
  }
22326
22363
  function dedupeWithDefault(numbers) {
@@ -24845,6 +24882,72 @@ var multicallViemAbiArray = async (chainId, abi, calls, getEvmClient16, retry =
24845
24882
  );
24846
24883
  }
24847
24884
  };
24885
+ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient16, poolSize, retries = maxRetries, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, logs = false) => {
24886
+ if (poolSize <= 1) {
24887
+ return multicallViemAbiArray(
24888
+ chainId,
24889
+ abi,
24890
+ calls,
24891
+ getEvmClient16,
24892
+ true,
24893
+ 0,
24894
+ retries,
24895
+ allowFailure,
24896
+ batchSize,
24897
+ logs
24898
+ );
24899
+ }
24900
+ const abiIsArray = isArray(abi[0]);
24901
+ const contracts = calls.map(({ address, name, params }, i) => ({
24902
+ abi: abiIsArray ? abi?.[i] : abi,
24903
+ address,
24904
+ functionName: name,
24905
+ args: params
24906
+ }));
24907
+ const batches = [];
24908
+ for (let i = 0; i < contracts.length; i += batchSize) {
24909
+ batches.push({ start: i, items: contracts.slice(i, i + batchSize) });
24910
+ }
24911
+ const results = new Array(contracts.length);
24912
+ const runBatch = async (batch, rpcId, attemptsLeft, size) => {
24913
+ try {
24914
+ const provider = getEvmClient16(chainId, rpcId);
24915
+ const returnData = await provider.multicall({
24916
+ allowFailure,
24917
+ batchSize: size,
24918
+ contracts: batch.items
24919
+ });
24920
+ const mapped = allowFailure ? returnData.map(
24921
+ ({ result, status }) => status !== "success" ? "0x" : result
24922
+ ) : returnData;
24923
+ for (let j = 0; j < mapped.length; j++) {
24924
+ results[batch.start + j] = mapped[j];
24925
+ }
24926
+ } catch (error) {
24927
+ if (logs) console.log("error in sharded multicall batch", error);
24928
+ if (attemptsLeft <= 0) throw error;
24929
+ return runBatch(
24930
+ batch,
24931
+ rpcId + 1,
24932
+ attemptsLeft - 1,
24933
+ Math.max(1, Math.floor(size / 2))
24934
+ );
24935
+ }
24936
+ };
24937
+ const workers = Math.max(1, Math.min(poolSize, batches.length));
24938
+ let cursor = 0;
24939
+ const worker = async (workerId) => {
24940
+ while (true) {
24941
+ const idx = cursor++;
24942
+ if (idx >= batches.length) break;
24943
+ await runBatch(batches[idx], workerId, retries, batchSize);
24944
+ }
24945
+ };
24946
+ await Promise.all(
24947
+ Array.from({ length: workers }, (_3, w) => worker(w))
24948
+ );
24949
+ return results;
24950
+ };
24848
24951
  function prepareMulticallInputs(abi, calls) {
24849
24952
  const abiIsArray = isArray(abi[0]);
24850
24953
  return calls.map(({ address, name, params }, i) => ({
@@ -29435,7 +29538,7 @@ function unflattenLenderData(pools) {
29435
29538
  }
29436
29539
  return result;
29437
29540
  }
29438
- var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient16, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, retries = 3, logs = false) => {
29541
+ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient16, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, retries = 3, logs = false, concurrency = 1) => {
29439
29542
  const queries = organizeUserQueries(queriesRaw);
29440
29543
  const builtCalls = await Promise.all(
29441
29544
  queries.map(async (query3) => {
@@ -29451,13 +29554,12 @@ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient16, allowF
29451
29554
  })
29452
29555
  );
29453
29556
  const calls = builtCalls.flat();
29454
- return await multicallViemAbiArray(
29557
+ return await multicallShardedAbiArray(
29455
29558
  chainId,
29456
29559
  calls.map((call) => call.abi),
29457
29560
  calls.map((call) => call.call),
29458
29561
  getEvmClient16,
29459
- true,
29460
- 0,
29562
+ concurrency,
29461
29563
  retries,
29462
29564
  allowFailure,
29463
29565
  batchSize,
@@ -32887,6 +32989,62 @@ var coreLstFetcher = {
32887
32989
  }
32888
32990
  };
32889
32991
 
32992
+ // src/yields/intrinsic/fetchers/hastra.ts
32993
+ var HASTRA_POR_URL = "https://www.hastra.io/hastra-pulse/public/api/v1/por";
32994
+ var HASTRA_PRIME_KEY = "Hastra PRIME::PRIME";
32995
+ var hastraPrimeFetcher = {
32996
+ label: "Hastra",
32997
+ fetch: async () => {
32998
+ const res = await fetch(HASTRA_POR_URL, {
32999
+ method: "GET",
33000
+ headers: { Accept: "application/json" }
33001
+ }).then((r) => r.json());
33002
+ const card = res?.demo_prime_card ?? {};
33003
+ const current = Number(card.current_rate);
33004
+ const fee = Number(card.fee);
33005
+ const lifetimePct = Number(card.lifetime_average_rate) * 100;
33006
+ let apr;
33007
+ if (Number.isFinite(current)) {
33008
+ apr = current - (Number.isFinite(fee) ? fee : 0);
33009
+ } else if (Number.isFinite(lifetimePct)) {
33010
+ apr = lifetimePct;
33011
+ } else {
33012
+ apr = 0;
33013
+ }
33014
+ return { [HASTRA_PRIME_KEY]: Math.max(0, apr) };
33015
+ }
33016
+ };
33017
+
33018
+ // src/yields/intrinsic/fetchers/lombard.ts
33019
+ var LBTC_APY_URL = "https://mainnet.prod.lombard.finance/api/v1/analytics/estimated-apy";
33020
+ var lombardLbtcFetcher = {
33021
+ label: "LBTC",
33022
+ fetch: async () => {
33023
+ const res = await fetch(LBTC_APY_URL, {
33024
+ headers: { accept: "application/json" }
33025
+ }).then((r) => r.json());
33026
+ const frac = Number(res?.lbtc_estimated_apy);
33027
+ return { LBTC: Number.isFinite(frac) ? frac * 100 : 0 };
33028
+ }
33029
+ };
33030
+ var LOMBARD_VAULT_APY_URL = "https://mainnet.prod.lombard.finance/api/v1/analytics/vault/apy/history";
33031
+ var createLombardVaultFetcher = (wrapper, key) => ({
33032
+ label: `LOMBARD_VAULT:${wrapper}`,
33033
+ fetch: async () => {
33034
+ const url = `${LOMBARD_VAULT_APY_URL}?vault_wrapper=${wrapper}&interval=APY_INTERVAL_1M`;
33035
+ const res = await fetch(url, {
33036
+ headers: { accept: "application/json" }
33037
+ }).then((r) => r.json());
33038
+ const latest = Array.isArray(res?.snapshots) ? res.snapshots[0] : void 0;
33039
+ const frac = Number(latest?.total_apy);
33040
+ return { [key]: Number.isFinite(frac) ? frac * 100 : 0 };
33041
+ }
33042
+ });
33043
+ var lombardLbtcvFetcher = createLombardVaultFetcher(
33044
+ "VAULT_WRAPPER_BTCE",
33045
+ "LBTCv"
33046
+ );
33047
+
32890
33048
  // src/yields/intrinsic/index.ts
32891
33049
  async function fetchIntrinsicYields() {
32892
33050
  const wstethPromise = safeFetch(wstethFetcher.label, wstethFetcher.fetch);
@@ -32955,7 +33113,10 @@ async function fetchIntrinsicYields() {
32955
33113
  beraEthFetcher,
32956
33114
  lbgtFetcher,
32957
33115
  psxdcFetcher,
32958
- coreLstFetcher
33116
+ coreLstFetcher,
33117
+ hastraPrimeFetcher,
33118
+ lombardLbtcFetcher,
33119
+ lombardLbtcvFetcher
32959
33120
  ];
32960
33121
  const results = await Promise.all([
32961
33122
  wstethPromise,
@@ -37994,6 +38155,7 @@ var EULER_EARN_SUBGRAPH_URLS = {
37994
38155
  [Chain.AVALANCHE_C_CHAIN]: eulerSubgraphUrl("euler-v2-avalanche")
37995
38156
  };
37996
38157
  var hasEulerEarnVaultSubgraph = (chainId) => chainId in EULER_EARN_SUBGRAPH_URLS;
38158
+ var getEulerEarnSubgraphUrl = (chainId) => EULER_EARN_SUBGRAPH_URLS[chainId];
37997
38159
  var EULER_EARN_VAULTS_QUERY = `
37998
38160
  {
37999
38161
  eulerEarnVaults(first: 200, skip: 0) {
@@ -38222,10 +38384,176 @@ async function fetchEulerEarnVaultsFromSubgraph(chainId, prices = {}, tokenList
38222
38384
  }
38223
38385
  return out;
38224
38386
  }
38387
+ var EULER_DATA_API_BASE2 = "https://v3.euler.finance/v3";
38388
+ var API_TIMEOUT_MS = 1e4;
38389
+ var DETAIL_CONCURRENCY = 8;
38390
+ var BLOCK_TIME_SEC = {
38391
+ "1": 12,
38392
+ "56": 0.75,
38393
+ "130": 1,
38394
+ "146": 0.5,
38395
+ "8453": 2,
38396
+ "1923": 2,
38397
+ "42161": 0.25,
38398
+ "43114": 2
38399
+ };
38400
+ var DEFAULT_BLOCK_TIME_SEC = 2;
38401
+ var MAX_LAG_SECONDS = 30 * 60;
38402
+ function safeBigInt2(v) {
38403
+ if (v == null || v === "") return 0n;
38404
+ try {
38405
+ return BigInt(typeof v === "number" ? Math.trunc(v) : v);
38406
+ } catch {
38407
+ return 0n;
38408
+ }
38409
+ }
38410
+ async function getJson(url) {
38411
+ const controller = new AbortController();
38412
+ const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
38413
+ try {
38414
+ const res = await fetch(url, { signal: controller.signal });
38415
+ if (!res.ok) return void 0;
38416
+ return await res.json();
38417
+ } catch {
38418
+ return void 0;
38419
+ } finally {
38420
+ clearTimeout(timer);
38421
+ }
38422
+ }
38423
+ async function isEulerEarnSubgraphStale(chainId, subgraphUrl) {
38424
+ const [subHead, chainHead] = await Promise.all([
38425
+ fetchSubgraphHead(subgraphUrl),
38426
+ getEvmClientUniversal({ chain: chainId, rpcId: 0 }).getBlockNumber().then((b) => Number(b)).catch(() => null)
38427
+ ]);
38428
+ if (subHead == null || chainHead == null) return false;
38429
+ const lagBlocks = chainHead - subHead;
38430
+ if (lagBlocks <= 0) return false;
38431
+ const lagSeconds = lagBlocks * (BLOCK_TIME_SEC[chainId] ?? DEFAULT_BLOCK_TIME_SEC);
38432
+ return lagSeconds > MAX_LAG_SECONDS;
38433
+ }
38434
+ async function fetchSubgraphHead(subgraphUrl) {
38435
+ const controller = new AbortController();
38436
+ const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
38437
+ try {
38438
+ const res = await fetch(subgraphUrl, {
38439
+ method: "POST",
38440
+ headers: { "Content-Type": "application/json" },
38441
+ body: JSON.stringify({ query: "{ _meta { block { number } } }" }),
38442
+ signal: controller.signal
38443
+ });
38444
+ if (!res.ok) return null;
38445
+ const json = await res.json();
38446
+ const n = json?.data?._meta?.block?.number;
38447
+ return typeof n === "number" ? n : null;
38448
+ } catch {
38449
+ return null;
38450
+ } finally {
38451
+ clearTimeout(timer);
38452
+ }
38453
+ }
38454
+ function mapApiDetail(d, chainId, prices, tokenList) {
38455
+ const address = (d.address ?? "").toLowerCase();
38456
+ const underlying = (d.asset?.address ?? "").toLowerCase();
38457
+ if (!address || !underlying) return null;
38458
+ const assetMeta = tokenList[underlying];
38459
+ const decimals = Number(d.decimals ?? d.asset?.decimals ?? 18);
38460
+ const totalAssetsRaw = String(d.totalAssets ?? "0");
38461
+ const totalSupplyRaw = String(d.totalShares ?? "0");
38462
+ const convertToAssets = d.exchangeRate != null ? String(d.exchangeRate) : deriveConvertToAssets(totalAssetsRaw, totalSupplyRaw, decimals);
38463
+ const supplyRate = Number(d.supplyApy ?? d.apyCurrent ?? 0) || 0;
38464
+ const availableRaw = safeBigInt2(d.availableAssets) || safeBigInt2(totalAssetsRaw);
38465
+ const totalAssetsBig = safeBigInt2(totalAssetsRaw);
38466
+ const liquidityRaw = (availableRaw > totalAssetsBig ? totalAssetsBig : availableRaw).toString();
38467
+ const totalAssetsFormatted = Number(parseRawAmount(totalAssetsRaw, decimals));
38468
+ const liquidityFormatted = Number(parseRawAmount(liquidityRaw, decimals));
38469
+ const oracleKey = toOracleKey(assetMeta?.assetGroup) ?? toGenericPriceKey(underlying, chainId);
38470
+ const priceUsd = prices[oracleKey] ?? prices[underlying] ?? 0;
38471
+ const totalAssetsUsd = priceUsd ? totalAssetsFormatted * priceUsd : Number(d.totalSupplyUsd ?? 0);
38472
+ const liquidityUsd = priceUsd ? liquidityFormatted * priceUsd : Number(d.availableAssetsUsd ?? 0);
38473
+ return {
38474
+ address,
38475
+ underlying,
38476
+ symbol: d.symbol ?? "",
38477
+ name: d.name ?? "",
38478
+ decimals,
38479
+ totalAssets: totalAssetsRaw,
38480
+ totalSupply: totalSupplyRaw,
38481
+ convertToAssets,
38482
+ supplyRate,
38483
+ rewardsRate: 0,
38484
+ depositRate: supplyRate,
38485
+ // The API doesn't surface the performance fee on this endpoint; the
38486
+ // headline APY is already net, so 0 here only affects fee display.
38487
+ fee: 0,
38488
+ owner: d.owner?.toLowerCase(),
38489
+ curator: d.curator?.toLowerCase(),
38490
+ curatorName: curatorNameFromVaultName(d.name, assetMeta?.symbol),
38491
+ guardian: d.guardian?.toLowerCase(),
38492
+ feeRecipient: d.feeReceiver?.toLowerCase() || void 0,
38493
+ asset: assetMeta,
38494
+ priceUsd: priceUsd || void 0,
38495
+ totalAssetsFormatted,
38496
+ totalAssetsUsd,
38497
+ liquidity: liquidityRaw,
38498
+ liquidityFormatted,
38499
+ liquidityUsd
38500
+ };
38501
+ }
38502
+ async function mapWithConcurrency(items, limit, fn) {
38503
+ const out = new Array(items.length);
38504
+ let cursor = 0;
38505
+ const worker = async () => {
38506
+ while (true) {
38507
+ const i = cursor++;
38508
+ if (i >= items.length) break;
38509
+ out[i] = await fn(items[i]);
38510
+ }
38511
+ };
38512
+ await Promise.all(
38513
+ Array.from({ length: Math.min(limit, items.length) }, () => worker())
38514
+ );
38515
+ return out;
38516
+ }
38517
+ async function fetchEulerEarnVaultsFromApi(chainId, prices = {}, tokenList = {}) {
38518
+ const list = await getJson(
38519
+ `${EULER_DATA_API_BASE2}/earn/vaults?chainId=${chainId}&limit=200`
38520
+ );
38521
+ if (!list) return void 0;
38522
+ const rows = list.data ?? [];
38523
+ if (rows.length === 0) return {};
38524
+ const details = await mapWithConcurrency(
38525
+ rows,
38526
+ DETAIL_CONCURRENCY,
38527
+ (row) => getJson(
38528
+ `${EULER_DATA_API_BASE2}/earn/vaults/${chainId}/${row.address}?include=strategies`
38529
+ ).then((d) => d?.data)
38530
+ );
38531
+ const out = {};
38532
+ for (const d of details) {
38533
+ if (!d) continue;
38534
+ const v = mapApiDetail(d, chainId, prices, tokenList);
38535
+ if (v) out[v.address] = v;
38536
+ }
38537
+ return out;
38538
+ }
38225
38539
 
38226
38540
  // src/vaults/euler-earn/fetchPublic.ts
38541
+ var isNonEmpty = (v) => !!v && Object.keys(v).length > 0;
38227
38542
  var fetchEulerEarnVaults = async (chainId, prices = {}, tokenList = {}) => {
38228
- return fetchEulerEarnVaultsFromSubgraph(chainId, prices, tokenList);
38543
+ const subgraphUrl = getEulerEarnSubgraphUrl(chainId);
38544
+ if (!subgraphUrl) {
38545
+ return await fetchEulerEarnVaultsFromApi(chainId, prices, tokenList) ?? {};
38546
+ }
38547
+ const [stale, subgraph] = await Promise.all([
38548
+ isEulerEarnSubgraphStale(chainId, subgraphUrl).catch(() => false),
38549
+ fetchEulerEarnVaultsFromSubgraph(chainId, prices, tokenList).then((r) => ({ ok: true, data: r })).catch(() => ({ ok: false, data: void 0 }))
38550
+ ]);
38551
+ if (!stale && subgraph.ok && isNonEmpty(subgraph.data)) {
38552
+ return subgraph.data;
38553
+ }
38554
+ const fromApi = await fetchEulerEarnVaultsFromApi(chainId, prices, tokenList);
38555
+ if (isNonEmpty(fromApi)) return fromApi;
38556
+ return subgraph.ok && subgraph.data ? subgraph.data : {};
38229
38557
  };
38230
38558
  var CHAIN_ID4 = "1";
38231
38559
  var SWBTC = "0x8db2350d78abc13f5673a411d4700bcf87864dde";
@@ -38356,36 +38684,6 @@ var stceloFetcher = {
38356
38684
  return { STCELO: apr };
38357
38685
  }
38358
38686
  };
38359
-
38360
- // src/yields/intrinsic/fetchers/lombard.ts
38361
- var LBTC_APY_URL = "https://mainnet.prod.lombard.finance/api/v1/analytics/estimated-apy";
38362
- var lombardLbtcFetcher = {
38363
- label: "LBTC",
38364
- fetch: async () => {
38365
- const res = await fetch(LBTC_APY_URL, {
38366
- headers: { accept: "application/json" }
38367
- }).then((r) => r.json());
38368
- const frac = Number(res?.lbtc_estimated_apy);
38369
- return { LBTC: Number.isFinite(frac) ? frac * 100 : 0 };
38370
- }
38371
- };
38372
- var LOMBARD_VAULT_APY_URL = "https://mainnet.prod.lombard.finance/api/v1/analytics/vault/apy/history";
38373
- var createLombardVaultFetcher = (wrapper, key) => ({
38374
- label: `LOMBARD_VAULT:${wrapper}`,
38375
- fetch: async () => {
38376
- const url = `${LOMBARD_VAULT_APY_URL}?vault_wrapper=${wrapper}&interval=APY_INTERVAL_1M`;
38377
- const res = await fetch(url, {
38378
- headers: { accept: "application/json" }
38379
- }).then((r) => r.json());
38380
- const latest = Array.isArray(res?.snapshots) ? res.snapshots[0] : void 0;
38381
- const frac = Number(latest?.total_apy);
38382
- return { [key]: Number.isFinite(frac) ? frac * 100 : 0 };
38383
- }
38384
- });
38385
- var lombardLbtcvFetcher = createLombardVaultFetcher(
38386
- "VAULT_WRAPPER_BTCE",
38387
- "LBTCv"
38388
- );
38389
38687
  var CHAIN_ID6 = "1284";
38390
38688
  var STDOT = "0xbc7e02c4178a7df7d3e564323a5c359dc96c4db4";
38391
38689
  var ONE_E185 = 10n ** 18n;
@@ -44832,6 +45130,28 @@ var SINGLE_CHAIN_ENTRIES = {
44832
45130
  withdrawalCooldownSeconds: 604800,
44833
45131
  yieldFetcher: mapleFetcher,
44834
45132
  yieldKey: "SYRUPUSDT"
45133
+ },
45134
+ {
45135
+ // Hastra Democratized PRIME — ERC-4626 over wYLDS (itself ERC-4626 over
45136
+ // USDC), so the share/asset ratio accrues on-chain (`convertToAssets`).
45137
+ // Solana-primary; the Ethereum deployment exists (verified on-chain:
45138
+ // symbol PRIME, 6 decimals, asset() = wYLDS) but carries no user holders
45139
+ // yet. Deposits are whitelist-gated, so `isMintable` is false — we list
45140
+ // + price it, but don't advertise a permissionless mint that would
45141
+ // revert. Two-phase exit (`requestRedeem` → `completeRedeem`). APR from
45142
+ // the public Proof-of-Reserve feed via `hastraPrimeFetcher`.
45143
+ address: "0x19ebb35279a16207ec4ba82799cc64715065f7f6",
45144
+ underlying: "0x6ad038ca6c04e885630851278ca0a856ad9a66cc",
45145
+ // wYLDS
45146
+ symbol: "PRIME",
45147
+ brand: "Hastra",
45148
+ decimals: 6,
45149
+ underlyingDecimals: 6,
45150
+ isRebasing: false,
45151
+ isMintable: false,
45152
+ withdrawalMode: "request-based",
45153
+ yieldFetcher: hastraPrimeFetcher,
45154
+ yieldKey: "Hastra PRIME::PRIME"
44835
45155
  }
44836
45156
  ],
44837
45157
  "8453": [
@@ -45747,7 +46067,7 @@ var GMX_SUPPORTED_CHAINS = Object.keys(GMX_API_HOSTS);
45747
46067
  var getGmxApiHost = (chainId) => GMX_API_HOSTS[chainId];
45748
46068
 
45749
46069
  // src/vaults/gmx/api.ts
45750
- var getJson = async (url) => {
46070
+ var getJson2 = async (url) => {
45751
46071
  const res = await fetch(url, {
45752
46072
  method: "GET",
45753
46073
  headers: { Accept: "application/json" }
@@ -45759,12 +46079,12 @@ var fetchGmxRawData = async (chainId, period, apiUrlOverride) => {
45759
46079
  const host = apiUrlOverride ?? getGmxApiHost(chainId);
45760
46080
  if (!host) throw new Error(`GMX not supported on chain ${chainId}`);
45761
46081
  const [apy, marketsRes, glvsRes, tokensRes] = await Promise.all([
45762
- getJson(`${host}/apy?period=${encodeURIComponent(period)}`),
45763
- getJson(`${host}/markets`).catch(() => ({
46082
+ getJson2(`${host}/apy?period=${encodeURIComponent(period)}`),
46083
+ getJson2(`${host}/markets`).catch(() => ({
45764
46084
  markets: []
45765
46085
  })),
45766
- getJson(`${host}/glvs`).catch(() => ({ glvs: [] })),
45767
- getJson(`${host}/tokens`).catch(() => ({
46086
+ getJson2(`${host}/glvs`).catch(() => ({ glvs: [] })),
46087
+ getJson2(`${host}/tokens`).catch(() => ({
45768
46088
  tokens: []
45769
46089
  }))
45770
46090
  ]);