@1delta/data-sdk 0.0.51 → 0.0.53

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
@@ -77,6 +77,8 @@ var LENDER_DATA_DEFAULTS = () => ({
77
77
  termMaxConfig: {},
78
78
  exactlyConfig: {},
79
79
  exactlyMarkets: {},
80
+ flyingTulipConfig: {},
81
+ flyingTulipAssets: {},
80
82
  tellerConfig: {},
81
83
  tellerPools: {},
82
84
  liquityConfig: {},
@@ -340,6 +342,24 @@ var isListaSmartLpAsset = (entry, asset) => {
340
342
  );
341
343
  };
342
344
 
345
+ // src/lending/flyingTulip.ts
346
+ var flyingTulipConfig = () => getGlobalData2()?.flyingTulipConfig;
347
+ var flyingTulipAssets = () => getGlobalData2()?.flyingTulipAssets;
348
+ var flyingTulipConfigFor = (lender, chainId) => getGlobalData2()?.flyingTulipConfig?.[lender]?.[String(chainId)];
349
+ var flyingTulipAssetsFor = (lender, chainId) => getGlobalData2()?.flyingTulipAssets?.[lender]?.[String(chainId)];
350
+ var flyingTulipLendersByChain = (chainId) => {
351
+ const chain = String(chainId);
352
+ const cfg = getGlobalData2()?.flyingTulipConfig ?? {};
353
+ const rosters = getGlobalData2()?.flyingTulipAssets ?? {};
354
+ const keys = [];
355
+ for (const lender of Object.keys(cfg)) {
356
+ if (cfg[lender]?.[chain]?.lendingLens && (rosters[lender]?.[chain]?.assets?.length ?? 0) > 0) {
357
+ keys.push(lender);
358
+ }
359
+ }
360
+ return keys;
361
+ };
362
+
343
363
  // src/lending/midnight.ts
344
364
  var midnightConfig = () => getGlobalData2()?.midnightConfig;
345
365
  var MIDNIGHT_API_OVERRIDE_KEY = "__1delta_midnight_api_base__";
@@ -353,12 +373,43 @@ var resolveMidnightApiBase = (chainId) => {
353
373
  const cfg = midnightConfig()?.[chainId]?.apiBaseUrl;
354
374
  return (cfg && cfg.length > 0 ? cfg : "https://api.morpho.org/v0/midnight").replace(/\/+$/, "");
355
375
  };
376
+ var TENOR_API_OVERRIDE_KEY = "__1delta_tenor_api_url__";
377
+ var setTenorApiUrl = (url) => {
378
+ globalThis[TENOR_API_OVERRIDE_KEY] = url && url.length > 0 ? url : void 0;
379
+ };
380
+ var tenorApiUrlOverride = () => globalThis[TENOR_API_OVERRIDE_KEY];
381
+ var resolveTenorApiUrl = (chainId) => {
382
+ const override = tenorApiUrlOverride();
383
+ if (override) return override.replace(/\/+$/, "");
384
+ const cfg = midnightConfig()?.[chainId]?.tenorApiUrl;
385
+ return (cfg && cfg.length > 0 ? cfg : "https://api.tenor.finance/graphql").replace(/\/+$/, "");
386
+ };
356
387
  var midnightMarkets = () => getGlobalData2()?.midnightMarkets;
357
388
  var midnightMarketsByChain = (chainId) => getGlobalData2()?.midnightMarkets?.[String(chainId)] ?? [];
358
389
  var midnightMarketById = (chainId, marketId) => {
359
390
  const lower = marketId.toLowerCase();
360
391
  return midnightMarketsByChain(chainId).find((m) => m.marketId.toLowerCase() === lower);
361
392
  };
393
+ var midnightMarketIsEnterable = (market, nowSec = Math.floor(Date.now() / 1e3)) => {
394
+ if (Number(market.maturity) <= nowSec) return false;
395
+ if (market.deprecatedAt && Number(market.deprecatedAt) <= nowSec) return false;
396
+ return market.gating?.enter === "open";
397
+ };
398
+ var midnightNotEnterableReason = (market, nowSec = Math.floor(Date.now() / 1e3)) => {
399
+ if (Number(market.maturity) <= nowSec) return "market has matured";
400
+ if (market.deprecatedAt && Number(market.deprecatedAt) <= nowSec)
401
+ return "market is deprecated \u2014 existing positions can still be repaid, exited and liquidated";
402
+ switch (market.gating?.enter) {
403
+ case "open":
404
+ return void 0;
405
+ case "allowlist":
406
+ return "permissioned market: taking offers is restricted to an allowlist";
407
+ case "unknown":
408
+ return `permissioned market: unrecognised enter gate ${market.gating.enterGate}`;
409
+ default:
410
+ return "market gating could not be resolved";
411
+ }
412
+ };
362
413
 
363
414
  // src/lending/term.ts
364
415
  var termConfig = () => getGlobalData2()?.termConfig;
@@ -1213,6 +1264,11 @@ exports.fluidChains = fluidChains;
1213
1264
  exports.fluidResolvers = fluidResolvers;
1214
1265
  exports.fluidVaultEntries = fluidVaultEntries;
1215
1266
  exports.fluidVaults = fluidVaults;
1267
+ exports.flyingTulipAssets = flyingTulipAssets;
1268
+ exports.flyingTulipAssetsFor = flyingTulipAssetsFor;
1269
+ exports.flyingTulipConfig = flyingTulipConfig;
1270
+ exports.flyingTulipConfigFor = flyingTulipConfigFor;
1271
+ exports.flyingTulipLendersByChain = flyingTulipLendersByChain;
1216
1272
  exports.frankencoinChainData = frankencoinChainData;
1217
1273
  exports.frankencoinConfig = frankencoinConfig;
1218
1274
  exports.frankencoinConfigFor = frankencoinConfigFor;
@@ -1279,8 +1335,10 @@ exports.loadCachedJson = loadCachedJson;
1279
1335
  exports.midnightApiBaseOverride = midnightApiBaseOverride;
1280
1336
  exports.midnightConfig = midnightConfig;
1281
1337
  exports.midnightMarketById = midnightMarketById;
1338
+ exports.midnightMarketIsEnterable = midnightMarketIsEnterable;
1282
1339
  exports.midnightMarkets = midnightMarkets;
1283
1340
  exports.midnightMarketsByChain = midnightMarketsByChain;
1341
+ exports.midnightNotEnterableReason = midnightNotEnterableReason;
1284
1342
  exports.morphoBundler3 = morphoBundler3;
1285
1343
  exports.morphoOracles = morphoOracles;
1286
1344
  exports.morphoPools = morphoPools;
@@ -1295,6 +1353,7 @@ exports.parseSiloV2LenderKey = parseSiloV2LenderKey;
1295
1353
  exports.parseSiloV3LenderKey = parseSiloV3LenderKey;
1296
1354
  exports.parseTermMaxLenderKey = parseTermMaxLenderKey;
1297
1355
  exports.resolveMidnightApiBase = resolveMidnightApiBase;
1356
+ exports.resolveTenorApiUrl = resolveTenorApiUrl;
1298
1357
  exports.resolveTermApiBase = resolveTermApiBase;
1299
1358
  exports.resolveTermOrderStoreBase = resolveTermOrderStoreBase;
1300
1359
  exports.resupplyConfig = resupplyConfig;
@@ -1309,6 +1368,7 @@ exports.riverMarkets = riverMarkets;
1309
1368
  exports.setMidnightApiBase = setMidnightApiBase;
1310
1369
  exports.setRemoteCacheGithubToken = setRemoteCacheGithubToken;
1311
1370
  exports.setRemoteCacheStore = setRemoteCacheStore;
1371
+ exports.setTenorApiUrl = setTenorApiUrl;
1312
1372
  exports.setTermApiBase = setTermApiBase;
1313
1373
  exports.setTermOrderStoreBase = setTermOrderStoreBase;
1314
1374
  exports.siloMarkets = siloMarkets;
@@ -1327,6 +1387,7 @@ exports.tellerConfigByChain = tellerConfigByChain;
1327
1387
  exports.tellerPoolByAddress = tellerPoolByAddress;
1328
1388
  exports.tellerPools = tellerPools;
1329
1389
  exports.tellerPoolsByChain = tellerPoolsByChain;
1390
+ exports.tenorApiUrlOverride = tenorApiUrlOverride;
1330
1391
  exports.termApiBaseOverride = termApiBaseOverride;
1331
1392
  exports.termConfig = termConfig;
1332
1393
  exports.termMarketById = termMarketById;
package/dist/index.mjs CHANGED
@@ -75,6 +75,8 @@ var LENDER_DATA_DEFAULTS = () => ({
75
75
  termMaxConfig: {},
76
76
  exactlyConfig: {},
77
77
  exactlyMarkets: {},
78
+ flyingTulipConfig: {},
79
+ flyingTulipAssets: {},
78
80
  tellerConfig: {},
79
81
  tellerPools: {},
80
82
  liquityConfig: {},
@@ -338,6 +340,24 @@ var isListaSmartLpAsset = (entry, asset) => {
338
340
  );
339
341
  };
340
342
 
343
+ // src/lending/flyingTulip.ts
344
+ var flyingTulipConfig = () => getGlobalData2()?.flyingTulipConfig;
345
+ var flyingTulipAssets = () => getGlobalData2()?.flyingTulipAssets;
346
+ var flyingTulipConfigFor = (lender, chainId) => getGlobalData2()?.flyingTulipConfig?.[lender]?.[String(chainId)];
347
+ var flyingTulipAssetsFor = (lender, chainId) => getGlobalData2()?.flyingTulipAssets?.[lender]?.[String(chainId)];
348
+ var flyingTulipLendersByChain = (chainId) => {
349
+ const chain = String(chainId);
350
+ const cfg = getGlobalData2()?.flyingTulipConfig ?? {};
351
+ const rosters = getGlobalData2()?.flyingTulipAssets ?? {};
352
+ const keys = [];
353
+ for (const lender of Object.keys(cfg)) {
354
+ if (cfg[lender]?.[chain]?.lendingLens && (rosters[lender]?.[chain]?.assets?.length ?? 0) > 0) {
355
+ keys.push(lender);
356
+ }
357
+ }
358
+ return keys;
359
+ };
360
+
341
361
  // src/lending/midnight.ts
342
362
  var midnightConfig = () => getGlobalData2()?.midnightConfig;
343
363
  var MIDNIGHT_API_OVERRIDE_KEY = "__1delta_midnight_api_base__";
@@ -351,12 +371,43 @@ var resolveMidnightApiBase = (chainId) => {
351
371
  const cfg = midnightConfig()?.[chainId]?.apiBaseUrl;
352
372
  return (cfg && cfg.length > 0 ? cfg : "https://api.morpho.org/v0/midnight").replace(/\/+$/, "");
353
373
  };
374
+ var TENOR_API_OVERRIDE_KEY = "__1delta_tenor_api_url__";
375
+ var setTenorApiUrl = (url) => {
376
+ globalThis[TENOR_API_OVERRIDE_KEY] = url && url.length > 0 ? url : void 0;
377
+ };
378
+ var tenorApiUrlOverride = () => globalThis[TENOR_API_OVERRIDE_KEY];
379
+ var resolveTenorApiUrl = (chainId) => {
380
+ const override = tenorApiUrlOverride();
381
+ if (override) return override.replace(/\/+$/, "");
382
+ const cfg = midnightConfig()?.[chainId]?.tenorApiUrl;
383
+ return (cfg && cfg.length > 0 ? cfg : "https://api.tenor.finance/graphql").replace(/\/+$/, "");
384
+ };
354
385
  var midnightMarkets = () => getGlobalData2()?.midnightMarkets;
355
386
  var midnightMarketsByChain = (chainId) => getGlobalData2()?.midnightMarkets?.[String(chainId)] ?? [];
356
387
  var midnightMarketById = (chainId, marketId) => {
357
388
  const lower = marketId.toLowerCase();
358
389
  return midnightMarketsByChain(chainId).find((m) => m.marketId.toLowerCase() === lower);
359
390
  };
391
+ var midnightMarketIsEnterable = (market, nowSec = Math.floor(Date.now() / 1e3)) => {
392
+ if (Number(market.maturity) <= nowSec) return false;
393
+ if (market.deprecatedAt && Number(market.deprecatedAt) <= nowSec) return false;
394
+ return market.gating?.enter === "open";
395
+ };
396
+ var midnightNotEnterableReason = (market, nowSec = Math.floor(Date.now() / 1e3)) => {
397
+ if (Number(market.maturity) <= nowSec) return "market has matured";
398
+ if (market.deprecatedAt && Number(market.deprecatedAt) <= nowSec)
399
+ return "market is deprecated \u2014 existing positions can still be repaid, exited and liquidated";
400
+ switch (market.gating?.enter) {
401
+ case "open":
402
+ return void 0;
403
+ case "allowlist":
404
+ return "permissioned market: taking offers is restricted to an allowlist";
405
+ case "unknown":
406
+ return `permissioned market: unrecognised enter gate ${market.gating.enterGate}`;
407
+ default:
408
+ return "market gating could not be resolved";
409
+ }
410
+ };
360
411
 
361
412
  // src/lending/term.ts
362
413
  var termConfig = () => getGlobalData2()?.termConfig;
@@ -1145,4 +1196,4 @@ async function fetchMainTokensMap() {
1145
1196
  }
1146
1197
  }
1147
1198
 
1148
- export { COOLER_ETHEREUM_CONFIG, CURVANCE_MONAD_CONFIG, FRAXLEND_ETHEREUM_CONFIG, GEARBOX_ACCOUNT_COMPRESSOR_V310, REMOTE_CACHE_STORE_TTL_S, RESUPPLY_ETHEREUM_CONFIG, RemoteFetchError, aaveOracles, aaveOraclesConfig, aavePools, aaveReserves, aaveTokens, aaveV4Oracles, aaveV4Peripherals, aaveV4SpokeLenderKey, aaveV4Spokes, aaveWethGateway, assertTwyneKeysUnique, chainLogoURI, chains, clearRemoteCache, compoundV2Oracles, compoundV2OraclesConfig, compoundV2Pools, compoundV2Reserves, compoundV2TokenArray, compoundV2Tokens, compoundV3BaseData, compoundV3Bulker, compoundV3OraclesData, compoundV3Pools, compoundV3Reserves, coolerConfig, coolerConfigFor, coolerLendersByChain, curvanceConfig, curvanceConfigFor, curvanceLendersByChain, curvancePositionManager, curvancePositionManagersFor, dolomiteChains, dolomiteConfigs, dolomiteEmode, dolomiteMarketIdByToken, dssChainData, dssConfigFor, dssDebtJoin, dssDebtToken, dssMarketByIlk, eulerConfigs, eulerVaults, exactlyConfig, exactlyMarketByAddress, exactlyMarketByAsset, exactlyMarkets, exactlyMarketsByChain, fetchMainTokensMap, fetchRemoteJson, fetchTokenList, fetchTokenListFile, fetchTokenLists, findAaveV4PositionManager, fluidChains, fluidResolvers, fluidVaultEntries, fluidVaults, frankencoinChainData, frankencoinConfig, frankencoinConfigFor, frankencoinLendersByChain, frankencoinMarketByPosition, frankencoinMarkets, fraxlendConfig, fraxlendConfigFor, fraxlendLendersByChain, fraxlendPairKey, fraxlendPairsFor, gearboxAccountCompressor, gearboxAddressProviderV310, gearboxBotListV3, gearboxChains, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxResolvers, gearboxV3LenderKey, getAaveV4GatewayAddresses, getAaveV4PositionManagers, getAaveV4SpokeAccess, getAaveV4SpokeEntry, getAaveV4SpokePeripherals, getChainEntries, getSiloV2MarketEntry, getSiloV3MarketEntry, initConfig, initializeChainData, initializeLenderData, inverseChainData, inverseConfig, inverseConfigFor, inverseLendersByChain, inverseMarketByAddress, inverseMarkets, isAaveV4OperationRestricted, isListaSmartLpAsset, liquityBranchByIndex, liquityBranchByTroveManager, liquityBranchesByChain, liquityConfig, liquityConfigFor, liquityLendersByChain, liquityMarkets, listaCollateralProvider, listaCollateralProviders, listaNativeProvider, listaSmartLpByCollateral, llamaLendApiBaseUrl, llamaLendChainData, llamaLendConfig, llamaLendConfigFor, llamaLendLenderKey, llamaLendLendersByChain, llamaLendLeverageZap, llamaLendMarketByController, llamaLendMarketByVault, llamaLendMarkets, llamaLendSupportsDelegation, llamaLendSupportsLeverage, loadCached, loadCachedJson, midnightApiBaseOverride, midnightConfig, midnightMarketById, midnightMarkets, midnightMarketsByChain, morphoBundler3, morphoOracles, morphoPools, morphoTypeMarkets, morphoTypeOracles, morphoTypeVaults, parseAaveV4SpokeLenderKey, parseFraxlendPairKey, parseGearboxV3LenderKey, parseLlamaLendLenderKey, parseSiloV2LenderKey, parseSiloV3LenderKey, parseTermMaxLenderKey, resolveMidnightApiBase, resolveTermApiBase, resolveTermOrderStoreBase, resupplyConfig, resupplyConfigFor, resupplyLendersByChain, riverChainData, riverConfig, riverConfigFor, riverLendersByChain, riverMarketByIndex, riverMarkets, setMidnightApiBase, setRemoteCacheGithubToken, setRemoteCacheStore, setTermApiBase, setTermOrderStoreBase, siloMarkets, siloMarketsV3, siloPeripherals, siloPeripheralsV3, siloV2LenderKey, siloV3LenderKey, skyChainData, skyConfig, skyConfigFor, skyLendersByChain, skyMarkets, tellerConfig, tellerConfigByChain, tellerPoolByAddress, tellerPools, tellerPoolsByChain, termApiBaseOverride, termConfig, termMarketById, termMarkets, termMarketsByChain, termMaxApiBaseUrl, termMaxChainIds, termMaxConfig, termMaxConfigByChain, termMaxLenderKey, termOrderStoreBaseOverride, twyneBaseKey, twyneBeaconFor, twyneChainData, twyneConfig, twyneConfigFor, twyneLendersByChain, twyneMarketByKey, twyneMarketFor, twyneMarketKey, twyneMarkets, twyneMarketsForIntermediateVault, twyneOperator, usddChainData, usddConfig, usddConfigFor, usddLendersByChain, usddMarketByIlk, usddMarkets };
1199
+ export { COOLER_ETHEREUM_CONFIG, CURVANCE_MONAD_CONFIG, FRAXLEND_ETHEREUM_CONFIG, GEARBOX_ACCOUNT_COMPRESSOR_V310, REMOTE_CACHE_STORE_TTL_S, RESUPPLY_ETHEREUM_CONFIG, RemoteFetchError, aaveOracles, aaveOraclesConfig, aavePools, aaveReserves, aaveTokens, aaveV4Oracles, aaveV4Peripherals, aaveV4SpokeLenderKey, aaveV4Spokes, aaveWethGateway, assertTwyneKeysUnique, chainLogoURI, chains, clearRemoteCache, compoundV2Oracles, compoundV2OraclesConfig, compoundV2Pools, compoundV2Reserves, compoundV2TokenArray, compoundV2Tokens, compoundV3BaseData, compoundV3Bulker, compoundV3OraclesData, compoundV3Pools, compoundV3Reserves, coolerConfig, coolerConfigFor, coolerLendersByChain, curvanceConfig, curvanceConfigFor, curvanceLendersByChain, curvancePositionManager, curvancePositionManagersFor, dolomiteChains, dolomiteConfigs, dolomiteEmode, dolomiteMarketIdByToken, dssChainData, dssConfigFor, dssDebtJoin, dssDebtToken, dssMarketByIlk, eulerConfigs, eulerVaults, exactlyConfig, exactlyMarketByAddress, exactlyMarketByAsset, exactlyMarkets, exactlyMarketsByChain, fetchMainTokensMap, fetchRemoteJson, fetchTokenList, fetchTokenListFile, fetchTokenLists, findAaveV4PositionManager, fluidChains, fluidResolvers, fluidVaultEntries, fluidVaults, flyingTulipAssets, flyingTulipAssetsFor, flyingTulipConfig, flyingTulipConfigFor, flyingTulipLendersByChain, frankencoinChainData, frankencoinConfig, frankencoinConfigFor, frankencoinLendersByChain, frankencoinMarketByPosition, frankencoinMarkets, fraxlendConfig, fraxlendConfigFor, fraxlendLendersByChain, fraxlendPairKey, fraxlendPairsFor, gearboxAccountCompressor, gearboxAddressProviderV310, gearboxBotListV3, gearboxChains, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxResolvers, gearboxV3LenderKey, getAaveV4GatewayAddresses, getAaveV4PositionManagers, getAaveV4SpokeAccess, getAaveV4SpokeEntry, getAaveV4SpokePeripherals, getChainEntries, getSiloV2MarketEntry, getSiloV3MarketEntry, initConfig, initializeChainData, initializeLenderData, inverseChainData, inverseConfig, inverseConfigFor, inverseLendersByChain, inverseMarketByAddress, inverseMarkets, isAaveV4OperationRestricted, isListaSmartLpAsset, liquityBranchByIndex, liquityBranchByTroveManager, liquityBranchesByChain, liquityConfig, liquityConfigFor, liquityLendersByChain, liquityMarkets, listaCollateralProvider, listaCollateralProviders, listaNativeProvider, listaSmartLpByCollateral, llamaLendApiBaseUrl, llamaLendChainData, llamaLendConfig, llamaLendConfigFor, llamaLendLenderKey, llamaLendLendersByChain, llamaLendLeverageZap, llamaLendMarketByController, llamaLendMarketByVault, llamaLendMarkets, llamaLendSupportsDelegation, llamaLendSupportsLeverage, loadCached, loadCachedJson, midnightApiBaseOverride, midnightConfig, midnightMarketById, midnightMarketIsEnterable, midnightMarkets, midnightMarketsByChain, midnightNotEnterableReason, morphoBundler3, morphoOracles, morphoPools, morphoTypeMarkets, morphoTypeOracles, morphoTypeVaults, parseAaveV4SpokeLenderKey, parseFraxlendPairKey, parseGearboxV3LenderKey, parseLlamaLendLenderKey, parseSiloV2LenderKey, parseSiloV3LenderKey, parseTermMaxLenderKey, resolveMidnightApiBase, resolveTenorApiUrl, resolveTermApiBase, resolveTermOrderStoreBase, resupplyConfig, resupplyConfigFor, resupplyLendersByChain, riverChainData, riverConfig, riverConfigFor, riverLendersByChain, riverMarketByIndex, riverMarkets, setMidnightApiBase, setRemoteCacheGithubToken, setRemoteCacheStore, setTenorApiUrl, setTermApiBase, setTermOrderStoreBase, siloMarkets, siloMarketsV3, siloPeripherals, siloPeripheralsV3, siloV2LenderKey, siloV3LenderKey, skyChainData, skyConfig, skyConfigFor, skyLendersByChain, skyMarkets, tellerConfig, tellerConfigByChain, tellerPoolByAddress, tellerPools, tellerPoolsByChain, tenorApiUrlOverride, termApiBaseOverride, termConfig, termMarketById, termMarkets, termMarketsByChain, termMaxApiBaseUrl, termMaxChainIds, termMaxConfig, termMaxConfigByChain, termMaxLenderKey, termOrderStoreBaseOverride, twyneBaseKey, twyneBeaconFor, twyneChainData, twyneConfig, twyneConfigFor, twyneLendersByChain, twyneMarketByKey, twyneMarketFor, twyneMarketKey, twyneMarkets, twyneMarketsForIntermediateVault, twyneOperator, usddChainData, usddConfig, usddConfigFor, usddLendersByChain, usddMarketByIlk, usddMarkets };
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Flying Tulip — Andre Cronje's CEX-style CROSS-MARGIN lender on Ethereum (1)
3
+ * and Sonic (146). One `PositionsManager` per chain holds every asset and
4
+ * health is one global check, so `FLYING_TULIP` is both the dispatch key and
5
+ * the market key (the collapsed Exactly shape — see FLYING_TULIP.md).
6
+ *
7
+ * Two published files, both prerequisites (no built-in seed — the risk knobs
8
+ * are one ungated Safe call from moving and the two chains already disagree,
9
+ * so pinning them here is how a stale number outlives a live change):
10
+ * - `config/flying-tulip.json` — per-chain protocol addresses (CREATE2, so
11
+ * address-identical across chains — but NEVER config-identical).
12
+ * - `data/flying-tulip-assets.json` — the `AssetSet`-log-discovered roster
13
+ * plus the per-chain margin knobs, regenerated by lender-metadata's
14
+ * `update:flying-tulip`.
15
+ */
16
+ export interface FlyingTulipConfigChain {
17
+ /** The one position book per chain — every deposit/borrow write target. */
18
+ positionsManager: string;
19
+ /** LendingLens — the whole public read surface (state, cfg, caps, prices). */
20
+ lendingLens: string;
21
+ /** ConfigRegistry (UNVERIFIED impl) — mmBps, caps, pauses, both HF gates. */
22
+ configRegistry: string;
23
+ /** AccountValuesLens — equity/maint/HF incl. `enginePnLUSDWad`. */
24
+ accountValuesLens: string;
25
+ /** OracleRouter behind the lens's `priceAndDecimals`. */
26
+ oracleRouter: string;
27
+ /** FT token — `collateral: false, mmBps: 0`, unpriceable on-protocol. */
28
+ ft: string;
29
+ /** ftUSD. */
30
+ ftUSD: string;
31
+ /** Registered engines (RFQ / meta-tx); informational for public data. */
32
+ engines?: {
33
+ [name: string]: string;
34
+ };
35
+ }
36
+ export type FlyingTulipConfigType = {
37
+ [lender: string]: {
38
+ [chainId: string]: FlyingTulipConfigChain;
39
+ };
40
+ };
41
+ /** One roster row: the log-discovered listing + a config snapshot. Values are
42
+ * a SNAPSHOT for display/fallback — fetchers read the live `assetCfg`. */
43
+ export interface FlyingTulipAssetRow {
44
+ address: string;
45
+ symbol: string;
46
+ name: string;
47
+ decimals: number;
48
+ irm: string;
49
+ mmBps: number;
50
+ enabled: boolean;
51
+ borrowable: boolean;
52
+ collateral: boolean;
53
+ supplyCap: string;
54
+ borrowCap: string;
55
+ depositPaused: boolean;
56
+ withdrawPaused: boolean;
57
+ borrowPaused: boolean;
58
+ /** false ⇒ the protocol oracle reverts for it (FT itself). NEVER batch an
59
+ * unpriceable asset into `pricesUSD` — the lens loops without a per-item
60
+ * catch, so one bad asset poisons the whole call. */
61
+ priceable: boolean;
62
+ }
63
+ export interface FlyingTulipAssetsChain {
64
+ /** Open gate: new borrows/withdrawals must leave HF ≥ this (1e4). */
65
+ marginHfSafeBps: number;
66
+ /** Liquidation trigger: HF < this (1e4) — 12500, NOT 10000. */
67
+ marginHfTargetBps: number;
68
+ /** Minimum account equity while any debt exists — PER CHAIN (wad). */
69
+ marginMinEquityUSDWad: string;
70
+ oracleRouter: string;
71
+ assets: FlyingTulipAssetRow[];
72
+ }
73
+ export type FlyingTulipAssetsType = {
74
+ [lender: string]: {
75
+ [chainId: string]: FlyingTulipAssetsChain;
76
+ };
77
+ };
78
+ export declare const flyingTulipConfig: () => FlyingTulipConfigType;
79
+ export declare const flyingTulipAssets: () => FlyingTulipAssetsType;
80
+ /** Deployment config for a Flying Tulip lender key on a chain. */
81
+ export declare const flyingTulipConfigFor: (lender: string, chainId: string | number) => FlyingTulipConfigChain | undefined;
82
+ /** Roster + margin knobs for a Flying Tulip lender key on a chain. */
83
+ export declare const flyingTulipAssetsFor: (lender: string, chainId: string | number) => FlyingTulipAssetsChain | undefined;
84
+ /**
85
+ * All Flying Tulip lender keys with a working deployment on a chain (drives
86
+ * `getLendersForChain`). Gated on BOTH published files: the lens address is
87
+ * what every read bootstraps from, and an empty roster means nothing to fetch
88
+ * — either absent must mean the lender is dark on that chain, never a key
89
+ * that fans out into zero-asset entries.
90
+ */
91
+ export declare const flyingTulipLendersByChain: (chainId: string | number) => string[];
@@ -24,6 +24,7 @@ export * from './gearbox';
24
24
  export * from './dolomite';
25
25
  export * from './initProtocol';
26
26
  export * from './lista';
27
+ export * from './flyingTulip';
27
28
  export * from './midnight';
28
29
  export * from './term';
29
30
  export * from './termMax';
@@ -11,6 +11,12 @@ export type MidnightConfigChain = {
11
11
  setterRatifier?: string | null;
12
12
  /** Midnight HTTP API base for book/quote/offer data (defaults to Morpho hosted). */
13
13
  apiBaseUrl?: string | null;
14
+ /**
15
+ * Tenor GraphQL endpoint — the PRIMARY rung of the source ladder for the
16
+ * roster and for offers; `apiBaseUrl` (Morpho's hosted Midnight API) is the
17
+ * fallback. Keyless and CORS-open. See TENOR_PLAN.md §0.6.
18
+ */
19
+ tenorApiUrl?: string | null;
14
20
  };
15
21
  export type MidnightConfigType = {
16
22
  [chainId: string]: MidnightConfigChain;
@@ -24,6 +30,33 @@ export type MidnightCollateralParam = {
24
30
  liquidationCursor: string;
25
31
  oracle: string;
26
32
  decimals: number;
33
+ /**
34
+ * When this leg is an ERC-4626 wrapper listed as collateral (the Tenor
35
+ * "vault-as-collateral" structure — a Vault-V2 allocating 100% to one Morpho
36
+ * Blue market, listed at ~98% LLTV alongside the real collateral), this is
37
+ * the vault's own address, i.e. `token`. Absent for a plain token leg.
38
+ *
39
+ * The point of carrying it explicitly rather than sniffing `asset()` is that
40
+ * routing INTO this leg is a different action (wrap the loan token into the
41
+ * vault, then supply the shares) and the row's risk story is different too —
42
+ * the collateral is itself a lending position. See TENOR_PLAN.md §P4.
43
+ */
44
+ collateralVault?: string | null;
45
+ };
46
+ /**
47
+ * Who may enter (take offers on) / liquidate a market. Midnight markets can pin
48
+ * an `enterGate` / `liquidatorGate` contract; zero address = permissionless.
49
+ *
50
+ * `'unknown'` is a REAL value and must not collapse into `'open'`: a gate
51
+ * contract we do not recognise is not an open market, and quoting it as one
52
+ * emits calldata that reverts. Callers gate on `enter !== 'open'`, never on the
53
+ * address being non-zero, so an unrecognised gate fails safe.
54
+ */
55
+ export type MidnightGating = {
56
+ enter: 'open' | 'allowlist' | 'unknown';
57
+ liquidator: 'open' | 'allowlist' | 'unknown';
58
+ enterGate: string;
59
+ liquidatorGate: string;
27
60
  };
28
61
  /** A Midnight market: full struct params needed to build calls + read state. */
29
62
  export type MidnightMarketConfig = {
@@ -56,6 +89,28 @@ export type MidnightMarketConfig = {
56
89
  continuousFee?: string;
57
90
  /** Optional display label, e.g. "USDC / WETH — 2026-09-18". */
58
91
  name?: string;
92
+ /**
93
+ * Midnight `market_family_id` — the ROLL SERIES this maturity belongs to.
94
+ * Every 4-week roll of "cbBTC/USDC" shares one family id, so this is what a
95
+ * renewal targets ("the September roll of that series"). Absent when the
96
+ * roster came from a source that does not publish it.
97
+ */
98
+ marketFamilyId?: string;
99
+ /** Tenor's own series id (`tenorMarkets.id`) — the curated grouping. */
100
+ tenorSeriesId?: string;
101
+ /** Morpho's own curation flag from the Midnight API's `listed`. */
102
+ listed?: boolean;
103
+ /**
104
+ * ENTRY IS CLOSED, the market is not dead. Set when Tenor has deprecated the
105
+ * market or its series: no new positions, but existing ones still accrue,
106
+ * repay, exit and liquidate — so the market MUST stay in the roster or every
107
+ * holder's position reads as nothing. (Deprecated series still held ~$239k of
108
+ * live positions when this was written.) Mirrors the offboarded-but-nonempty
109
+ * rule used for Sky ilks: drop only when it is both closed AND empty.
110
+ */
111
+ deprecatedAt?: string | null;
112
+ /** Enter/liquidator gating. Absent means "not resolved", not "open". */
113
+ gating?: MidnightGating;
59
114
  };
60
115
  export type MidnightMarketsType = {
61
116
  [chainId: string]: MidnightMarketConfig[];
@@ -65,8 +120,25 @@ export declare const setMidnightApiBase: (url: string | undefined | null) => voi
65
120
  export declare const midnightApiBaseOverride: () => string | undefined;
66
121
  /** Resolve the Midnight API base for a chain: override → config → hosted default. */
67
122
  export declare const resolveMidnightApiBase: (chainId: string) => string;
123
+ export declare const setTenorApiUrl: (url: string | undefined | null) => void;
124
+ export declare const tenorApiUrlOverride: () => string | undefined;
125
+ /** Resolve the Tenor GraphQL endpoint for a chain: override → config → hosted default. */
126
+ export declare const resolveTenorApiUrl: (chainId: string) => string;
68
127
  export declare const midnightMarkets: () => MidnightMarketsType;
69
128
  /** All Midnight market configs on a chain (empty array if none/unloaded). */
70
129
  export declare const midnightMarketsByChain: (chainId: string | number) => MidnightMarketConfig[];
71
130
  /** Look up one Midnight market config by its bytes32 id (case-insensitive). */
72
131
  export declare const midnightMarketById: (chainId: string | number, marketId: string) => MidnightMarketConfig | undefined;
132
+ /**
133
+ * May a NEW position be opened here? Fails safe in both directions:
134
+ * - `gating` absent → unresolved, not "open" → refuse.
135
+ * - `gating.enter !== 'open'` → allowlisted or unrecognised → refuse.
136
+ * - `deprecatedAt` in the past → entry closed by Tenor (the market itself
137
+ * stays serviceable: repay / withdraw / exit / liquidate are unaffected).
138
+ *
139
+ * Never gate a REDUCING action on this — a user in a gated or deprecated market
140
+ * must always be able to get out.
141
+ */
142
+ export declare const midnightMarketIsEnterable: (market: Pick<MidnightMarketConfig, "gating" | "deprecatedAt" | "maturity">, nowSec?: number) => boolean;
143
+ /** Human-readable reason a market refuses new positions, or `undefined` if it does not. */
144
+ export declare const midnightNotEnterableReason: (market: Pick<MidnightMarketConfig, "gating" | "deprecatedAt" | "maturity">, nowSec?: number) => string | undefined;
@@ -31,6 +31,7 @@ import type { UsddConfigType, UsddMarketsType } from './dss';
31
31
  import type { EulerConfigsType, EulerVaultsType } from './euler';
32
32
  import type { ExactlyConfigType, ExactlyMarketsType } from './exactly';
33
33
  import type { FluidResolversType, FluidVaultsType } from './fluid';
34
+ import type { FlyingTulipAssetsType, FlyingTulipConfigType } from './flyingTulip';
34
35
  import type { FrankencoinConfigType, FrankencoinMarketsType } from './frankencoin';
35
36
  import type { GearboxResolversType } from './gearbox';
36
37
  import type { InitConfigType } from './initProtocol';
@@ -89,6 +90,8 @@ export interface GlobalLenderDataRegistry {
89
90
  termMaxConfig: TermMaxConfigType;
90
91
  exactlyConfig: ExactlyConfigType;
91
92
  exactlyMarkets: ExactlyMarketsType;
93
+ flyingTulipConfig: FlyingTulipConfigType;
94
+ flyingTulipAssets: FlyingTulipAssetsType;
92
95
  tellerConfig: TellerConfigType;
93
96
  tellerPools: TellerPoolsType;
94
97
  liquityConfig: LiquityConfigType;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.0.51",
7
+ "version": "0.0.53",
8
8
  "description": "Hold and initialize lending protocol data across a stack",
9
9
  "files": [
10
10
  "dist"