@1delta/margin-fetcher 5.0.92 → 5.0.94

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
@@ -1,7 +1,7 @@
1
1
  import { parseAbi, keccak256, encodeAbiParameters, formatEther, BaseError, erc20Abi, isAddress, stringToHex, pad, encodeFunctionData, decodeFunctionResult, decodeAbiParameters, formatUnits, getAddress, toBytes, slice, concat, AbiEncodingLengthMismatchError, concatHex, parseAbiParameters, hexToString, InvalidAddressError, boolToHex, integerRegex, numberToHex, bytesRegex, BytesSizeMismatchError, arrayRegex, UnsupportedPackedAbiType } from './chunk-JUYF2XLF.js';
2
2
  import './chunk-BYTNVMX7.js';
3
3
  import './chunk-PR4QN5HX.js';
4
- import { Lender, isExactly, isMidnight, isTerm, isTermMax, isTeller, isListaDao, isLiquityFamily, isRiver, isInverse, isCooler, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, isFlyingTulip, isTwyne, isFraxlend, isAaveV4Type, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isCompoundV2Type, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, isMorphoType, isUsdd, isSky, hasCrossMarginRisk, isEulerType, isInit, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isMorphoBlue, isAaveV2Type, isAaveV32Type, isAaveV3Type, isYLDR, isLista, hasSubAccounts, isTectonicType, isKineticType, isBenqiType } from '@1delta/lender-registry';
4
+ import { Lender, isExactly, isMidnight, isTerm, isTermMax, isTeller, isListaDao, isLiquityFamily, isRiver, isInverse, isCooler, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, isFlyingTulip, isTwyne, isFraxlend, isAaveV4Type, isKamino, isJupiterLend, isSave, isLoopscale, isProject0, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isCompoundV2Type, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, isMorphoType, isUsdd, isSky, hasCrossMarginRisk, isEulerType, isInit, isVenusType, normalizeLenderKey, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isMorphoBlue, kaminoMarketFromKey, jupiterLendVaultFromKey, saveMarketFromKey, loopscaleMarketFromKey, project0GroupFromKey, isAaveV2Type, isAaveV32Type, isAaveV3Type, isYLDR, isLista, hasSubAccounts, isTectonicType, isKineticType, isBenqiType } from '@1delta/lender-registry';
5
5
  export { hasCrossMarginRisk, isAaveType, isAaveV2Type, isAaveV32Type, isAaveV3Type, isCompoundV3, isCompoundV3Type, isInit, isMorphoType, isMultiMarket, isYLDR } from '@1delta/lender-registry';
6
6
  import { fetchTokenLists, fetchTokenList, aavePools, compoundV3Pools, initConfig, morphoPools, compoundV2Pools, eulerVaults, siloMarkets, siloV2LenderKey, siloMarketsV3, siloV3LenderKey, aaveV4Spokes, aaveV4SpokeLenderKey, fluidResolvers, gearboxResolvers, dolomiteConfigs, midnightConfig, termConfig, termMarketsByChain, exactlyConfig, flyingTulipLendersByChain, liquityLendersByChain, riverLendersByChain, inverseLendersByChain, coolerLendersByChain, llamaLendLendersByChain, usddLendersByChain, skyLendersByChain, frankencoinLendersByChain, resupplyLendersByChain, curvanceLendersByChain, fraxlendLendersByChain, twyneLendersByChain, tellerConfigByChain, tellerPoolsByChain, termMaxConfigByChain, aaveReserves, compoundV3Reserves, dolomiteIsolationMarket, morphoTypeMarkets, resolveTermApiBase, flyingTulipConfigFor, flyingTulipAssetsFor, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, termMaxApiBaseUrl, termMaxLenderKey, inverseConfigFor, inverseChainData, coolerConfigFor, llamaLendConfigFor, llamaLendChainData, llamaLendApiBaseUrl, resupplyConfigFor, fraxlendConfigFor, dssConfigFor, dssChainData, dssDebtToken, dssDebtJoin, frankencoinConfigFor, frankencoinChainData, aaveTokens, compoundV3BaseData, compoundV2TokenArray, morphoTypeVaults, eulerConfigs, fluidVaultEntries, gearboxMarketConfigurators, dolomiteIsolation, liquityMarkets, riverMarkets, tellerConfig, tellerPools, termMarkets, termMaxConfig, midnightMarkets, midnightCollateralRef, llamaLendMarkets, fraxlendPairsFor, inverseMarkets, curvanceConfig, frankencoinMarkets, twyneMarkets, twyneConfigFor, exactlyMarkets, aaveOracles, resolveMidnightApiBase, llamaLendMarketByVault, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, curvanceConfigFor, listaCollateralProvider, gearboxMarketCompressor, gearboxV3LenderKey, midnightMarketsByChain, twyneChainData, parseAaveV4SpokeLenderKey, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2OraclesConfig, compoundV3OraclesData, compoundV2Reserves, aaveV4Oracles, morphoTypeOracles } from '@1delta/data-sdk';
7
7
  import lodash from 'lodash';
@@ -12,7 +12,7 @@ export { MorphoLensAbi } from '@1delta/abis';
12
12
  import { prepareDebitDataMulticall, prepareLenderDebitMulticall, parseDebitDataResult, parseLenderDebitResult, getPermit2ContractAddress, getLstAcceptedInputs, savingsVerbRequires, savingsSupportsVerb, getCompoundV2Comptroller as getCompoundV2Comptroller$1, getCompoundV3CometAddress as getCompoundV3CometAddress$1, getMorphoAddress, FLUID_VAULT_FACTORY, getAaveStyleLenderTokenAddress, LendingMode, getAaveCollateralTokenAddress, getSiloHalfForUnderlying, findSavingsWithdrawEntry, bandLtvCurve, InitMarginAddresses, ignoresReceiver, buildLstWithdrawRequest, SAVINGS_RECEIVER_CAPABILITY } from '@1delta/calldata-sdk';
13
13
  import { proxyNativeFetch } from '@1delta/proxy-fetch';
14
14
  import { BALANCER_V2_FORKS, BALANCER_V3_FORKS, UNISWAP_V4_FORKS, isFlashLoanSourceExcluded, FLASH_LOAN_IDS } from '@1delta/dex-registry';
15
- import { getNativeDecimals } from '@1delta/wnative';
15
+ import { getNativeDecimals, getWrappedNativeAddressSafe, isNativeWrapOneToOne } from '@1delta/wnative';
16
16
 
17
17
  // src/abis/aave-v2/ProtocolDataProvider.ts
18
18
  var ProtocolDataProviderAbi = [
@@ -7436,6 +7436,7 @@ var getAaveV3ReservesDataConverter = (lender, chainId, prices, additionalYields,
7436
7436
  const asset = assetsToQuery[i];
7437
7437
  const reserveData = data[i * stride];
7438
7438
  const configData = data[i * stride + 1];
7439
+ const siloedBorrowing = data[i * stride + 2] === true;
7439
7440
  const reserveCaps = data[i * stride + 3];
7440
7441
  const debtCeiling = data[i * stride + 4];
7441
7442
  const reserveEMode = data[i * stride + 5];
@@ -7542,6 +7543,7 @@ var getAaveV3ReservesDataConverter = (lender, chainId, prices, additionalYields,
7542
7543
  collateralActive: usageAsCollateralEnabled,
7543
7544
  borrowingEnabled,
7544
7545
  depositsEnabled: true,
7546
+ ...siloedBorrowing ? { siloedBorrowing: true } : {},
7545
7547
  hasStable: configData?.[7 /* stableBorrowRateEnabled */],
7546
7548
  isActive: configData?.[8 /* isActive */],
7547
7549
  isFrozen: configData?.[9 /* isFrozen */],
@@ -7875,6 +7877,7 @@ function parseAave32(chainId, lender, prices, additionalYields, tokenList) {
7875
7877
  const asset = assetsToQuery[i];
7876
7878
  const reserveData = data[i * stride];
7877
7879
  const configData = data[i * stride + 1];
7880
+ const siloedBorrowing = data[i * stride + 2] === true;
7878
7881
  const reserveCaps = data[i * stride + 3];
7879
7882
  const debtCeiling = data[i * stride + 4];
7880
7883
  const aTokenBalanceRaw = data[i * stride + 5];
@@ -7981,6 +7984,7 @@ function parseAave32(chainId, lender, prices, additionalYields, tokenList) {
7981
7984
  collateralActive: usageAsCollateralEnabled,
7982
7985
  borrowingEnabled,
7983
7986
  depositsEnabled: true,
7987
+ ...siloedBorrowing ? { siloedBorrowing: true } : {},
7984
7988
  hasStable: configData?.[7 /* stableBorrowRateEnabled */],
7985
7989
  isActive: configData?.[8 /* isActive */],
7986
7990
  isFrozen: configData?.[9 /* isFrozen */],
@@ -12043,6 +12047,9 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12043
12047
  let collateral = 0;
12044
12048
  let borrowDiscountedCollateral = 0;
12045
12049
  let adjustedDebt = 0;
12050
+ let liquidationAdjustedDebt = 0;
12051
+ let hasLiquidationWeights = false;
12052
+ let collateralDebtCapacity = Infinity;
12046
12053
  for (let i = 0; i < marketUids2.length; i++) {
12047
12054
  const marketUid = marketUids2[i];
12048
12055
  if (!lenderData?.[marketUid] || !payload.lendingPositions[posId][marketUid])
@@ -12070,6 +12077,13 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12070
12077
  collateral += (config?.collateralFactor ?? 1) * depositsUSDOracle;
12071
12078
  borrowDiscountedCollateral += (config?.borrowCollateralFactor ?? 1) * depositsUSDOracle;
12072
12079
  adjustedDebt += (config?.borrowFactor ?? 1) * debtUSDOracle;
12080
+ if (config?.liquidationBorrowFactor != null) hasLiquidationWeights = true;
12081
+ liquidationAdjustedDebt += (config?.liquidationBorrowFactor ?? config?.borrowFactor ?? 1) * debtUSDOracle;
12082
+ if (config?.collateralDebtCapacity != null && Number(pos.deposits) > 0 && !config.collateralDisabled)
12083
+ collateralDebtCapacity = Math.min(
12084
+ collateralDebtCapacity,
12085
+ config.collateralDebtCapacity
12086
+ );
12073
12087
  depositInterest += depositRate * depositsUSD;
12074
12088
  borrowInterest += debtUSD * variableBorrowRate;
12075
12089
  }
@@ -12082,6 +12096,7 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12082
12096
  deposits,
12083
12097
  debt,
12084
12098
  adjustedDebt,
12099
+ ...hasLiquidationWeights ? { liquidationAdjustedDebt } : {},
12085
12100
  nav,
12086
12101
  deposits24h: histData[posId]?.totalDeposits24h,
12087
12102
  debt24h: histData[posId]?.totalDebt24h,
@@ -12139,6 +12154,11 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12139
12154
  if (borrowLiquidity != null) {
12140
12155
  borrowable = String(Math.min(Number(borrowable), borrowLiquidity));
12141
12156
  }
12157
+ borrowable = capByModeDebtCapacity(
12158
+ borrowable,
12159
+ config?.debtCapacity,
12160
+ collateralDebtCapacity
12161
+ );
12142
12162
  pos.withdrawable = withdrawable;
12143
12163
  pos.borrowable = borrowable;
12144
12164
  pos.underlyingInfo = buildUnderlyingInfo(
@@ -12149,6 +12169,11 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12149
12169
  if (borrowLiquidity != null) {
12150
12170
  borrowable = String(Math.min(Number(borrowable), borrowLiquidity));
12151
12171
  }
12172
+ borrowable = capByModeDebtCapacity(
12173
+ borrowable,
12174
+ config?.debtCapacity,
12175
+ collateralDebtCapacity
12176
+ );
12152
12177
  payload.lendingPositions[posId][marketUid] = {
12153
12178
  marketUid,
12154
12179
  deposits: "0",
@@ -12167,6 +12192,9 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12167
12192
  accountId: posId,
12168
12193
  ...accountAddresses?.[posId] ? { accountAddress: accountAddresses[posId] } : {},
12169
12194
  health: balanceData2.debt === 0 ? null : balanceData2.adjustedDebt > 0 ? balanceData2.borrowDiscountedCollateral / balanceData2.adjustedDebt : balanceData2.collateral / balanceData2.debt,
12195
+ ...hasLiquidationWeights ? {
12196
+ liquidationHealth: balanceData2.debt === 0 ? null : balanceData2.collateral / liquidationAdjustedDebt
12197
+ } : {},
12170
12198
  borrowCapacityUSD: creditLine,
12171
12199
  userConfig,
12172
12200
  // aggregated balance data
@@ -12183,6 +12211,13 @@ function createMultiAccountTypeUserState(payload, lenderData, histData, accountA
12183
12211
  data
12184
12212
  };
12185
12213
  }
12214
+ function capByModeDebtCapacity(borrowable, debtCapacity, collateralDebtCapacity) {
12215
+ let cap = Infinity;
12216
+ if (debtCapacity != null) cap = Math.min(cap, Math.max(0, debtCapacity));
12217
+ if (Number.isFinite(collateralDebtCapacity))
12218
+ cap = Math.min(cap, Math.max(0, collateralDebtCapacity));
12219
+ return Number.isFinite(cap) ? String(Math.min(Number(borrowable), cap)) : borrowable;
12220
+ }
12186
12221
 
12187
12222
  // src/lending/user-data/utils/readContext.ts
12188
12223
  var blockNumberFromTag = (blockTag) => {
@@ -44152,15 +44187,19 @@ function fuseLenderData(userDataResult, summary) {
44152
44187
  );
44153
44188
  return entries;
44154
44189
  }
44155
-
44156
- // src/lending/user-data/read/select.ts
44157
44190
  var PREFIX_LENDERS = /* @__PURE__ */ new Set([
44158
44191
  "MORPHO_BLUE",
44159
44192
  "LISTA_DAO",
44160
44193
  "COMPOUND_V3",
44161
- "CURVANCE"
44194
+ "CURVANCE",
44195
+ // Solana families — every one fans out to per-market keys
44196
+ "KAMINO",
44197
+ "JUPITER_LEND",
44198
+ "SAVE",
44199
+ "LOOPSCALE",
44200
+ "PROJECT_0"
44162
44201
  ]);
44163
- var parseLenderKey = (raw) => raw.trim().toUpperCase().replaceAll("-", "_");
44202
+ var parseLenderKey = (raw) => normalizeLenderKey(raw);
44164
44203
  function filterLenderMeta(meta, filter) {
44165
44204
  const lenders = filter?.lenders;
44166
44205
  if (!lenders?.length) return meta;
@@ -63491,15 +63530,20 @@ function parseVault3(entry, results, chainId, prices, tokenList, marketIds, rate
63491
63530
  // src/vaults/morpho/rateSanity.ts
63492
63531
  var IMPLAUSIBLE_APR_PERCENT = 100;
63493
63532
  var PINNED_LIQUIDITY_FRACTION = 1e-3;
63533
+ var DEAD_LIQUIDITY_FRACTION = 1e-6;
63534
+ var DEAD_APR_PERCENT = 25;
63494
63535
  var isUnrealizableRate = (v) => isPinnedMarketRate({
63495
63536
  aprPercent: v.depositRate,
63496
63537
  totalAssets: v.totalAssetsFormatted,
63497
63538
  liquidity: v.liquidityFormatted
63498
63539
  });
63499
63540
  var isPinnedMarketRate = (args) => {
63500
- if (!(args.aprPercent > IMPLAUSIBLE_APR_PERCENT)) return false;
63501
63541
  if (!(args.totalAssets > 0)) return false;
63502
- return args.liquidity / args.totalAssets < PINNED_LIQUIDITY_FRACTION;
63542
+ const withdrawableShare = args.liquidity / args.totalAssets;
63543
+ if (args.aprPercent > IMPLAUSIBLE_APR_PERCENT && withdrawableShare < PINNED_LIQUIDITY_FRACTION) {
63544
+ return true;
63545
+ }
63546
+ return args.aprPercent > DEAD_APR_PERCENT && withdrawableShare < DEAD_LIQUIDITY_FRACTION;
63503
63547
  };
63504
63548
  var dropUnrealizableRates = (vaults) => {
63505
63549
  const entries = Object.entries(vaults);
@@ -74592,7 +74636,7 @@ var fetchGmxVaults = async (chainId, multicallRetry, options) => {
74592
74636
  const symbolOf = /* @__PURE__ */ new Map();
74593
74637
  for (const t of tokens) symbolOf.set(t.address.toLowerCase(), t.symbol);
74594
74638
  const out = {};
74595
- const build = (address, name, kind, longToken, shortToken, indexToken, entry) => {
74639
+ const build6 = (address, name, kind, longToken, shortToken, indexToken, entry) => {
74596
74640
  const longSymbol = symbolOf.get(longToken.toLowerCase());
74597
74641
  const shortSymbol = symbolOf.get(shortToken.toLowerCase());
74598
74642
  return {
@@ -74616,7 +74660,7 @@ var fetchGmxVaults = async (chainId, multicallRetry, options) => {
74616
74660
  for (const m of markets) {
74617
74661
  if (!m.isListed) continue;
74618
74662
  const key3 = m.marketToken.toLowerCase();
74619
- out[key3] = build(
74663
+ out[key3] = build6(
74620
74664
  m.marketToken,
74621
74665
  m.name,
74622
74666
  "gm",
@@ -74629,7 +74673,7 @@ var fetchGmxVaults = async (chainId, multicallRetry, options) => {
74629
74673
  for (const g of glvs) {
74630
74674
  if (!g.isListed) continue;
74631
74675
  const key3 = g.glvToken.toLowerCase();
74632
- out[key3] = build(
74676
+ out[key3] = build6(
74633
74677
  g.glvToken,
74634
74678
  g.name,
74635
74679
  "glv",
@@ -74984,10 +75028,10 @@ async function getJson4(url, label) {
74984
75028
  }
74985
75029
  return response.json();
74986
75030
  }
74987
- function cache4(slot, build, store) {
75031
+ function cache4(slot, build6, store) {
74988
75032
  const now = Date.now();
74989
75033
  if (slot && now - slot.at < CACHE_TTL_MS6) return slot.promise;
74990
- const promise = build();
75034
+ const promise = build6();
74991
75035
  const entry = { at: now, promise };
74992
75036
  store(entry);
74993
75037
  promise.catch(() => store(void 0));
@@ -75528,6 +75572,7 @@ var computeVaultApr = (points, options) => {
75528
75572
  };
75529
75573
 
75530
75574
  // src/vaults/lookup.ts
75575
+ var NON_EVM_VAULT_PROVIDERS = /* @__PURE__ */ new Set(["hypercore"]);
75531
75576
  function buildVaultLookup(data) {
75532
75577
  const map = /* @__PURE__ */ new Map();
75533
75578
  const addEntries = (bag, provider) => {
@@ -76519,6 +76564,134 @@ var TERM_PROFILES = [
76519
76564
  },
76520
76565
  docsUrl: "https://docs.morpho.org/morpho/concepts/markets"
76521
76566
  }),
76567
+ // ── Solana lenders ───────────────────────────────────────────────────────
76568
+ // Ported from margin-fetcher-sol's profiles; the facts behind each line are
76569
+ // verified against the deployed programs in UNIFIED_API_AUDIT.md §9.
76570
+ // Kamino is a crossing of Morpho and Aave V3: a market is PERMISSIONLESSLY
76571
+ // deployed and typically lends one asset against a set of collaterals (the
76572
+ // Morpho half), while inside the market a multi-asset pool with elevation
76573
+ // groups prices the pairs (the Aave half).
76574
+ P({
76575
+ id: "kamino.klend@v1",
76576
+ name: "Kamino Lend market (variable-rate pool)",
76577
+ family: "kamino",
76578
+ docsUrl: "https://docs.kamino.finance/",
76579
+ supply: {
76580
+ description: "A shared liquidity pool inside one Kamino lending market. Markets are deployed permissionlessly and run by their owner \u2014 Kamino for the primary market, a third-party curator for the others \u2014 who sets every reserve's parameters. Deposits earn interest paid by borrowers, at a rate that moves with utilization, minus the protocol take rate. Withdrawals are instant up to the cash left in the pool, and a reserve can additionally rate-limit them with a rolling net-withdrawal cap.",
76581
+ implications: [
76582
+ "Your yield is not fixed \u2014 it rises and falls with borrowing demand.",
76583
+ "If utilization reaches 100 %, withdrawals are blocked until borrowers repay or new deposits arrive.",
76584
+ "A reserve may rate-limit withdrawals with a rolling net-withdrawal cap.",
76585
+ "Your deposit is exposed to every collateral asset THIS market accepts, not just one \u2014 and the market owner, not Kamino, decides what that set is."
76586
+ ]
76587
+ },
76588
+ borrow: {
76589
+ description: "Borrow the market's loan asset against the collaterals it accepts, at a rate that moves with utilization. Most markets lend one asset; the primary market lends many. The debt accrues continuously and can be repaid at any time. Positions are obligations \u2014 a wallet can hold several per market, each with its own health. Elevation groups raise the LTV for specific collateral/debt pairs, and an obligation sits in at most one group.",
76590
+ implications: [
76591
+ "The rate can change slot to slot \u2014 a cheap borrow can become expensive.",
76592
+ "If the collateral value falls past the liquidation threshold, a liquidator repays part of your debt (a close factor per call) and takes collateral plus a bonus that scales with how far past the threshold you are; a deeply unhealthy or very small position is liquidated whole.",
76593
+ "Inside an elevation group only the group\u2019s debt asset can be borrowed, every deposit must be one of the group\u2019s collaterals, and the number of collaterals is capped.",
76594
+ "Some reserves count as collateral ONLY inside an elevation group: holding one in an obligation outside every group disables all new borrowing on that obligation.",
76595
+ "Markets with auto-deleverage enabled can lower the liquidation threshold over time and unwind positions without a price move.",
76596
+ "Parameters are set by the market owner and can change without a protocol-wide vote."
76597
+ ]
76598
+ }
76599
+ }),
76600
+ P({
76601
+ id: "jupiter-lend.vault@v1",
76602
+ name: "Jupiter Lend vault (Fluid T1 on Solana)",
76603
+ family: "jupiter-lend",
76604
+ docsUrl: "https://developers.jup.ag/docs/lend",
76605
+ supply: {
76606
+ description: "Collateral posted to a Jupiter Lend vault sits on the shared Liquidity Layer, where every vault and earn token that touches the same asset draws from one pool. Collateral earns the layer's supply rate only when that asset is also lent out (SOL does; JLP, JupSOL and the LST collaterals do not). Withdrawals are bounded by a per-position limit that expands over six hours.",
76607
+ implications: [
76608
+ "A withdrawal larger than the current limit cannot clear in one transaction \u2014 the limit grows toward the position over ~6 hours.",
76609
+ "Your collateral shares one liquidity pool with every other vault and earn token on that asset."
76610
+ ]
76611
+ },
76612
+ borrow: {
76613
+ description: "Borrow one asset against one collateral at a rate set per ASSET at the Liquidity Layer, plus a per-vault additive offset (the magnifier, in bps \u2014 e.g. vault 101 pays the layer rate minus 2 %), so two vaults lending the same asset can charge different rates. Debt accrues continuously and can be repaid at any time. Positions are NFTs, one collateral/debt pair each.",
76614
+ implications: [
76615
+ "The rate moves with the layer's utilization of the borrowed asset, block to block.",
76616
+ "Past the liquidation threshold a liquidator repays part of the debt and takes collateral plus a penalty; past the max liquidation limit the position is liquidated ENTIRELY.",
76617
+ "Borrowing is capped by an expanding per-vault ceiling on the layer, so a large borrow may need to wait for the ceiling to grow."
76618
+ ]
76619
+ }
76620
+ }),
76621
+ P({
76622
+ id: "save.pool@v1",
76623
+ name: "Save (ex-Solend) lending pool",
76624
+ family: "save",
76625
+ docsUrl: "https://docs.save.finance/",
76626
+ supply: {
76627
+ description: "A shared liquidity pool inside one Save lending market \u2014 the Main pool is run by Save's own key; other pools are deployed permissionlessly by third parties who set every parameter. Deposits mint cTokens that appreciate as borrowers pay interest, at a rate that moves with utilization along a three-legged curve, minus a protocol take rate. Withdrawals are instant up to the cash left in the reserve and the market's outflow limit.",
76628
+ implications: [
76629
+ "Your yield is not fixed \u2014 it moves with borrowing demand, slot to slot.",
76630
+ "If the reserve is fully lent out, withdrawals wait for repayments or new deposits; permissionless pools have been left pinned there permanently.",
76631
+ "A market-wide outflow limiter can cap how much leaves the whole pool in a rolling window.",
76632
+ "Bad debt in the market is socialised to its depositors; the pool owner decides which collaterals the pool accepts."
76633
+ ]
76634
+ },
76635
+ borrow: {
76636
+ description: "Borrow any borrowable reserve against the collaterals the market accepts, at a variable rate accrued every slot. Liquid-staked SOL collateral can be valued off the SOL price times an owner-set ratio rather than an LST oracle. Debt accrues continuously and can be repaid at any time; one obligation holds up to six positions.",
76637
+ implications: [
76638
+ "The rate can change every slot, and is quoted on a slot-year \u2014 the wall-clock rate runs about a quarter higher than the curve.",
76639
+ "Past the liquidation threshold a liquidator repays at most 20 % of your debt per call (and at most $500k at once) and takes collateral plus a bonus that scales with how far past the threshold you are, plus a protocol fee; a borrow worth $1 or less is liquidated whole.",
76640
+ "Isolated reserves can only be borrowed on their own: an obligation that borrows one may hold no other borrow, and they never count as collateral.",
76641
+ "A borrow or withdrawal needs fresh oracle prices for EVERY asset in the obligation; a stale long-tail feed blocks the whole account until a price is posted.",
76642
+ "Parameters are set by the market owner and can change without a protocol-wide vote."
76643
+ ]
76644
+ }
76645
+ }),
76646
+ P({
76647
+ id: "loopscale.creditbook@v1",
76648
+ name: "Loopscale credit order book (fixed-rate, fixed-duration)",
76649
+ family: "loopscale",
76650
+ docsUrl: "https://docs.loopscale.com/",
76651
+ supply: {
76652
+ description: "A fixed-rate loan filled from an order book of resting lender offers rather than a pool \u2014 Morpho Midnight's product on Solana. A lender rests a rate per collateral and per duration (1 day, 1 week, 1 month, 3 months); a borrower fills the best one and a repayment ledger is opened against escrowed collateral. Passive lenders deposit into a curated vault that rests the offers for them.",
76653
+ implications: [
76654
+ "Your rate is fixed for the term \u2014 it does not move with utilization, because there is no pool.",
76655
+ "Before maturity your claim can only leave by selling the ledger to another lender at a negotiated price; there may be no buyer.",
76656
+ "A curated vault charges a fee on the interest it earns for you, and can park idle deposits in a third-party pool.",
76657
+ "Vault curators choose the accepted collateral and its LTV (behind a 24-hour timelock) and set rates and fees immediately."
76658
+ ]
76659
+ },
76660
+ borrow: {
76661
+ description: "Borrow one asset against one collateral at a rate fixed for the chosen duration. At maturity a healthy loan is refinanced into a new 1-day term from any matching offer; if none matches, a 48-hour grace period runs at the same rate and then the loan may be partially liquidated. Repay at any time with interest to date; a loan can hold up to five collaterals and five ledgers.",
76662
+ implications: [
76663
+ "Health counts the interest owed at MATURITY as debt, so a longer term is riskier on day one than the same principal for a day.",
76664
+ "Liquidation is partial first \u2014 the minimum collateral to restore the max LTV \u2014 and the fee is how far past the liquidation LTV the loan was, not a flat bonus.",
76665
+ "The LTV and liquidation threshold are the OFFER's, pinned into your ledger at origination; a better or worse offer next to it has different ones.",
76666
+ "Auto-refinance is a best effort: if no lender rests an offer at maturity, the grace period is your only cover before liquidation."
76667
+ ]
76668
+ }
76669
+ }),
76670
+ P({
76671
+ id: "project0.group@v1",
76672
+ name: "Project 0 (marginfi v2) lending group",
76673
+ family: "project0",
76674
+ docsUrl: "https://docs.0.xyz/",
76675
+ supply: {
76676
+ description: "A shared pool per asset (a 'bank') inside one cross-margined group run by the Project 0 foundation \u2014 the marginfi v2 program, rebranded. Deposits earn the bank's lending rate, which moves with utilization along a multi-point curve and is settled into the deposit's share value whenever the bank is touched. Some banks are wrappers: they hold a Kamino, Drift or Jupiter Lend position, or a validator's native stake, and earn THAT venue's yield rather than an interest rate here.",
76677
+ implications: [
76678
+ "Your yield is not fixed \u2014 it moves with borrowing demand, and accrues as simple interest between touches of the bank.",
76679
+ "Withdrawals are instant up to the cash left in the bank, and can be capped by a per-bank hourly and daily outflow limit shared with borrows.",
76680
+ "On a wrapped bank you hold shares of another venue; its risks, rates and exits apply on top.",
76681
+ "Bad debt in the group is socialised to depositors of the affected bank after the insurance fund; banks can be paused, set reduce-only or killed by the group admins."
76682
+ ]
76683
+ },
76684
+ borrow: {
76685
+ description: "Borrow any borrowable bank against every collateral bank the account holds, cross-margined across up to 16 balances per account. Collateral is valued at an initial weight to open a borrow and a higher maintenance weight for liquidation; debt is inflated by a liability weight, which is higher for opening than for liquidation. When everything the account borrows is in the same e-mode class as its collateral (stables against stables, SOL against liquid staking tokens), the collateral counts at a lifted weight.",
76686
+ implications: [
76687
+ "The rate can change at any touch of the bank and is quoted on a 365-day year, simple interest.",
76688
+ "Past the maintenance threshold a liquidator repays debt and takes collateral plus a premium set on the debt bank \u2014 2.5 % to the liquidator and 2.5 % to the insurance fund by default \u2014 only as far as restoring health to zero.",
76689
+ "Borrowing another asset can switch e-mode off and drop your collateral weights at once; check what the new borrow does to the whole account.",
76690
+ "A reduce-only bank takes no new deposits or borrows, and \u2014 unless it is the variant that keeps borrowing power \u2014 its collateral stops counting toward a NEW borrow; a paused bank blocks withdrawals, repayments and liquidations too.",
76691
+ "Isolated-tier assets can be borrowed only on their own and never count as collateral; parameters are set by the foundation and its delegate admins without a protocol-wide vote."
76692
+ ]
76693
+ }
76694
+ }),
76522
76695
  // ── Vaults ───────────────────────────────────────────────────────────────
76523
76696
  P({
76524
76697
  id: "vault.lending@v1",
@@ -76698,6 +76871,7 @@ function resolveVaultProfileId(provider, solvency) {
76698
76871
 
76699
76872
  // src/terms/types.ts
76700
76873
  var TERM_SHEET_SCHEMA_VERSION = 1;
76874
+ var termAddressKey = (chainId, address) => chainId === void 0 || isEvmChainId(String(chainId)) ? address.toLowerCase() : address;
76701
76875
 
76702
76876
  // src/terms/buildTermSheet.ts
76703
76877
  var isNum = (v) => typeof v === "number" && Number.isFinite(v);
@@ -76705,7 +76879,10 @@ var clamp013 = (v) => Math.max(0, Math.min(1, v));
76705
76879
  function assetRef(input, now) {
76706
76880
  const a = input.asset ?? {};
76707
76881
  const chainId = String(a.chainId ?? input.chainId);
76708
- const address = String(a.address ?? input.underlying ?? "").toLowerCase();
76882
+ const address = termAddressKey(
76883
+ chainId,
76884
+ String(a.address ?? input.underlying ?? "")
76885
+ );
76709
76886
  return {
76710
76887
  chainId,
76711
76888
  address,
@@ -76734,7 +76911,10 @@ function instrumentOf(props, chainId, address, now) {
76734
76911
  const bridged = typeof pendle.bridgedFrom === "string" && pendle.bridgedFrom;
76735
76912
  const origin = pendle.origin && typeof pendle.origin.chainId === "string" && typeof pendle.origin.address === "string" ? {
76736
76913
  chainId: String(pendle.origin.chainId),
76737
- address: String(pendle.origin.address).toLowerCase()
76914
+ address: termAddressKey(
76915
+ String(pendle.origin.chainId),
76916
+ String(pendle.origin.address)
76917
+ )
76738
76918
  } : void 0;
76739
76919
  const originChain = origin?.chainId ?? (bridged ? PENDLE_ORIGIN_CHAIN_BY_CODE[bridged] : void 0);
76740
76920
  return {
@@ -76796,7 +76976,10 @@ function rewardTerms(input, side) {
76796
76976
  if (!apr) continue;
76797
76977
  const isPoints = r.kind === "points" || !r.asset;
76798
76978
  out.push({
76799
- asset: r.asset ? { chainId: input.chainId, address: String(r.asset).toLowerCase() } : void 0,
76979
+ asset: r.asset ? {
76980
+ chainId: input.chainId,
76981
+ address: termAddressKey(input.chainId, String(r.asset))
76982
+ } : void 0,
76800
76983
  kind: isPoints ? "points" : "token",
76801
76984
  apr,
76802
76985
  side,
@@ -77278,6 +77461,26 @@ function buildCoverage(sheet) {
77278
77461
  pending: Object.keys(pending).length ? pending : void 0
77279
77462
  };
77280
77463
  }
77464
+ function mergeAdapterCoverage(base, patch) {
77465
+ if (!patch) return base;
77466
+ const present = new Set(base.present);
77467
+ const pending = { ...base.pending ?? {} };
77468
+ const notApplicable = {
77469
+ ...base.notApplicable ?? {}
77470
+ };
77471
+ for (const [k, v] of Object.entries(patch.pending ?? {}))
77472
+ if (typeof v === "string" && !present.has(k)) pending[k] = v;
77473
+ for (const [k, v] of Object.entries(patch.notApplicable ?? {}))
77474
+ if (typeof v === "string" && !present.has(k)) {
77475
+ notApplicable[k] = v;
77476
+ delete pending[k];
77477
+ }
77478
+ return {
77479
+ present: base.present,
77480
+ notApplicable: Object.keys(notApplicable).length ? notApplicable : void 0,
77481
+ pending: Object.keys(pending).length ? pending : void 0
77482
+ };
77483
+ }
77281
77484
  function buildTermSheet(input, opts = {}) {
77282
77485
  const now = opts.now ?? Math.floor(Date.now() / 1e3);
77283
77486
  const siblings = opts.siblings ?? [];
@@ -77304,7 +77507,10 @@ function buildTermSheet(input, opts = {}) {
77304
77507
  if (merged[side] && !base[side]) merged[side] = void 0;
77305
77508
  }
77306
77509
  const withInfo = finalizeInfo(merged);
77307
- withInfo.coverage = buildCoverage(withInfo);
77510
+ withInfo.coverage = mergeAdapterCoverage(
77511
+ buildCoverage(withInfo),
77512
+ opts.patch?.coverage
77513
+ );
77308
77514
  return withInfo;
77309
77515
  }
77310
77516
 
@@ -78058,8 +78264,6 @@ var FALLBACK_TRAITS = {
78058
78264
  hasDecomposableBacking: false,
78059
78265
  hasUtilization: false
78060
78266
  };
78061
-
78062
- // src/earn/uid.ts
78063
78267
  var VAULT_VENUE_PREFIX = "vault.";
78064
78268
  function isVaultVenue(uidOrVenue) {
78065
78269
  return uidOrVenue.startsWith(VAULT_VENUE_PREFIX);
@@ -78073,7 +78277,7 @@ function buildVaultEarnUid(provider, chainId, address) {
78073
78277
  `Invalid earnUid parameters: provider=${provider}, chainId=${chainId}, address=${address}`
78074
78278
  );
78075
78279
  }
78076
- return `${vaultVenue(provider)}:${chainId}:${address.toLowerCase()}`;
78280
+ return `${vaultVenue(provider)}:${chainId}:${refKey(chainId, address)}`;
78077
78281
  }
78078
78282
  function earnUidFromMarketUid(marketUid) {
78079
78283
  const parts = splitUid(marketUid);
@@ -78102,9 +78306,10 @@ function parseEarnUid(earnUid, knownProviders) {
78102
78306
  kind: "lending",
78103
78307
  venue,
78104
78308
  chainId,
78105
- // Lower-cased to match `normalizeMarketUid` / `createMarketUid`, which
78106
- // both lowercase the ref segment. Harmless for Dolomite's integer id.
78107
- ref: ref.toLowerCase(),
78309
+ // Canonicalized like `normalizeMarketUid` / `createMarketUid`: lower-cased
78310
+ // on EVM (harmless for Dolomite's integer id), VERBATIM elsewhere — a
78311
+ // base58 ref is case-significant.
78312
+ ref: refKey(chainId, ref),
78108
78313
  marketUid: earnUid
78109
78314
  };
78110
78315
  }
@@ -78122,7 +78327,7 @@ function parseEarnUid(earnUid, knownProviders) {
78122
78327
  venue,
78123
78328
  provider,
78124
78329
  chainId,
78125
- address: ref.toLowerCase()
78330
+ address: refKey(chainId, ref)
78126
78331
  };
78127
78332
  }
78128
78333
  function tryParseEarnUid(earnUid, knownProviders) {
@@ -78143,6 +78348,7 @@ function splitUid(uid) {
78143
78348
  if (!venue || !chainId || !ref) return void 0;
78144
78349
  return { venue, chainId, ref };
78145
78350
  }
78351
+ var refKey = (chainId, ref) => isEvmChainId(chainId) ? ref.toLowerCase() : ref;
78146
78352
  var VENUE_KIND_LABELS = {
78147
78353
  lending: "Lending markets",
78148
78354
  vault: "Vaults"
@@ -78268,12 +78474,20 @@ function isInstanceSegment(seg) {
78268
78474
  if (/^0X[0-9A-F]+$/i.test(seg)) return true;
78269
78475
  return seg.length >= 8 && /^[0-9A-F]+$/i.test(seg);
78270
78476
  }
78271
- function venueBrandKey(venue) {
78272
- if (venue.startsWith(VAULT_VENUE_PREFIX)) return venue;
78273
- const key3 = venue.toUpperCase();
78477
+ function knownFamily(key3) {
78274
78478
  for (const family of FAMILY_KEYS) {
78275
78479
  if (key3 === family || key3.startsWith(family + "_")) return family;
78276
78480
  }
78481
+ return void 0;
78482
+ }
78483
+ function isLenderVenueKey(key3) {
78484
+ return !!key3 && knownFamily(key3.toUpperCase()) !== void 0;
78485
+ }
78486
+ function venueBrandKey(venue) {
78487
+ if (venue.startsWith(VAULT_VENUE_PREFIX)) return venue;
78488
+ const key3 = venue.toUpperCase();
78489
+ const family = knownFamily(key3);
78490
+ if (family) return family;
78277
78491
  const segments = key3.split("_");
78278
78492
  const cut = segments.findIndex(isInstanceSegment);
78279
78493
  return (cut > 0 ? segments.slice(0, cut) : segments).join("_");
@@ -80018,7 +80232,15 @@ function toTermSheetInput(row, ctx = {}) {
80018
80232
  closeFactor: num15(v?.closeFactor),
80019
80233
  targetHealthFactor: num15(v?.targetHealthFactor),
80020
80234
  collateralDisabled: v?.collateralDisabled === true,
80021
- debtDisabled: v?.debtDisabled === true
80235
+ debtDisabled: v?.debtDisabled === true,
80236
+ // the mode-level position fields (UNIFIED_API_AUDIT §11) — set
80237
+ // only where the row carries them, so EVM inputs are unchanged
80238
+ ...v?.liquidationBorrowFactor != null ? { liquidationBorrowFactor: num15(v.liquidationBorrowFactor) } : {},
80239
+ ...v?.debtCapacity != null ? { debtCapacity: num15(v.debtCapacity) } : {},
80240
+ ...v?.collateralDebtCapacity != null ? { collateralDebtCapacity: num15(v.collateralDebtCapacity) } : {},
80241
+ ...v?.maxCollateralAssets != null ? { maxCollateralAssets: num15(v.maxCollateralAssets) } : {},
80242
+ ...v?.exclusiveCollateral != null ? { exclusiveCollateral: v.exclusiveCollateral === true } : {},
80243
+ ...v?.openParameter ? { openParameter: v.openParameter } : {}
80022
80244
  }
80023
80245
  ])
80024
80246
  ) : void 0;
@@ -80089,6 +80311,9 @@ function toTermSheetInput(row, ctx = {}) {
80089
80311
  "variableBorrowDisabled",
80090
80312
  "flags.variableBorrowDisabled"
80091
80313
  ),
80314
+ ...pick2(row, "siloedBorrowing", "flags.siloedBorrowing") != null ? {
80315
+ siloedBorrowing: pick2(row, "siloedBorrowing", "flags.siloedBorrowing") === true
80316
+ } : {},
80092
80317
  config,
80093
80318
  // `caps.` is NOT optional here. `/pools/latest` serializes both of these as
80094
80319
  // TOP-LEVEL row fields, while `/lending/latest` — the endpoint the lending
@@ -81835,6 +82060,753 @@ function num17(v) {
81835
82060
  const n = typeof v === "string" ? Number(v) : v;
81836
82061
  return Number.isFinite(n) && n > 0 ? n : void 0;
81837
82062
  }
82063
+ var KLEND_PROGRAM_ID = "KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD";
82064
+ var KAMINO_MAIN_MARKET = "7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF";
82065
+ var KAMINO_PROFILE_ID = "kamino.klend@v1";
82066
+ var MAIN_MARKET_FULL_LIQUIDATION = {
82067
+ aboveLtv: 0.95,
82068
+ belowDebtValueUsd: 2,
82069
+ maxPerLiquidationUsd: 25e5,
82070
+ verifiedAt: "2026-09-28"
82071
+ };
82072
+ var OBLIGATION_MAX_DEPOSITS = 8;
82073
+ var OBLIGATION_MAX_BORROWS = 5;
82074
+ var isNum3 = (v) => typeof v === "number" && Number.isFinite(v);
82075
+ function elevationGroups(input) {
82076
+ const out = [];
82077
+ for (const [id, raw] of Object.entries(input.config ?? {})) {
82078
+ if (id === "0") continue;
82079
+ const c = raw;
82080
+ const role = !c.collateralDisabled ? "collateral" : !c.debtDisabled ? "debt" : "none";
82081
+ out.push({
82082
+ id,
82083
+ label: c.label,
82084
+ role,
82085
+ ...role === "collateral" ? {
82086
+ ltv: c.borrowCollateralFactor,
82087
+ liquidationLtv: c.collateralFactor
82088
+ } : {},
82089
+ ...isNum3(c.maxCollateralAssets) ? { maxCollateralAssets: c.maxCollateralAssets } : {},
82090
+ ...typeof c.exclusiveCollateral === "boolean" ? { exclusiveCollateral: c.exclusiveCollateral } : {},
82091
+ ...role === "collateral" && isNum3(c.collateralDebtCapacity) ? { collateralDebtCapacity: c.collateralDebtCapacity } : {}
82092
+ });
82093
+ }
82094
+ return out;
82095
+ }
82096
+ function build(input) {
82097
+ const market = kaminoMarketFromKey(input.lender);
82098
+ const isMain = market === KAMINO_MAIN_MARKET;
82099
+ const base = input.config?.["0"];
82100
+ const groups = elevationGroups(input);
82101
+ const address = input.asset?.address ?? input.underlying;
82102
+ const pending = {
82103
+ "borrow.liquidation.maxBonus": "the reserve's max liquidation bonus and each group's max bonus are not served; `penalty` is the reserve MIN bonus \u2014 the bonus scales with how far past the threshold the obligation is",
82104
+ "borrow.liquidation.autoDeleverage": "auto-deleverage (reserve / market flags, margin-call period, per-day threshold decay) is not served; when armed the trigger is price-and-time",
82105
+ "supply.fees": "the protocol take rate (already netted out of the supply APR) is not served",
82106
+ "supply.exit.withdrawalCap": "the reserve's net-withdrawal cap (capacity, interval, current total) is not served",
82107
+ "borrow.availability.debtWithdrawalCap": "the reserve's net-borrow cap (`debtWithdrawalCap`) is not served",
82108
+ "borrow.fees.flash-loan": "the flash-loan fee is not served",
82109
+ "constraints.collateralRules": "`disableUsageAsCollOutsideEmode` is a reserve flag the origin does not serve; an LTV-0 default entry cannot tell it from a plain LTV of 0",
82110
+ "governance.controller": "the market owner (Kamino, or a third-party curator) is not served",
82111
+ oracle: "Scope / Pyth / Switchboard per reserve (`config.tokenInfo`) \u2014 not served and not classified"
82112
+ };
82113
+ if (!isMain)
82114
+ pending["borrow.liquidation.fullLiquidation"] = "this market's insolvency-risk LTV, minimum full-liquidation value and per-liquidation cap are LendingMarket fields the origin does not serve (verified values exist for the main market only)";
82115
+ if (!isNum3(input.closeFactor) && !isNum3(base?.closeFactor))
82116
+ pending["borrow.liquidation.closeFactor"] = "the market's liquidationMaxDebtCloseFactorPct is not on the row; the builder's 1 is a placeholder, not the market's value";
82117
+ if (!isNum3(input.originationFee))
82118
+ pending["borrow.fees"] = "the origination fee lives in the reserve account, which this row was not built from";
82119
+ if (!isNum3(base?.debtCapacity))
82120
+ pending["borrow.availability.debtCapacityOutsideGroups"] = "the remaining outside-group borrow limit (`config.debtCapacity`) is not on the input";
82121
+ if (groups.some(
82122
+ (g) => g.maxCollateralAssets === void 0 || g.exclusiveCollateral === void 0
82123
+ ))
82124
+ pending["borrow.modes.constraints"] = "maxCollateralAssets / exclusiveCollateral per elevation group are served on `config` but not on the input";
82125
+ if (groups.some(
82126
+ (g) => g.role === "collateral" && g.collateralDebtCapacity === void 0
82127
+ ))
82128
+ pending["borrow.modes.collateralDebtCapacity"] = "the per-group cap on new debt against this collateral (`config[g].collateralDebtCapacity`) is not on the input; a cap of 0 closes the group to NEW debt only";
82129
+ const originationFee = isNum3(input.originationFee) && input.originationFee > 0 ? [
82130
+ {
82131
+ id: "origination",
82132
+ label: "Borrow origination fee",
82133
+ when: "entry",
82134
+ unit: "percent",
82135
+ basis: "principal",
82136
+ value: input.originationFee,
82137
+ payee: "protocol",
82138
+ mutable: true,
82139
+ description: "Taken out of the borrowed amount: the wallet receives the borrow less this fee."
82140
+ }
82141
+ ] : void 0;
82142
+ const collateralOnlyInGroups = base?.borrowCollateralFactor === 0 && (base.collateralFactor ?? 0) > 0;
82143
+ return {
82144
+ ...address ? { asset: { address: String(address) } } : {},
82145
+ supply: {
82146
+ // klend accrues and compounds interest per slot.
82147
+ rate: { compounding: "per-slot" },
82148
+ ext: {
82149
+ kamino: {
82150
+ ...collateralOnlyInGroups ? {
82151
+ noBorrowingPowerOutsideGroups: "LTV 0 outside every elevation group: this deposit adds no borrowing power there but still counts at its liquidation threshold"
82152
+ } : {},
82153
+ elevationGroups: groups.filter((g) => g.role === "collateral")
82154
+ }
82155
+ }
82156
+ },
82157
+ borrow: {
82158
+ rate: { compounding: "per-slot" },
82159
+ liquidation: {
82160
+ model: "repay-seize",
82161
+ absorber: "liquidator",
82162
+ reversible: false,
82163
+ // Auto-deleverage would make it price-and-time; it is not served, so
82164
+ // the ordinary price trigger stands and the rest is pending.
82165
+ trigger: "price",
82166
+ seizure: "proportional",
82167
+ ...isNum3(base?.liquidationPenalty) ? {
82168
+ penalties: [
82169
+ {
82170
+ id: "bonus-min",
82171
+ label: "Liquidation bonus (at the threshold)",
82172
+ value: base.liquidationPenalty,
82173
+ description: "The reserve's minimum bonus. It scales with how far the obligation sits past its liquidation threshold, up to the reserve maximum (capped at the group maximum inside an elevation group)."
82174
+ }
82175
+ ]
82176
+ } : {}
82177
+ },
82178
+ ...originationFee ? { fees: originationFee } : {},
82179
+ ext: {
82180
+ kamino: {
82181
+ closeFactorSource: "LendingMarket.liquidationMaxDebtCloseFactorPct",
82182
+ fullLiquidationRule: "The close factor rises to 100 % above the market's insolvency-risk LTV; a debt worth less than the market's minimum full-liquidation value is liquidated whole; one liquidation repays at most the market's per-liquidation USD cap.",
82183
+ ...isMain ? { fullLiquidation: MAIN_MARKET_FULL_LIQUIDATION } : {},
82184
+ ...isNum3(base?.debtCapacity) ? { debtCapacityOutsideGroups: base.debtCapacity } : {},
82185
+ elevationGroups: groups,
82186
+ elevationGroupRules: {
82187
+ oneGroupPerObligation: true,
82188
+ onlyDebtReserveBorrowable: true,
82189
+ everyDepositMustBeMember: true,
82190
+ debtReserveCannotBeDeposit: true,
82191
+ borrowFactorInsideGroup: 1,
82192
+ allowNewLoansGatesRequestAndBorrow: true,
82193
+ zeroGroupCapClosesNewDebtOnly: true,
82194
+ selection: "per obligation (`request_elevation_group`)"
82195
+ }
82196
+ }
82197
+ }
82198
+ },
82199
+ constraints: {
82200
+ crossMargin: true,
82201
+ positionModel: "sub-account",
82202
+ positionIdMeaning: `The obligation pubkey \u2014 a PDA over [tag, id, owner, market, seed1, seed2]: tag 0 vanilla lending (both seeds default), 1 Multiply and 3 Leverage (the pair's mints), 2 Lending (one mint, seed1 = seed2); up to 256 ids per (tag, seed pair) per market. Each obligation is its own position with its own elevation group and health, at most ${OBLIGATION_MAX_DEPOSITS} deposits and ${OBLIGATION_MAX_BORROWS} borrows. The hosted builder addresses vanilla #0 only.`
82203
+ },
82204
+ ext: {
82205
+ kamino: {
82206
+ program: KLEND_PROGRAM_ID,
82207
+ ...market ? { market } : {},
82208
+ isMainMarket: isMain,
82209
+ /** The marketUid ref is the RESERVE pubkey, not the mint. */
82210
+ marketUidRef: "reserve"
82211
+ }
82212
+ },
82213
+ coverage: { pending }
82214
+ };
82215
+ }
82216
+ var kaminoAdapter = {
82217
+ id: "kamino",
82218
+ matches: isKamino,
82219
+ profileId: () => KAMINO_PROFILE_ID,
82220
+ build
82221
+ };
82222
+ var JUPITER_LEND_PROFILE_ID = "jupiter-lend.vault@v1";
82223
+ var FLUID_VAULT_TYPE_T1 = 1e4;
82224
+ var JL_MAX_BORROW_FEE_PERCENT = 2.55;
82225
+ var JL_MAIN_PROGRAMS = {
82226
+ liquidity: "jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC",
82227
+ vaults: "jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi",
82228
+ oracle: "jupnw4B6Eqs7ft6rxpzYLJZYSnrpRgPcr589n5Kv4oc",
82229
+ flashloan: "jupgfSgfuAXv4B6R2Uxu85Z1qdzgju79s6MfZekN6XS"
82230
+ };
82231
+ var isNum4 = (v) => typeof v === "number" && Number.isFinite(v);
82232
+ function build2(input) {
82233
+ const vault = jupiterLendVaultFromKey(input.lender);
82234
+ const address = input.asset?.address ?? input.underlying;
82235
+ const pending = {
82236
+ "borrow.liquidation.liquidationMaxLimit": "the max liquidation limit (the LTV past which a position is liquidated ENTIRELY) is not served",
82237
+ "borrow.availability.cap": "the layer's EXPANDING borrow limit (current, hard max, expand percent and duration) is not served \u2014 it is not a cap, so the row carries none",
82238
+ "supply.exit.withdrawalLimit": "the expanding per-position withdrawal limit and the vault's withdrawal gap are not served",
82239
+ "borrow.availability.minSize": "the vault's minimum borrow is not served",
82240
+ "borrow.fees.flash-loan": "the market flashloan program's fee and flashable set are not served",
82241
+ "borrow.ext.rateMagnifiers": "the vault's additive supply / borrow magnifiers are not served (the row's rates already include them)",
82242
+ oracle: "the vault's oracle (sources, hops) is not served; its price is borrow-per-supply in HUMAN units \xD7 1e15",
82243
+ "governance.controller": "the vault admin / rate-model authority is not on the public API"
82244
+ };
82245
+ if (!isNum4(input.originationFee) && input.borrowingEnabled === true)
82246
+ pending["borrow.fees"] = "the vault's borrow fee is not on the row";
82247
+ const fees = isNum4(input.originationFee) && input.originationFee > 0 ? [
82248
+ {
82249
+ id: "origination",
82250
+ label: "Borrow fee",
82251
+ when: "entry",
82252
+ unit: "percent",
82253
+ basis: "principal",
82254
+ value: input.originationFee,
82255
+ payee: "protocol",
82256
+ mutable: true,
82257
+ cap: JL_MAX_BORROW_FEE_PERCENT,
82258
+ description: "Charged once on the amount borrowed; the vault stores it as a u8 at 1e4, so it can never exceed 2.55 %."
82259
+ }
82260
+ ] : void 0;
82261
+ return {
82262
+ ...address ? { asset: { address: String(address) } } : {},
82263
+ // Rates are set on the Liquidity Layer — claim that basis only when the
82264
+ // layer totals are actually on the row (the fluid adapter's rule). Only
82265
+ // REFINES a block the builder made: a patch with no base would become a
82266
+ // utilization block without a utilization.
82267
+ ...isNum4(input.utilization) ? {
82268
+ utilization: input.irmTotalDeposits != null && input.irmTotalDebt != null ? { basis: "liquidity-layer", lockupRatio: input.lockupRatio } : { lockupRatio: input.lockupRatio }
82269
+ } : {},
82270
+ borrow: {
82271
+ liquidation: {
82272
+ model: "repay-seize",
82273
+ absorber: "liquidator",
82274
+ reversible: false,
82275
+ trigger: "price",
82276
+ seizure: "proportional"
82277
+ },
82278
+ ...fees ? { fees } : {},
82279
+ ext: {
82280
+ jupiterLend: {
82281
+ fullLiquidationRule: "Past the liquidation threshold a liquidator repays part of the debt and takes collateral plus the penalty; past the max liquidation limit the position is liquidated entirely.",
82282
+ rateMagnifier: {
82283
+ additive: true,
82284
+ unit: "bps",
82285
+ includedInRowRates: true,
82286
+ note: "A signed APR offset ADDED to the layer's per-token rate (vault 101: \u2212200) \u2014 not EVM Fluid's multiplier."
82287
+ },
82288
+ borrowLimit: "An EXPANDING ceiling on the layer, not a cap: a borrow above the current limit waits for it to grow toward the vault's hard maximum."
82289
+ }
82290
+ }
82291
+ },
82292
+ constraints: {
82293
+ crossMargin: false,
82294
+ positionModel: "nft",
82295
+ positionIdMeaning: "The vault position NFT id (per vault; one collateral / debt pair each). positionId 0 MINTS a new position \u2014 only an opening deposit may pass 0; any other action sent with 0 acts on a fresh empty position and reports success."
82296
+ },
82297
+ ext: {
82298
+ jupiterLend: {
82299
+ ...vault ? { market: vault.market, vaultId: vault.vaultId } : {},
82300
+ fluidVaultType: FLUID_VAULT_TYPE_T1,
82301
+ ...vault?.market === "main" ? { programs: JL_MAIN_PROGRAMS } : {},
82302
+ /** The marketUid ref is the leg's MINT. */
82303
+ marketUidRef: "mint"
82304
+ }
82305
+ },
82306
+ coverage: { pending }
82307
+ };
82308
+ }
82309
+ var jupiterLendAdapter = {
82310
+ id: "jupiter-lend",
82311
+ matches: isJupiterLend,
82312
+ profileId: () => JUPITER_LEND_PROFILE_ID,
82313
+ build: build2
82314
+ };
82315
+ var SAVE_PROGRAM_ID = "So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo";
82316
+ var SAVE_PROFILE_ID = "save.pool@v1";
82317
+ var SAVE_LIQUIDATION_CLOSE_FACTOR = 0.2;
82318
+ var SAVE_MAX_LIQUIDATABLE_VALUE_USD = 5e5;
82319
+ var SAVE_FULL_LIQUIDATION_VALUE_USD = 1;
82320
+ var SAVE_MAX_PENALTY = 0.25;
82321
+ var SAVE_SLOTS_PER_YEAR = 63072e3;
82322
+ var SAVE_MAX_OBLIGATION_RESERVES = 10;
82323
+ var SAVE_POSITION_LIMIT = 6;
82324
+ var isNum5 = (v) => typeof v === "number" && Number.isFinite(v);
82325
+ function build3(input) {
82326
+ const market = saveMarketFromKey(input.lender);
82327
+ const base = input.config?.["0"];
82328
+ const siloed = input.siloedBorrowing;
82329
+ const address = input.asset?.address ?? input.underlying;
82330
+ const pending = {
82331
+ "borrow.liquidation.maxBonus": "the max liquidation bonus and the max liquidation threshold it is reached at are not served; `penalty` is what the borrower pays AT the threshold",
82332
+ "borrow.liquidation.penaltySplit": "the row carries bonus + protocol fee as one figure; the split is not served",
82333
+ "supply.fees": "the protocol take rate on interest is not served (it is already netted out of the supply APR)",
82334
+ "borrow.fees.flash-loan": "the flash-loan fee is not served",
82335
+ "borrow.fees.host": "the host (referrer) share of the origination fee is not served",
82336
+ "supply.exit.rateLimiter": "the market-wide outflow limiter (window, max outflow) is in the LendingMarket account and not served \u2014 read on-chain before stating exit capacity",
82337
+ "borrow.rate.bounds": "the three-segment curve (min / optimal / max / super-max rates) is not served",
82338
+ "governance.controller": "the market owner (Save's key for Main, a third party elsewhere) is not served",
82339
+ oracle: "Pyth pull / Switchboard per reserve, and the owner-set SOL-price ratio some LST reserves are valued with, are not served",
82340
+ "borrow.liquidation.oracleStaleness": "Pyth pull \u2264 120 s, Switchboard \u2264 240 slots; a stale long-tail feed blocks every borrow or withdrawal of an obligation holding it"
82341
+ };
82342
+ if (typeof siloed !== "boolean")
82343
+ pending["constraints.siloedBorrowing"] = "the isolated-reserve flag (`siloedBorrowing`) is served on the row but not on the input";
82344
+ if (!isNum5(input.originationFee))
82345
+ pending["borrow.fees"] = "the origination fee is not on the row";
82346
+ const originationFee = isNum5(input.originationFee) && input.originationFee > 0 ? [
82347
+ {
82348
+ id: "origination",
82349
+ label: "Borrow (origination) fee",
82350
+ when: "entry",
82351
+ unit: "percent",
82352
+ basis: "principal",
82353
+ value: input.originationFee,
82354
+ payee: "protocol",
82355
+ mutable: true,
82356
+ description: "Deducted from the amount received; part of it goes to the referring host account when one is named."
82357
+ }
82358
+ ] : void 0;
82359
+ return {
82360
+ ...address ? { asset: { address: String(address) } } : {},
82361
+ supply: {
82362
+ rate: { compounding: "per-slot" },
82363
+ counterparty: {
82364
+ kind: "pool",
82365
+ solvency: "overcollateralized",
82366
+ socializedLoss: true
82367
+ },
82368
+ principal: { protected: false, risks: ["bad-debt"] }
82369
+ },
82370
+ borrow: {
82371
+ rate: { compounding: "per-slot" },
82372
+ liquidation: {
82373
+ model: "repay-seize",
82374
+ absorber: "liquidator",
82375
+ reversible: false,
82376
+ trigger: "price",
82377
+ // A program constant — the row carries the same 0.2.
82378
+ closeFactor: SAVE_LIQUIDATION_CLOSE_FACTOR,
82379
+ seizure: "proportional",
82380
+ permissioned: false,
82381
+ badDebt: "socialized",
82382
+ ...isNum5(base?.liquidationPenalty) ? {
82383
+ penalties: [
82384
+ {
82385
+ id: "bonus-plus-protocol-fee",
82386
+ label: "Liquidator bonus + protocol fee (at the threshold)",
82387
+ value: base.liquidationPenalty,
82388
+ description: `What the borrower pays at the liquidation threshold: the liquidator bonus plus the protocol liquidation fee (the liquidator seizes both and pays the fee on). The bonus scales linearly toward the reserve maximum as the obligation approaches its max liquidation threshold; bonus + fee is capped at ${SAVE_MAX_PENALTY * 100} %.`
82389
+ }
82390
+ ]
82391
+ } : {}
82392
+ },
82393
+ counterparty: {
82394
+ kind: "pool",
82395
+ solvency: "overcollateralized",
82396
+ socializedLoss: true
82397
+ },
82398
+ ...originationFee ? { fees: originationFee } : {},
82399
+ ext: {
82400
+ save: {
82401
+ closeFactor: {
82402
+ fraction: SAVE_LIQUIDATION_CLOSE_FACTOR,
82403
+ basis: "the obligation's WEIGHTED borrow value",
82404
+ maxPerCallUsd: SAVE_MAX_LIQUIDATABLE_VALUE_USD,
82405
+ fullLiquidationAtOrBelowUsd: SAVE_FULL_LIQUIDATION_VALUE_USD
82406
+ },
82407
+ maxPenalty: SAVE_MAX_PENALTY,
82408
+ /** The row's `borrowFactor`: the debt multiplier (`borrowed_value += value × borrow_weight`). */
82409
+ ...isNum5(base?.borrowFactor) ? { borrowWeight: base.borrowFactor } : {},
82410
+ isolatedRule: "Isolated reserves are borrow-side only: an obligation borrowing one may hold no other borrow (and one holding a regular borrow may not add it); deposits are unrestricted; LTV and LT are forced to 0.",
82411
+ ...typeof siloed === "boolean" ? { isolated: siloed } : {},
82412
+ slotYear: {
82413
+ slotsPerYear: SAVE_SLOTS_PER_YEAR,
82414
+ note: "The curve compounds per slot on a 0.5 s slot-year; the row publishes it scaled to the measured slot time."
82415
+ }
82416
+ }
82417
+ }
82418
+ },
82419
+ constraints: {
82420
+ crossMargin: true,
82421
+ positionModel: "sub-account",
82422
+ positionIdMeaning: `The obligation pubkey, derived with createWithSeed(wallet, seed, program): #0 seeds with market[0:32], #n with market[0:24] + n (6 digits) + "m" \u2014 no index account needed. One obligation holds up to ${SAVE_MAX_OBLIGATION_RESERVES} reserves (the SDK caps a position at ${SAVE_POSITION_LIMIT}).`,
82423
+ ...typeof siloed === "boolean" ? { siloedBorrowing: siloed } : {}
82424
+ },
82425
+ ext: {
82426
+ save: {
82427
+ program: SAVE_PROGRAM_ID,
82428
+ ...market ? { market } : {},
82429
+ /** The marketUid ref is the RESERVE pubkey, not the mint. */
82430
+ marketUidRef: "reserve"
82431
+ }
82432
+ },
82433
+ coverage: { pending }
82434
+ };
82435
+ }
82436
+ var saveAdapter = {
82437
+ id: "save",
82438
+ matches: isSave,
82439
+ profileId: () => SAVE_PROFILE_ID,
82440
+ build: build3
82441
+ };
82442
+ var LOOPSCALE_PROFILE_ID = "loopscale.creditbook@v1";
82443
+ var LOOPSCALE_PROGRAM_ID = "1oopBoJG58DgkUVKkEzKgyG9dvRmpgeEm1AVjoHkF78";
82444
+ var LOOPSCALE_BEAM_ORACLE_PROGRAM_ID = "beamVVkNmKeXcuZ6zLpC9eM5YgVyAn4Z9xdPrz3gCW2";
82445
+ var LOOPSCALE_GRACE_PERIOD_SECS = 172800;
82446
+ var LOOPSCALE_REFINANCE_TERM_DAYS = 1;
82447
+ var LOOPSCALE_MAX_COLLATERALS = 5;
82448
+ var LOOPSCALE_MAX_LEDGERS = 5;
82449
+ var LS_NO_ACCOUNT = "11111111111111111111111111111111";
82450
+ var DAY2 = 86400;
82451
+ var isNum6 = (v) => typeof v === "number" && Number.isFinite(v);
82452
+ function menuOf(input) {
82453
+ if (!input.terms?.length) return void 0;
82454
+ return input.terms.map((t) => ({
82455
+ ...t,
82456
+ durationSecs: isNum6(t.durationSecs) ? t.durationSecs : Math.round(t.durationDays * DAY2)
82457
+ }));
82458
+ }
82459
+ function build4(input) {
82460
+ const pair = loopscaleMarketFromKey(input.lender);
82461
+ const m = input.market ?? {};
82462
+ const cfg = input.config?.["0"];
82463
+ const address = input.asset?.address ?? input.underlying;
82464
+ const menu = menuOf(input);
82465
+ const durations = (menu ?? []).map((t) => t.durationSecs).filter(isNum6);
82466
+ const tenor = durations.length ? {
82467
+ minDurationSecs: Math.min(...durations),
82468
+ maxDurationSecs: Math.max(...durations)
82469
+ } : {};
82470
+ const oracleAccount = typeof m.oracle === "string" && m.oracle !== LS_NO_ACCOUNT ? m.oracle : void 0;
82471
+ const lltvRaw = m.lltv != null ? Number(m.lltv) : void 0;
82472
+ const bestOneDayLqt = lltvRaw != null && Number.isFinite(lltvRaw) && lltvRaw > 0 ? lltvRaw / 1e18 : void 0;
82473
+ const openParameter = cfg?.openParameter;
82474
+ const pending = {
82475
+ "borrow.liquidation.penalty": "distance-based \u2014 the fee is how far past the liquidation LTV the loan was (80.5 % on an 80 % threshold \u21D2 0.5 %); there is no flat figure to state",
82476
+ "borrow.rate.menu.ltv": "each tenor's best-offer LTV / LQT and its depth ladder are not served (`terms` carry the rate only); the row's factors are the best 1-day offer's",
82477
+ "supply.fees": "the curated vault's interest fee (0\u201325 %) is not served; the row's depositRate is already net of the fee the converter attributed",
82478
+ "borrow.counterparty.curator": "which strategy rests the best offer (and its vault) is not served",
82479
+ "governance.controller": "per strategy: the curator (24 h timelock on collateral / LTV, rates and fees immediate) and the protocol admin are not on the public API"
82480
+ };
82481
+ if (!oracleAccount)
82482
+ pending.oracle = "no oracle account is on params.market for this collateral (the MarketInformation read did not name one)";
82483
+ else
82484
+ pending.oracle = `the program reads ${oracleAccount} (BEAM: Pyth / Switchboard / Chainlink / RedStone + component pricing); not classified`;
82485
+ if (!isNum6(input.originationFee) && input.borrowingEnabled === true)
82486
+ pending["borrow.fees"] = "no curated vault offers this pair \u2014 the resting strategy\u2019s fees are not on the public API";
82487
+ if (!cfg?.openParameter && cfg?.collateralDisabled === false)
82488
+ pending["supply.ext.openParameter"] = "the per-loan threshold domain (`config['0'].openParameter`, kind `loan-lqt`) is served on the collateral row but not on the input";
82489
+ const isLoanLeg = cfg?.debtDisabled === false || input.rateModel === "fixedTerm" || !!input.terms?.length;
82490
+ const originationFee = isNum6(input.originationFee) ? input.originationFee > 0 ? [
82491
+ {
82492
+ id: "origination",
82493
+ label: "Origination fee",
82494
+ when: "entry",
82495
+ unit: "percent",
82496
+ basis: "principal",
82497
+ value: input.originationFee,
82498
+ payee: "curator",
82499
+ mutable: true,
82500
+ description: "Set by the strategy (vault) resting the offer; taken at origination. The row's figure is the best offer's vault, else the highest among the pair's vaults."
82501
+ }
82502
+ ] : [] : void 0;
82503
+ const fixedRate = {
82504
+ kind: "fixed-term",
82505
+ source: "orderbook",
82506
+ isLocked: true,
82507
+ compounding: "none",
82508
+ ...menu ? { menu } : {}
82509
+ };
82510
+ return {
82511
+ ...address ? { asset: { address: String(address) } } : {},
82512
+ // An order book has no pool utilization; the row's 0 is a placeholder.
82513
+ // `null`, not `undefined`: the deep merge skips `undefined`, so only
82514
+ // `null` removes the builder's block (the type has no "remove" spelling).
82515
+ utilization: null,
82516
+ supply: isLoanLeg ? {
82517
+ // What an advanced lender resting at the best 1-day rate earns.
82518
+ rate: fixedRate,
82519
+ maturity: {
82520
+ kind: "rolling-duration",
82521
+ ...tenor,
82522
+ // The ledger is repaid out of the refinancing offer, or runs the
82523
+ // grace period at the same rate.
82524
+ atMaturity: "refinanced",
82525
+ graceSecs: LOOPSCALE_GRACE_PERIOD_SECS
82526
+ },
82527
+ exit: {
82528
+ // Before maturity a ledger leaves only by being sold to another
82529
+ // strategy at a negotiated price — and there may be no buyer.
82530
+ mode: "market-sale",
82531
+ settlement: "sync",
82532
+ priceRisk: "may-be-impossible",
82533
+ partialAllowed: true
82534
+ },
82535
+ counterparty: { kind: "orderbook", solvency: "overcollateralized" },
82536
+ principal: { protected: false, risks: ["bad-debt"] },
82537
+ ext: {
82538
+ loopscale: {
82539
+ exitBeforeMaturity: "sell-ledger",
82540
+ passiveLenders: "Deposit into a curated vault (its own earn row), which rests the offers and charges a fee on the interest"
82541
+ }
82542
+ }
82543
+ } : {
82544
+ ...openParameter ? {
82545
+ ext: {
82546
+ loopscale: {
82547
+ // Each loan pins the LTV / LQT of the offer it filled;
82548
+ // `modes[<loan pubkey>]` carries the value per position.
82549
+ openParameter
82550
+ }
82551
+ }
82552
+ } : {}
82553
+ },
82554
+ borrow: {
82555
+ rate: fixedRate,
82556
+ maturity: {
82557
+ kind: "rolling-duration",
82558
+ ...tenor,
82559
+ atMaturity: "refinanced",
82560
+ graceSecs: LOOPSCALE_GRACE_PERIOD_SECS
82561
+ },
82562
+ // Interest accrues to date; repaying early costs the interest so far.
82563
+ debtShape: "accruing",
82564
+ exit: {
82565
+ earlyRepay: "free",
82566
+ atMaturityCost: "accrued",
82567
+ // Not refinanced and past the grace period: liquidatable whatever
82568
+ // the health.
82569
+ lateBehaviour: "liquidatable",
82570
+ partialAllowed: true
82571
+ },
82572
+ liquidation: {
82573
+ model: "repay-seize",
82574
+ absorber: "liquidator",
82575
+ reversible: false,
82576
+ trigger: "price-and-time",
82577
+ seizure: "proportional",
82578
+ // Distance-based: there is no headline penalty. The row's 0 is the
82579
+ // converter's placeholder; `null` removes it (see `utilization`).
82580
+ penalty: null,
82581
+ penalties: [
82582
+ {
82583
+ id: "distance-past-threshold",
82584
+ label: "Distance past the liquidation LTV",
82585
+ value: 0,
82586
+ description: "Partial first: the minimum collateral to bring the loan back under its MAX LTV is sold, and the fee equals how far past the liquidation LTV the loan was (80.5 % on an 80 % threshold \u21D2 0.5 %). 0 is its value AT the threshold. Health counts the interest owed at maturity as debt."
82587
+ }
82588
+ ]
82589
+ },
82590
+ counterparty: { kind: "orderbook", solvency: "overcollateralized" },
82591
+ ...originationFee ? { fees: originationFee } : {},
82592
+ ext: {
82593
+ loopscale: {
82594
+ autoRefinance: {
82595
+ termDays: LOOPSCALE_REFINANCE_TERM_DAYS,
82596
+ bestEffort: true,
82597
+ fallback: "no matching offer \u21D2 a 48-hour grace period at the same rate, then partial liquidation"
82598
+ },
82599
+ gracePeriodSecs: LOOPSCALE_GRACE_PERIOD_SECS,
82600
+ healthCountsInterestToMaturity: true,
82601
+ ltvPinnedAtOrigination: true,
82602
+ ...bestOneDayLqt !== void 0 ? {
82603
+ bestOneDayLiquidationLtv: bestOneDayLqt,
82604
+ bestOneDayLiquidationLtvNote: "params.market.lltv: the best 1-day offer's threshold today \u2014 a moving proxy, not a market constant"
82605
+ } : {}
82606
+ }
82607
+ }
82608
+ },
82609
+ constraints: {
82610
+ crossMargin: true,
82611
+ positionModel: "loan-id",
82612
+ positionIdMeaning: `The Loan account pubkey \u2014 one per loan, opened by the venue's builder; up to ${LOOPSCALE_MAX_COLLATERALS} collaterals and ${LOOPSCALE_MAX_LEDGERS} ledgers each, cross-margined inside the loan.`
82613
+ },
82614
+ ext: {
82615
+ loopscale: {
82616
+ program: LOOPSCALE_PROGRAM_ID,
82617
+ oracleProgram: LOOPSCALE_BEAM_ORACLE_PROGRAM_ID,
82618
+ ...pair ? { pair } : {},
82619
+ ...oracleAccount ? { oracleAccount } : {},
82620
+ /** The marketUid ref is the leg's MINT. */
82621
+ marketUidRef: "mint"
82622
+ }
82623
+ },
82624
+ coverage: {
82625
+ pending,
82626
+ notApplicable: { utilization: "order book \u2014 no pool utilization" }
82627
+ }
82628
+ };
82629
+ }
82630
+ var loopscaleAdapter = {
82631
+ id: "loopscale",
82632
+ matches: isLoopscale,
82633
+ profileId: () => LOOPSCALE_PROFILE_ID,
82634
+ build: build4
82635
+ };
82636
+ var PROJECT_0_PROFILE_ID = "project0.group@v1";
82637
+ var P0_PROGRAM_ID = "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA";
82638
+ var P0_MAIN_GROUP = "4qp6Fx6tnZkY5Wropq9wUYgtFxXKwE6viZxFHg3rdAG8";
82639
+ var P0_DEFAULT_LIQUIDATION_FEE = 0.025;
82640
+ var P0_LIQUIDATION_CLOSEOUT_USD = 5;
82641
+ var P0_MAX_BALANCES = 16;
82642
+ var P0_SECONDS_PER_YEAR = 365 * 24 * 60 * 60;
82643
+ var isNum7 = (v) => typeof v === "number" && Number.isFinite(v);
82644
+ function derivedModes(input) {
82645
+ const cfg = input.config;
82646
+ if (!cfg || Object.keys(cfg).length <= 1) return void 0;
82647
+ return Object.entries(cfg).map(([key3, c]) => {
82648
+ const isDefault = key3 === "0";
82649
+ return {
82650
+ modeId: key3,
82651
+ label: c.label,
82652
+ isDefault,
82653
+ entry: isDefault ? void 0 : "automatic",
82654
+ liquidation: {
82655
+ ltv: c.borrowCollateralFactor,
82656
+ liquidationLtv: c.collateralFactor,
82657
+ penalty: c.liquidationPenalty,
82658
+ closeFactor: c.closeFactor ?? input.closeFactor ?? 1,
82659
+ targetHealthFactor: c.targetHealthFactor ?? input.targetHealthFactor
82660
+ },
82661
+ ...c.debtDisabled ? { availability: { canOpen: false } } : {}
82662
+ };
82663
+ });
82664
+ }
82665
+ function build5(input) {
82666
+ const group = project0GroupFromKey(input.lender);
82667
+ const base = input.config?.["0"];
82668
+ const siloed = input.siloedBorrowing;
82669
+ const address = input.asset?.address ?? input.underlying;
82670
+ const penalty = base?.liquidationPenalty;
82671
+ const defaultFees = isNum7(penalty) && Math.abs(penalty - 2 * P0_DEFAULT_LIQUIDATION_FEE) < 1e-9;
82672
+ const liabilityWeightMaint = base?.liquidationBorrowFactor;
82673
+ const pending = {
82674
+ "ext.project0.operationalState": "the bank's operational state (Operational / Paused / ReduceOnly / ReduceOnlyWithBorrowingPower, or a circuit-breaker halt) is not served; the flags carry its effect on opening only",
82675
+ "borrow.fees.interest": "the group, insurance and program fee legs on interest (and their fixed APRs) are not served",
82676
+ "supply.exit.rateLimiter": "the bank's hourly / daily outflow limiter (shared by withdrawals and borrows) and the group's USD limiter are not served",
82677
+ "supply.rate.wrapped": "whether this bank wraps a Kamino / Drift / Jupiter Lend position or native stake is not served; a wrapped bank's yield is the venue's (on intrinsicYield when the fetcher supplies it)",
82678
+ "borrow.liquidation.receivership": "the receivership path (a liquidator controls the account for one transaction, at a higher premium) is not modelled",
82679
+ "borrow.modes.sameAsset": "the group's same-asset e-mode leverage (and the 20\xD7 / 40\xD7 caps) is not served",
82680
+ oracle: "the oracle setup (Pyth push / Switchboard / fixed / Kamino Scope / staked), max age and confidence cap are not served",
82681
+ "governance.roles": "the group admin and its delegates (e-mode, curve, limit, risk admins) are not served; multisig status unverified"
82682
+ };
82683
+ if (!isNum7(liabilityWeightMaint) && base?.debtDisabled === false)
82684
+ pending["borrow.liquidation.liquidationBorrowFactor"] = "the maintenance liability weight (`config.liquidationBorrowFactor`) is served on the row but not on the input; `borrowFactor` is the INITIAL weight, which overstates the debt for liquidation";
82685
+ if (typeof siloed !== "boolean")
82686
+ pending["constraints.siloedBorrowing"] = "the isolated-tier flag (`siloedBorrowing`) is served on the row but not on the input";
82687
+ if (isNum7(penalty) && !defaultFees)
82688
+ pending["borrow.liquidation.penaltySplit"] = "the row carries liquidator + insurance fee as one figure; the split is not served";
82689
+ if (!isNum7(input.originationFee))
82690
+ pending["borrow.fees"] = "the origination fee is not on the row";
82691
+ const penalties = !isNum7(penalty) ? void 0 : defaultFees ? [
82692
+ {
82693
+ id: "liquidator-fee",
82694
+ label: "Liquidator premium",
82695
+ value: P0_DEFAULT_LIQUIDATION_FEE,
82696
+ description: "Read from the LIABILITY bank being repaid (a stored 0 is this 2.5 % default); it goes to the liquidator."
82697
+ },
82698
+ {
82699
+ id: "insurance-fee",
82700
+ label: "Insurance fund fee",
82701
+ value: P0_DEFAULT_LIQUIDATION_FEE,
82702
+ description: "Also read from the liability bank; the liquidatee pays both, the insurance fund keeps this one. `penalty` is the total the liquidatee loses."
82703
+ }
82704
+ ] : [
82705
+ {
82706
+ id: "liquidation-fees",
82707
+ label: "Liquidator premium + insurance fee",
82708
+ value: penalty,
82709
+ description: "Both read from the LIABILITY bank being repaid; the liquidatee pays the total."
82710
+ }
82711
+ ];
82712
+ const originationFee = isNum7(input.originationFee) && input.originationFee > 0 ? [
82713
+ {
82714
+ id: "origination",
82715
+ label: "Borrow origination fee",
82716
+ when: "entry",
82717
+ unit: "percent",
82718
+ basis: "principal",
82719
+ value: input.originationFee,
82720
+ payee: "protocol",
82721
+ mutable: true
82722
+ }
82723
+ ] : void 0;
82724
+ const modes = derivedModes(input);
82725
+ return {
82726
+ ...address ? { asset: { address: String(address) } } : {},
82727
+ supply: {
82728
+ // Simple interest settled into the share value at every touch.
82729
+ rate: { compounding: "on-touch" },
82730
+ counterparty: {
82731
+ kind: "pool",
82732
+ solvency: "overcollateralized",
82733
+ socializedLoss: true
82734
+ },
82735
+ principal: { protected: false, risks: ["bad-debt"] },
82736
+ ...modes ? { modes } : {}
82737
+ },
82738
+ borrow: {
82739
+ rate: { compounding: "on-touch" },
82740
+ liquidation: {
82741
+ model: "repay-seize",
82742
+ absorber: "liquidator",
82743
+ reversible: false,
82744
+ trigger: "price",
82745
+ seizure: "proportional",
82746
+ permissioned: false,
82747
+ // The insurance fund absorbs first; the rest is socialised to the
82748
+ // bank's depositors (`counterparty.socializedLoss`).
82749
+ badDebt: "insurance-fund",
82750
+ ...penalties ? { penalties } : {}
82751
+ },
82752
+ counterparty: {
82753
+ kind: "pool",
82754
+ solvency: "overcollateralized",
82755
+ socializedLoss: true
82756
+ },
82757
+ ...originationFee ? { fees: originationFee } : {},
82758
+ ...modes ? { modes } : {},
82759
+ ext: {
82760
+ project0: {
82761
+ liquidation: {
82762
+ partialToHealthZero: true,
82763
+ closeoutBelowEquityUsd: P0_LIQUIDATION_CLOSEOUT_USD,
82764
+ feesReadFrom: "the liability bank",
82765
+ defaultFeeEach: P0_DEFAULT_LIQUIDATION_FEE
82766
+ },
82767
+ liabilityWeights: {
82768
+ /** `borrowFactor`: the weight a NEW borrow is checked against. */
82769
+ ...isNum7(base?.borrowFactor) ? { init: base.borrowFactor } : {},
82770
+ /** `liquidationBorrowFactor`: the weight liquidation health uses. */
82771
+ ...isNum7(liabilityWeightMaint) ? { maint: liabilityWeightMaint } : {}
82772
+ },
82773
+ emodeModel: "Derived, never selected: an account's mode follows the e-mode tags of everything it borrows \u2014 the program takes the least favourable lift per collateral tag across the liabilities, and a liability with no entry for a collateral tag removes that lift.",
82774
+ operationalStates: {
82775
+ Operational: "every action",
82776
+ ReduceOnly: "no deposits or borrows; withdrawals and repayments work; the collateral counts toward liquidation health only (initial weight 0)",
82777
+ ReduceOnlyWithBorrowingPower: "no deposits or borrows; the collateral keeps both weights",
82778
+ Paused: "no deposits, withdrawals, borrows, repayments or liquidations",
82779
+ accrual: "interest accrues at the curve rate in every state"
82780
+ },
82781
+ isolatedRule: "An isolated-tier bank can be borrowed only on its own and never counts as collateral.",
82782
+ ...typeof siloed === "boolean" ? { isolated: siloed } : {},
82783
+ secondsPerYear: P0_SECONDS_PER_YEAR
82784
+ }
82785
+ }
82786
+ },
82787
+ constraints: {
82788
+ crossMargin: true,
82789
+ positionModel: "sub-account",
82790
+ positionIdMeaning: `The marginfi account pubkey \u2014 a keypair account (older) or the PDA ["marginfi_account", group, authority, u16 index, u16 third-party id]; any number per wallet, up to ${P0_MAX_BALANCES} balances each, one health per account.`,
82791
+ ...typeof siloed === "boolean" ? { siloedBorrowing: siloed } : {}
82792
+ },
82793
+ ext: {
82794
+ project0: {
82795
+ program: P0_PROGRAM_ID,
82796
+ ...group ? { group, isMainGroup: group === P0_MAIN_GROUP } : {},
82797
+ /** The marketUid ref is the BANK pubkey, not the mint. */
82798
+ marketUidRef: "bank"
82799
+ }
82800
+ },
82801
+ coverage: { pending }
82802
+ };
82803
+ }
82804
+ var project0Adapter = {
82805
+ id: "project0",
82806
+ matches: isProject0,
82807
+ profileId: () => PROJECT_0_PROFILE_ID,
82808
+ build: build5
82809
+ };
81838
82810
 
81839
82811
  // src/terms/adapters/index.ts
81840
82812
  var TERM_ADAPTERS = [
@@ -81860,7 +82832,14 @@ var TERM_ADAPTERS = [
81860
82832
  twyneAdapter,
81861
82833
  fraxlendAdapter,
81862
82834
  morphoBlueAdapter,
81863
- aaveV4Adapter
82835
+ aaveV4Adapter,
82836
+ // Solana families — predicates match `<FAMILY>` / `<FAMILY>_<base58>` on an
82837
+ // `_` boundary, disjoint from every EVM key above.
82838
+ kaminoAdapter,
82839
+ jupiterLendAdapter,
82840
+ saveAdapter,
82841
+ loopscaleAdapter,
82842
+ project0Adapter
81864
82843
  ];
81865
82844
  function resolveAdapter(lender) {
81866
82845
  return TERM_ADAPTERS.find((a) => a.matches(lender));
@@ -81944,9 +82923,10 @@ function enrichmentIndexFromRows(rows) {
81944
82923
  }
81945
82924
  const token = breakdown.find((b) => b?.category === "token");
81946
82925
  const chainId = String(row?.chainId ?? uid.split(":")[1] ?? "");
81947
- const address = String(
81948
- row?.asset?.address ?? row?.underlying ?? uid.split(":")[2] ?? ""
81949
- ).toLowerCase();
82926
+ const address = termAddressKey(
82927
+ chainId,
82928
+ String(row?.asset?.address ?? row?.underlying ?? uid.split(":")[2] ?? "")
82929
+ );
81950
82930
  if (token?.score != null && chainId && address) {
81951
82931
  assetRisk[chainId] ??= {};
81952
82932
  assetRisk[chainId][address] = {
@@ -82013,7 +82993,7 @@ function enrichTermSheet(sheet, index) {
82013
82993
  sheet.oracle = {
82014
82994
  ...sheet.oracle,
82015
82995
  kind: "price-feed",
82016
- address: oracleRow.oracle.toLowerCase(),
82996
+ address: termAddressKey(sheet.chainId, oracleRow.oracle),
82017
82997
  provider: oracleRow.provider,
82018
82998
  priceDescription: oracleRow.priceDescription,
82019
82999
  intendedPair: oracleRow.intendedPair,
@@ -82078,7 +83058,7 @@ function enrichTermSheet(sheet, index) {
82078
83058
  if (itemOracle?.oracle) {
82079
83059
  item.oracle = {
82080
83060
  kind: "price-feed",
82081
- address: itemOracle.oracle.toLowerCase(),
83061
+ address: termAddressKey(sheet.chainId, itemOracle.oracle),
82082
83062
  provider: itemOracle.provider,
82083
83063
  band: itemOracle.band,
82084
83064
  score: itemOracle.score,
@@ -82268,8 +83248,8 @@ function validateTermSheet(sheet) {
82268
83248
  `oracle.kind none but liquidation.trigger is ${t} with model ${m ?? "unset"}`
82269
83249
  );
82270
83250
  }
82271
- if (o.address && o.address !== o.address.toLowerCase())
82272
- fail("oracle-lowercase", "oracle.address must be lowercased");
83251
+ if (o.address && o.address !== termAddressKey(sheet.chainId, o.address))
83252
+ fail("oracle-lowercase", "oracle.address must be lowercased (EVM)");
82273
83253
  }
82274
83254
  const g = sheet.governance;
82275
83255
  if (g) {
@@ -82648,13 +83628,28 @@ function stampCapabilities(row) {
82648
83628
  row.capabilities = row.venueKind === "lending" ? lendingCapabilities(row) : vaultCapabilities(row);
82649
83629
  return row;
82650
83630
  }
83631
+ function nativeStandsIn(row) {
83632
+ const wrapped = getWrappedNativeAddressSafe(row.chainId);
83633
+ return !!wrapped && wrapped.toLowerCase() === String(row.asset?.address ?? "").toLowerCase() && isNativeWrapOneToOne(row.chainId);
83634
+ }
83635
+ var NO_NATIVE_PROVIDERS = /* @__PURE__ */ new Set(["gmx", "hypercore"]);
82651
83636
  function lendingCapabilities(row) {
82652
83637
  const caps = [];
83638
+ const native = nativeStandsIn(row) && !isLiquityFamily(row.venue) && !isFluid(row.venue);
83639
+ const fixedLendExit = isTermMax(row.venue) || isTerm(row.venue);
82653
83640
  if (row.availability.canDeposit) {
82654
- caps.push({ action: "deposit", acceptsPayAsset: true });
83641
+ caps.push({
83642
+ action: "deposit",
83643
+ acceptsPayAsset: true,
83644
+ acceptsNative: native
83645
+ });
82655
83646
  }
82656
83647
  if (row.availability.canWithdraw) {
82657
- caps.push({ action: "withdraw", acceptsReceiveAsset: true });
83648
+ caps.push({
83649
+ action: "withdraw",
83650
+ acceptsReceiveAsset: true,
83651
+ acceptsNative: native && !fixedLendExit
83652
+ });
82658
83653
  }
82659
83654
  return caps;
82660
83655
  }
@@ -82672,6 +83667,9 @@ var NON_4626_DEPOSIT_KINDS = /* @__PURE__ */ new Set([
82672
83667
  "frankencoin",
82673
83668
  "yieldbasis",
82674
83669
  "wren",
83670
+ // Vesper va* pools — `deposit(amount)` credits msg.sender only (mirrors the
83671
+ // worker's list, which had it and this one did not)
83672
+ "vesper",
82675
83673
  "hyperbeat",
82676
83674
  "native-wnlp",
82677
83675
  "bitway"
@@ -82712,7 +83710,8 @@ function swapRoutedCapabilities(row, opts) {
82712
83710
  action: "deposit",
82713
83711
  via: "swap",
82714
83712
  requires: ["slippage"],
82715
- acceptsPayAsset: true
83713
+ acceptsPayAsset: true,
83714
+ acceptsNative: nativeStandsIn(row)
82716
83715
  });
82717
83716
  }
82718
83717
  if (row.availability.canWithdraw) {
@@ -82720,7 +83719,8 @@ function swapRoutedCapabilities(row, opts) {
82720
83719
  action: "withdraw",
82721
83720
  via: "swap",
82722
83721
  requires: ["slippage"],
82723
- acceptsReceiveAsset: true
83722
+ acceptsReceiveAsset: true,
83723
+ acceptsNative: nativeStandsIn(row)
82724
83724
  });
82725
83725
  }
82726
83726
  return caps;
@@ -82743,21 +83743,33 @@ function vaultCapabilities(row) {
82743
83743
  // deposit — but ONLY for rows whose deposit is a plain synchronous
82744
83744
  // ERC-4626 call. Advertising it anywhere else builds a zap input that
82745
83745
  // 400s at submit, which is exactly what this flag existed to prevent.
82746
- acceptsPayAsset: acceptsVaultZap(row, provider)
83746
+ acceptsPayAsset: acceptsVaultZap(row, provider),
83747
+ // native for a wrapped-native deposit token is NOT a zap: the 4626 rows
83748
+ // take it through the composer, every single-token builder (Lagoon,
83749
+ // the non-4626 savings kinds, ERC-20-only LST mints) as a leading wrap
83750
+ acceptsNative: !NO_NATIVE_PROVIDERS.has(provider) && nativeStandsIn(row)
82747
83751
  });
82748
83752
  }
82749
83753
  if (!row.availability.canWithdraw) return caps;
82750
83754
  const mode = row.exit.mode;
82751
83755
  const isAsync = provider !== "hypercore" && (ASYNC_PROVIDERS.has(provider) || ASYNC_EXIT_MODES.has(mode));
82752
83756
  if (!isAsync) {
82753
- caps.push({ action: "withdraw", requires: withdrawRequires(provider) });
83757
+ caps.push({
83758
+ action: "withdraw",
83759
+ requires: withdrawRequires(provider),
83760
+ // the unwrap rides the composer's 4626 withdraw — the same rows the
83761
+ // deposit zap serves; the single-token exits have no unwrap leg yet
83762
+ acceptsNative: acceptsVaultZap(row, provider) && nativeStandsIn(row)
83763
+ });
82754
83764
  return caps;
82755
83765
  }
82756
83766
  if (mode === "fee-or-queued" && meta.instantRedeemEnabled !== false) {
82757
83767
  caps.push({
82758
83768
  action: "withdraw",
82759
83769
  requires: withdrawRequires(provider),
82760
- feeBps: num13(meta.withdrawFeeBps) ?? row.exit.feeBps
83770
+ feeBps: num13(meta.withdrawFeeBps) ?? row.exit.feeBps,
83771
+ // a fee-paying single-token exit: pays the vault's token only
83772
+ acceptsNative: false
82761
83773
  });
82762
83774
  }
82763
83775
  caps.push({
@@ -83075,6 +84087,6 @@ function earnPositionTotals(items) {
83075
84087
  };
83076
84088
  }
83077
84089
 
83078
- export { ApiBookSource, DEFAULT_MIDNIGHT_API, DEFAULT_OUTLIER_GUARD, DEFAULT_PROFILE_ID, DEFAULT_STALE_REJECT_SECONDS, DEFAULT_TERMMAX_API, DEFAULT_TERM_ORDER_STORE, DOLOMITE_ISO_ID_PREFIX, EARN_DESCRIPTIONS, EARN_LABELS, EARN_RATE_SOURCE_BY_PROVIDER, EMPTY_BALANCE, EXACTLY_LENDER_KEY, FLYING_TULIP_LENDER_KEY, FRACTION_RATE_PROVIDERS, GMX_API_HOSTS, GMX_READ_CONTRACTS, GMX_SUPPORTED_CHAINS, HYPERCORE_VAULT_REGISTRY, IDLE_MARKET_ID, INTERFACE_IDS, LAGOON_API_URL, LAGOON_CHAIN_IDS, MORPHO_LENS, MULTICALL_FAILURE, MaxParamThresholds, PASSTHROUGH_RATE_EPSILON, PENDLE_ASSETS_URL, PENDLE_CHAIN_IDS, PENDLE_MARKETS_URL, PREFIX_LENDERS, SDK_FRACTION_RATE_PROVIDERS, SPECTRA_NETWORKS, SPECTRA_RATE_MAX_PERCENT, SPECTRA_RATE_MIN_PERCENT, STABLECOIN_SYMBOLS, STCELO_MANAGER_ADDRESS, TELLER_CALLS_PER_BID, DECIMAL_BASE as TERMMAX_DECIMAL_BASE, TERMMAX_LIQUIDATION_PENALTY, TERMMAX_LIQUIDATION_WINDOW_SECS, TERMMAX_LIQUIDATOR_BONUS, TERMMAX_MARKETS_PER_CALL, TERMMAX_PARTIAL_CLOSE_FACTOR, TERMMAX_PARTIAL_LIQUIDATION_THRESHOLD_USD, TERM_ADAPTERS, TERM_PROFILES, TERM_SHEET_SCHEMA_VERSION, TermMaxApiSource, TermSubgraphSource, UPSHIFT_CHAIN_IDS, UPSHIFT_VAULTS_URL, VAULT_PROVIDERS, VAULT_PROVIDER_PROFILE, VAULT_PROVIDER_TRAITS, VAULT_SHARE_PRICE_PROBE, VAULT_VENUE_PREFIX, VOLATILE_VAULT_OVERRIDES, YEARN_CHAIN_IDS, YEARN_YDAEMON_BASE, __resetResupplyUserCaches, accountDepositListKey, accountWithdrawalListKey, appendSnapshot, applyEarnSanity, applyPositionDelta, attachImplications, attachPricesToFlashLiquidity, blockNumberFromTag, borrowDescription, borrowFindings, borrowHeadline, buildExposures2 as buildExposures, buildFluidFTokensCall, buildLendingPositionUid, buildLiquityUserCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildQueriesFromMeta, buildSumerAccumulators, buildSummaries, buildTellerUserCall, buildTermMaxUserCall, buildTermSheet, buildTermSheetsForGroup, buildVaultEarnUid, buildVaultLookup, buildVaultTermSheet, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyFreshness, classifyReliability, classifyVault, clearPendleMarketsCache, clearSpectraMarketsCache, collateralSymbolsByVenue, collectFeedObservations, computeBorrowDelta2 as computeBorrowDelta, computeCloseTradeDeltas, computeCollateralSwapDeltas, computeDebtSwapDeltas, computeDepositDelta2 as computeDepositDelta, computeEModeAnalysis, computeOpenTradeDeltas, computePostTradeMetrics, computeRepayDelta2 as computeRepayDelta, computeSumerBorrowDelta, computeSumerDepositDelta, computeSumerRepayDelta, computeSumerWaterfall, computeSumerWithdrawDelta, computeVaultApr, computeWithdrawDelta2 as computeWithdrawDelta, computeZapTradeDeltas, consensusReference, convertCoolerMarketsToResponse, convertDssMarketsToResponse, convertExactlyMarketsToResponse, convertFlyingTulipMarketsToResponse, convertFrankencoinMarketsToResponse, convertFraxlendPairsToResponse, convertInverseMarketsToResponse, convertLenderUserDataResult, convertLiquityMarketsToResponse, convertLlamaLendMarketsToResponse, convertResupplyMarketsToResponse, convertRiverMarketsToResponse, convertTellerMarketsToResponse, convertTermMarketsToResponse, convertTermMaxMarketsToResponse, convertUsddMarketsToResponse, createMarketUid, createMidnightBookSource, createMulticallRpcCall, createRawRpcCalls, createTermBookSource, createTermMaxDataSource, decodeListaMarkets, decodeMarkets, decodePackedListaUserDataset, decodePackedMorphoUserDataset, deriveBorrowTags, deriveSupplyTags, detectInterfaceKinds, dexResolverFor, disambiguateEarnNames, dolomiteVaultAddress, dssIlkBytes32, dssKeyParts, dssLenderKey, duration, earnDescription, earnLabel, earnMarketFromPool, earnMarketFromVault, earnMarketLabel, earnPositionFromLenderEntry, earnPositionFromVaultBalance, earnPositionTotals, earnRateAtMaturity, earnRowSubtitle, earnUidFromMarketUid, earnVaultTerms, earnVenueKind, emitterCoverage, encodeBalanceFetcherCalldata, enrichTermSheet, enrichmentIndexFromRows, enumerateEmitters, exactlyPairLtv, exactlyPenaltyRateToAprPercent, exactlyWadRateToPercent, feePhrase, feedKeyOf, feedStatKey, fetchCoolerMarkets, fetchDolomiteAccountNumbers, fetchDolomiteSubAccounts, fetchDssMarkets, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchExactlyMarkets, fetchFlashLiquidityForChain, fetchFluidDexState, fetchFluidFTokens, fetchFlyingTulipMarkets, fetchFrankencoinMarkets, fetchFraxlendPairs, fetchGeneralYields, fetchGeneralYieldsByMarketUid, fetchGmxExecutionFees, fetchGmxTickerPrices, fetchGmxVaults, fetchHypercoreVaults, fetchInverseMarkets, fetchLagoonApiVaults, fetchLagoonVaults, fetchLiquityMarkets, fetchListaVaultsFromChain, fetchLlamaLendMarkets, fetchMorphoUserBalances, fetchMorphoUserPositionMarkets, fetchMorphoVaults, fetchMorphoVaultsFromApi, fetchMorphoVaultsFromChain, fetchOraclePrices, fetchPendleApiAssets, fetchPendleApiMarkets, fetchPendlePrices, fetchPendlePtMarkets, fetchResupplyMarkets, fetchRiverMarkets, fetchSiloVaults, fetchSpectraApiMarkets, fetchSpectraPtMarkets, fetchTellerMarkets, fetchTermMarkets, fetchTermMaxMarkets, fetchTermStoreOrders, fetchTokenBalances, fetchTokenMetadata, fetchUpshiftApiVaults, fetchUpshiftVaults, fetchUsddMarkets, fetchYearnApiVaults, fetchYearnVaults, fillableRemaining, filterActiveLenders, filterLenderMeta, filterLendersByProtocol, finalizeInfo, findingsFor, formatRaw, frankencoinKeyParts, frankencoinLenderKey, fraxlendAssetPerCollateral, fraxlendKeyParts, fraxlendLenderKey, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, getCachedFluidDexState, getCachedLiquityTroves, getCachedTellerBids, getCachedTermMaxDiscovery, getCachedTermMaxMarket, getCachedTermMaxMarkets, getCoreValidators, getFluidFTokensConverter, getGmxApiHost, getGmxReadContracts, getGmxUserPositions, getHealthFactor, getHypercoreUserPositions, getHypercoreVaultRegistry, getLenderAssets, getLenderPublicData, getLenderPublicDataAll, getLenderPublicDataViaApi, getLenderUserDataMulti, getLenderUserDataResult, getLendersForChain, getLstDelegation, getLstValidators, getLstWithdrawalRegistry, getLstWithdrawalRequests, getMaxAmountClose, getMaxAmountCollateralSwap, getMaxAmountDebtSwap, getMaxAmountOpen, getMergedUserData, getMorphoTypeMarketConverter, getReadFailurePolicy, getResolvedDolomiteAccountNumbers, getResolvedDolomiteSubAccounts, getStCeloValidatorGroups, getSubAccountAddress, getSubAccountIndex, getTermProfile, getVaultPublicDataAll, getVaultWithdrawalRequests, hasCritical, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasPendleMarkets, hasSpectraMarkets, hasUpshiftVaults, hasYearnVaults, ilkToKeySegment, implausibleRatePercent, injectLenderInfoIntoEntries, inverseKeyParts, inverseLenderKey, isBoundNeed, isFailedCall, isIlliquid, isLendingPosition, isLiveMarket as isLivePendleMarket, isLiveSpectraMarket, isMaturedTerm, isSecondaryMarketOnly, isStablecoinSymbol, isUnearnableEarnRate, isUnrealizableEarnRate, isVaultPosition, isVaultVenue, isYearnV3, keySegmentToIlk, keysFromMaps, lenderApiOnly, lenderFamily, liquityCandidateTroveIds, liquityKeyParts, liquityLenderKey, llamaLendKeyParts, llamaLendLenderKey, marketKeysOf, meetsLiquidityFloor, mergeDeep, multicall3Abi2 as multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, organizeUserQueries, parseBalanceFetcherResult, parseDolomiteSubAccountId, parseEarnUid, parseLenderKey, parseMergedResult, parseMulticallRpcResponses, parseExpirySeconds as parsePendleExpirySeconds, parseRawRpcBatchResponses, parseRawRpcResponses, parseCurveFee as parseSpectraCurveFee, parsePtRate as parseSpectraPtRate, parseTermMaxLtv, parseTokenBalanceResult, pct, assetKey as pendleAssetKey, pickPool as pickSpectraPool, positivePart2 as positivePart, predictInverseEscrow, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, probeAaveFeedTimestamps, pruneFeedStats, rankFindings, ratePercent, readUserPositions, readVaultSharePrices, rejectOutliers as rejectPriceOutliers, repairImpossibleTvl, resolveAdapter, resolveDerivation, resolveDolomiteRowIdentity, resolveEarnIdentity, resolveModeConfig, resolveStCeloDepositGroup, resolveVaultProfileId, resupplyKeyParts, resupplyLenderKey, resupplyMarketLabel, riverKeyParts, riverLenderKey, sanePercent as saneSpectraPercent, savingsAddresses, savingsBalanceKind, secondaryMarketVault, selectAssetGroupPrices, setMysticApiKey, shortDate, spectraAddress, spectraNetwork, spectraPoolsUrl, splitChainScopedAddress as splitPendleChainScopedAddress, stampCapabilities, stampEarnSubtitles, stampVaultClassification, stampVaultTermSheets, stripLeadingBrand, subAccountsOf, supplyDescription, supplyFindings, supplyHeadline, swapRoutedProvidersArePriceConsistent, tellerBpsToPercent, tellerImpliedLtv, tellerLenderKey, tellerPoolFromLenderKey, termApiBaseUrl, termLenderKey, termMaxApiBase, borrowNif as termMaxBorrowNif, curveApr as termMaxCurveApr, curveAprNumber as termMaxCurveAprNumber, daysToMaturity as termMaxDaysToMaturity, lendNif as termMaxLendNif, mintGtFeeRatio as termMaxMintGtFeeRatio, ratioToNumber as termMaxRatioToNumber, ratioToPercent as termMaxRatioToPercent, termOfferRateToAprPct, termOrderStoreBaseUrl, tickToAprNumber, tickToPrice, toDigest, toDolomiteSubAccountId, toTermFillNow, toTermSheetInput, toVaultTermInput, trancheFromCounterparty, tryParseEarnUid, unflattenLenderData, updateFeedStats, usdValue, usddIlkBytes32, usddKeyParts, usddLenderKey, validateTermSheet, validateTermSheets, validateUserData, vaultSharesToAssets, vaultTermInputFromEarnMarket, vaultTermInputFromSourceRow, vaultTraits, vaultVenue, venueBrand, venueBrandKey, withMaturityLabel, withTrancheLabel };
84090
+ export { ApiBookSource, DEFAULT_MIDNIGHT_API, DEFAULT_OUTLIER_GUARD, DEFAULT_PROFILE_ID, DEFAULT_STALE_REJECT_SECONDS, DEFAULT_TERMMAX_API, DEFAULT_TERM_ORDER_STORE, DOLOMITE_ISO_ID_PREFIX, EARN_DESCRIPTIONS, EARN_LABELS, EARN_RATE_SOURCE_BY_PROVIDER, EMPTY_BALANCE, EXACTLY_LENDER_KEY, FLYING_TULIP_LENDER_KEY, FRACTION_RATE_PROVIDERS, GMX_API_HOSTS, GMX_READ_CONTRACTS, GMX_SUPPORTED_CHAINS, HYPERCORE_VAULT_REGISTRY, IDLE_MARKET_ID, INTERFACE_IDS, LAGOON_API_URL, LAGOON_CHAIN_IDS, MORPHO_LENS, MULTICALL_FAILURE, MaxParamThresholds, NON_EVM_VAULT_PROVIDERS, PASSTHROUGH_RATE_EPSILON, PENDLE_ASSETS_URL, PENDLE_CHAIN_IDS, PENDLE_MARKETS_URL, PREFIX_LENDERS, SDK_FRACTION_RATE_PROVIDERS, SPECTRA_NETWORKS, SPECTRA_RATE_MAX_PERCENT, SPECTRA_RATE_MIN_PERCENT, STABLECOIN_SYMBOLS, STCELO_MANAGER_ADDRESS, TELLER_CALLS_PER_BID, DECIMAL_BASE as TERMMAX_DECIMAL_BASE, TERMMAX_LIQUIDATION_PENALTY, TERMMAX_LIQUIDATION_WINDOW_SECS, TERMMAX_LIQUIDATOR_BONUS, TERMMAX_MARKETS_PER_CALL, TERMMAX_PARTIAL_CLOSE_FACTOR, TERMMAX_PARTIAL_LIQUIDATION_THRESHOLD_USD, TERM_ADAPTERS, TERM_PROFILES, TERM_SHEET_SCHEMA_VERSION, TermMaxApiSource, TermSubgraphSource, UPSHIFT_CHAIN_IDS, UPSHIFT_VAULTS_URL, VAULT_PROVIDERS, VAULT_PROVIDER_PROFILE, VAULT_PROVIDER_TRAITS, VAULT_SHARE_PRICE_PROBE, VAULT_VENUE_PREFIX, VOLATILE_VAULT_OVERRIDES, YEARN_CHAIN_IDS, YEARN_YDAEMON_BASE, __resetResupplyUserCaches, accountDepositListKey, accountWithdrawalListKey, appendSnapshot, applyEarnSanity, applyPositionDelta, attachImplications, attachPricesToFlashLiquidity, blockNumberFromTag, borrowDescription, borrowFindings, borrowHeadline, buildExposures2 as buildExposures, buildFluidFTokensCall, buildLendingPositionUid, buildLiquityUserCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildQueriesFromMeta, buildSumerAccumulators, buildSummaries, buildTellerUserCall, buildTermMaxUserCall, buildTermSheet, buildTermSheetsForGroup, buildVaultEarnUid, buildVaultLookup, buildVaultTermSheet, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyFreshness, classifyReliability, classifyVault, clearPendleMarketsCache, clearSpectraMarketsCache, collateralSymbolsByVenue, collectFeedObservations, computeBorrowDelta2 as computeBorrowDelta, computeCloseTradeDeltas, computeCollateralSwapDeltas, computeDebtSwapDeltas, computeDepositDelta2 as computeDepositDelta, computeEModeAnalysis, computeOpenTradeDeltas, computePostTradeMetrics, computeRepayDelta2 as computeRepayDelta, computeSumerBorrowDelta, computeSumerDepositDelta, computeSumerRepayDelta, computeSumerWaterfall, computeSumerWithdrawDelta, computeVaultApr, computeWithdrawDelta2 as computeWithdrawDelta, computeZapTradeDeltas, consensusReference, convertCoolerMarketsToResponse, convertDssMarketsToResponse, convertExactlyMarketsToResponse, convertFlyingTulipMarketsToResponse, convertFrankencoinMarketsToResponse, convertFraxlendPairsToResponse, convertInverseMarketsToResponse, convertLenderUserDataResult, convertLiquityMarketsToResponse, convertLlamaLendMarketsToResponse, convertResupplyMarketsToResponse, convertRiverMarketsToResponse, convertTellerMarketsToResponse, convertTermMarketsToResponse, convertTermMaxMarketsToResponse, convertUsddMarketsToResponse, createMarketUid, createMidnightBookSource, createMultiAccountTypeUserState, createMulticallRpcCall, createRawRpcCalls, createTermBookSource, createTermMaxDataSource, decodeListaMarkets, decodeMarkets, decodePackedListaUserDataset, decodePackedMorphoUserDataset, deriveBorrowTags, deriveSupplyTags, detectInterfaceKinds, dexResolverFor, disambiguateEarnNames, dolomiteVaultAddress, dssIlkBytes32, dssKeyParts, dssLenderKey, duration, earnDescription, earnLabel, earnMarketFromPool, earnMarketFromVault, earnMarketLabel, earnPositionFromLenderEntry, earnPositionFromVaultBalance, earnPositionTotals, earnRateAtMaturity, earnRowSubtitle, earnUidFromMarketUid, earnVaultTerms, earnVenueKind, emitterCoverage, encodeBalanceFetcherCalldata, enrichTermSheet, enrichmentIndexFromRows, enumerateEmitters, exactlyPairLtv, exactlyPenaltyRateToAprPercent, exactlyWadRateToPercent, feePhrase, feedKeyOf, feedStatKey, fetchCoolerMarkets, fetchDolomiteAccountNumbers, fetchDolomiteSubAccounts, fetchDssMarkets, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchExactlyMarkets, fetchFlashLiquidityForChain, fetchFluidDexState, fetchFluidFTokens, fetchFlyingTulipMarkets, fetchFrankencoinMarkets, fetchFraxlendPairs, fetchGeneralYields, fetchGeneralYieldsByMarketUid, fetchGmxExecutionFees, fetchGmxTickerPrices, fetchGmxVaults, fetchHypercoreVaults, fetchInverseMarkets, fetchLagoonApiVaults, fetchLagoonVaults, fetchLiquityMarkets, fetchListaVaultsFromChain, fetchLlamaLendMarkets, fetchMorphoUserBalances, fetchMorphoUserPositionMarkets, fetchMorphoVaults, fetchMorphoVaultsFromApi, fetchMorphoVaultsFromChain, fetchOraclePrices, fetchPendleApiAssets, fetchPendleApiMarkets, fetchPendlePrices, fetchPendlePtMarkets, fetchResupplyMarkets, fetchRiverMarkets, fetchSiloVaults, fetchSpectraApiMarkets, fetchSpectraPtMarkets, fetchTellerMarkets, fetchTermMarkets, fetchTermMaxMarkets, fetchTermStoreOrders, fetchTokenBalances, fetchTokenMetadata, fetchUpshiftApiVaults, fetchUpshiftVaults, fetchUsddMarkets, fetchYearnApiVaults, fetchYearnVaults, fillableRemaining, filterActiveLenders, filterLenderMeta, filterLendersByProtocol, finalizeInfo, findingsFor, formatRaw, frankencoinKeyParts, frankencoinLenderKey, fraxlendAssetPerCollateral, fraxlendKeyParts, fraxlendLenderKey, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, getCachedFluidDexState, getCachedLiquityTroves, getCachedTellerBids, getCachedTermMaxDiscovery, getCachedTermMaxMarket, getCachedTermMaxMarkets, getCoreValidators, getFluidFTokensConverter, getGmxApiHost, getGmxReadContracts, getGmxUserPositions, getHealthFactor, getHypercoreUserPositions, getHypercoreVaultRegistry, getLenderAssets, getLenderPublicData, getLenderPublicDataAll, getLenderPublicDataViaApi, getLenderUserDataMulti, getLenderUserDataResult, getLendersForChain, getLstDelegation, getLstValidators, getLstWithdrawalRegistry, getLstWithdrawalRequests, getMaxAmountClose, getMaxAmountCollateralSwap, getMaxAmountDebtSwap, getMaxAmountOpen, getMergedUserData, getMorphoTypeMarketConverter, getReadFailurePolicy, getResolvedDolomiteAccountNumbers, getResolvedDolomiteSubAccounts, getStCeloValidatorGroups, getSubAccountAddress, getSubAccountIndex, getTermProfile, getVaultPublicDataAll, getVaultWithdrawalRequests, hasCritical, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasPendleMarkets, hasSpectraMarkets, hasUpshiftVaults, hasYearnVaults, ilkToKeySegment, implausibleRatePercent, injectLenderInfoIntoEntries, inverseKeyParts, inverseLenderKey, isBoundNeed, isFailedCall, isIlliquid, isLenderVenueKey, isLendingPosition, isLiveMarket as isLivePendleMarket, isLiveSpectraMarket, isMaturedTerm, isSecondaryMarketOnly, isStablecoinSymbol, isUnearnableEarnRate, isUnrealizableEarnRate, isVaultPosition, isVaultVenue, isYearnV3, keySegmentToIlk, keysFromMaps, lenderApiOnly, lenderFamily, liquityCandidateTroveIds, liquityKeyParts, liquityLenderKey, llamaLendKeyParts, llamaLendLenderKey, marketKeysOf, meetsLiquidityFloor, mergeDeep, multicall3Abi2 as multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, organizeUserQueries, parseBalanceFetcherResult, parseDolomiteSubAccountId, parseEarnUid, parseLenderKey, parseMergedResult, parseMulticallRpcResponses, parseExpirySeconds as parsePendleExpirySeconds, parseRawRpcBatchResponses, parseRawRpcResponses, parseCurveFee as parseSpectraCurveFee, parsePtRate as parseSpectraPtRate, parseTermMaxLtv, parseTokenBalanceResult, pct, assetKey as pendleAssetKey, pickPool as pickSpectraPool, positivePart2 as positivePart, predictInverseEscrow, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, probeAaveFeedTimestamps, pruneFeedStats, rankFindings, ratePercent, readUserPositions, readVaultSharePrices, rejectOutliers as rejectPriceOutliers, repairImpossibleTvl, resolveAdapter, resolveDerivation, resolveDolomiteRowIdentity, resolveEarnIdentity, resolveModeConfig, resolveStCeloDepositGroup, resolveVaultProfileId, resupplyKeyParts, resupplyLenderKey, resupplyMarketLabel, riverKeyParts, riverLenderKey, sanePercent as saneSpectraPercent, savingsAddresses, savingsBalanceKind, secondaryMarketVault, selectAssetGroupPrices, setMysticApiKey, shortDate, spectraAddress, spectraNetwork, spectraPoolsUrl, splitChainScopedAddress as splitPendleChainScopedAddress, stampCapabilities, stampEarnSubtitles, stampVaultClassification, stampVaultTermSheets, stripLeadingBrand, subAccountsOf, supplyDescription, supplyFindings, supplyHeadline, swapRoutedProvidersArePriceConsistent, tellerBpsToPercent, tellerImpliedLtv, tellerLenderKey, tellerPoolFromLenderKey, termApiBaseUrl, termLenderKey, termMaxApiBase, borrowNif as termMaxBorrowNif, curveApr as termMaxCurveApr, curveAprNumber as termMaxCurveAprNumber, daysToMaturity as termMaxDaysToMaturity, lendNif as termMaxLendNif, mintGtFeeRatio as termMaxMintGtFeeRatio, ratioToNumber as termMaxRatioToNumber, ratioToPercent as termMaxRatioToPercent, termOfferRateToAprPct, termOrderStoreBaseUrl, tickToAprNumber, tickToPrice, toDigest, toDolomiteSubAccountId, toTermFillNow, toTermSheetInput, toVaultTermInput, trancheFromCounterparty, tryParseEarnUid, unflattenLenderData, updateFeedStats, usdValue, usddIlkBytes32, usddKeyParts, usddLenderKey, validateTermSheet, validateTermSheets, validateUserData, vaultSharesToAssets, vaultTermInputFromEarnMarket, vaultTermInputFromSourceRow, vaultTraits, vaultVenue, venueBrand, venueBrandKey, withMaturityLabel, withTrancheLabel };
83079
84091
  //# sourceMappingURL=index.js.map
83080
84092
  //# sourceMappingURL=index.js.map