@1delta/margin-fetcher 5.0.91 → 5.0.93

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;
@@ -50765,7 +50804,7 @@ var BITWAY_LEGS2 = [
50765
50804
  "USDT",
50766
50805
  "0x5c4a6903732532eeb3ae0803e062d8ae25d52bd1",
50767
50806
  "0x2b8464ffb2b77de64cfefdeb00ad925576f157cb",
50768
- "the Absolute Return strategy (0.5% instant-exit fee)"
50807
+ "Absolute Return strategy (0.5% instant-exit fee)"
50769
50808
  ],
50770
50809
  [
50771
50810
  "bwU",
@@ -50775,7 +50814,7 @@ var BITWAY_LEGS2 = [
50775
50814
  "U",
50776
50815
  "0x5c4a6903732532eeb3ae0803e062d8ae25d52bd1",
50777
50816
  "0x2b8464ffb2b77de64cfefdeb00ad925576f157cb",
50778
- "the Absolute Return strategy (0.5% instant-exit fee)"
50817
+ "Absolute Return strategy (0.5% instant-exit fee)"
50779
50818
  ],
50780
50819
  [
50781
50820
  "bwBTW",
@@ -50785,7 +50824,7 @@ var BITWAY_LEGS2 = [
50785
50824
  "BTW",
50786
50825
  "0x5c4a6903732532eeb3ae0803e062d8ae25d52bd1",
50787
50826
  "0x2b8464ffb2b77de64cfefdeb00ad925576f157cb",
50788
- "the Absolute Return strategy (0.5% instant-exit fee). The rate is denominated in BTW, Bitway's own volatile token \u2014 not in dollars"
50827
+ "Absolute Return strategy (0.5% instant-exit fee). The rate is denominated in BTW, Bitway's own volatile token \u2014 not in dollars"
50789
50828
  ],
50790
50829
  [
50791
50830
  "BTWUSDT",
@@ -50795,7 +50834,7 @@ var BITWAY_LEGS2 = [
50795
50834
  "USDT",
50796
50835
  "0xb82e32062c773c7748776c06fdb11b92edae3b63",
50797
50836
  "0xfc8e6b1ab1a4c37724f8bc797730afa8d01d04ef",
50798
- "the Core Alpha strategy (no instant-exit fee live; ~1M per-user stake cap)"
50837
+ "Core Alpha strategy (no instant-exit fee live; ~1M per-user stake cap)"
50799
50838
  ],
50800
50839
  [
50801
50840
  "BTWUSD1",
@@ -50805,7 +50844,7 @@ var BITWAY_LEGS2 = [
50805
50844
  "USD1",
50806
50845
  "0xb82e32062c773c7748776c06fdb11b92edae3b63",
50807
50846
  "0xfc8e6b1ab1a4c37724f8bc797730afa8d01d04ef",
50808
- "the Core Alpha strategy (no instant-exit fee live; ~1M per-user stake cap)"
50847
+ "Core Alpha strategy (no instant-exit fee live; ~1M per-user stake cap)"
50809
50848
  ],
50810
50849
  [
50811
50850
  "BTWU",
@@ -50815,7 +50854,7 @@ var BITWAY_LEGS2 = [
50815
50854
  "U",
50816
50855
  "0xb82e32062c773c7748776c06fdb11b92edae3b63",
50817
50856
  "0xfc8e6b1ab1a4c37724f8bc797730afa8d01d04ef",
50818
- "the Core Alpha strategy (no instant-exit fee live; ~1M per-user stake cap)"
50857
+ "Core Alpha strategy (no instant-exit fee live; ~1M per-user stake cap)"
50819
50858
  ]
50820
50859
  ];
50821
50860
  var BITWAY_ENTRIES = {
@@ -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));
@@ -76519,6 +76563,134 @@ var TERM_PROFILES = [
76519
76563
  },
76520
76564
  docsUrl: "https://docs.morpho.org/morpho/concepts/markets"
76521
76565
  }),
76566
+ // ── Solana lenders ───────────────────────────────────────────────────────
76567
+ // Ported from margin-fetcher-sol's profiles; the facts behind each line are
76568
+ // verified against the deployed programs in UNIFIED_API_AUDIT.md §9.
76569
+ // Kamino is a crossing of Morpho and Aave V3: a market is PERMISSIONLESSLY
76570
+ // deployed and typically lends one asset against a set of collaterals (the
76571
+ // Morpho half), while inside the market a multi-asset pool with elevation
76572
+ // groups prices the pairs (the Aave half).
76573
+ P({
76574
+ id: "kamino.klend@v1",
76575
+ name: "Kamino Lend market (variable-rate pool)",
76576
+ family: "kamino",
76577
+ docsUrl: "https://docs.kamino.finance/",
76578
+ supply: {
76579
+ 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.",
76580
+ implications: [
76581
+ "Your yield is not fixed \u2014 it rises and falls with borrowing demand.",
76582
+ "If utilization reaches 100 %, withdrawals are blocked until borrowers repay or new deposits arrive.",
76583
+ "A reserve may rate-limit withdrawals with a rolling net-withdrawal cap.",
76584
+ "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."
76585
+ ]
76586
+ },
76587
+ borrow: {
76588
+ 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.",
76589
+ implications: [
76590
+ "The rate can change slot to slot \u2014 a cheap borrow can become expensive.",
76591
+ "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.",
76592
+ "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.",
76593
+ "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.",
76594
+ "Markets with auto-deleverage enabled can lower the liquidation threshold over time and unwind positions without a price move.",
76595
+ "Parameters are set by the market owner and can change without a protocol-wide vote."
76596
+ ]
76597
+ }
76598
+ }),
76599
+ P({
76600
+ id: "jupiter-lend.vault@v1",
76601
+ name: "Jupiter Lend vault (Fluid T1 on Solana)",
76602
+ family: "jupiter-lend",
76603
+ docsUrl: "https://developers.jup.ag/docs/lend",
76604
+ supply: {
76605
+ 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.",
76606
+ implications: [
76607
+ "A withdrawal larger than the current limit cannot clear in one transaction \u2014 the limit grows toward the position over ~6 hours.",
76608
+ "Your collateral shares one liquidity pool with every other vault and earn token on that asset."
76609
+ ]
76610
+ },
76611
+ borrow: {
76612
+ 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.",
76613
+ implications: [
76614
+ "The rate moves with the layer's utilization of the borrowed asset, block to block.",
76615
+ "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.",
76616
+ "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."
76617
+ ]
76618
+ }
76619
+ }),
76620
+ P({
76621
+ id: "save.pool@v1",
76622
+ name: "Save (ex-Solend) lending pool",
76623
+ family: "save",
76624
+ docsUrl: "https://docs.save.finance/",
76625
+ supply: {
76626
+ 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.",
76627
+ implications: [
76628
+ "Your yield is not fixed \u2014 it moves with borrowing demand, slot to slot.",
76629
+ "If the reserve is fully lent out, withdrawals wait for repayments or new deposits; permissionless pools have been left pinned there permanently.",
76630
+ "A market-wide outflow limiter can cap how much leaves the whole pool in a rolling window.",
76631
+ "Bad debt in the market is socialised to its depositors; the pool owner decides which collaterals the pool accepts."
76632
+ ]
76633
+ },
76634
+ borrow: {
76635
+ 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.",
76636
+ implications: [
76637
+ "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.",
76638
+ "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.",
76639
+ "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.",
76640
+ "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.",
76641
+ "Parameters are set by the market owner and can change without a protocol-wide vote."
76642
+ ]
76643
+ }
76644
+ }),
76645
+ P({
76646
+ id: "loopscale.creditbook@v1",
76647
+ name: "Loopscale credit order book (fixed-rate, fixed-duration)",
76648
+ family: "loopscale",
76649
+ docsUrl: "https://docs.loopscale.com/",
76650
+ supply: {
76651
+ 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.",
76652
+ implications: [
76653
+ "Your rate is fixed for the term \u2014 it does not move with utilization, because there is no pool.",
76654
+ "Before maturity your claim can only leave by selling the ledger to another lender at a negotiated price; there may be no buyer.",
76655
+ "A curated vault charges a fee on the interest it earns for you, and can park idle deposits in a third-party pool.",
76656
+ "Vault curators choose the accepted collateral and its LTV (behind a 24-hour timelock) and set rates and fees immediately."
76657
+ ]
76658
+ },
76659
+ borrow: {
76660
+ 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.",
76661
+ implications: [
76662
+ "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.",
76663
+ "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.",
76664
+ "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.",
76665
+ "Auto-refinance is a best effort: if no lender rests an offer at maturity, the grace period is your only cover before liquidation."
76666
+ ]
76667
+ }
76668
+ }),
76669
+ P({
76670
+ id: "project0.group@v1",
76671
+ name: "Project 0 (marginfi v2) lending group",
76672
+ family: "project0",
76673
+ docsUrl: "https://docs.0.xyz/",
76674
+ supply: {
76675
+ 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.",
76676
+ implications: [
76677
+ "Your yield is not fixed \u2014 it moves with borrowing demand, and accrues as simple interest between touches of the bank.",
76678
+ "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.",
76679
+ "On a wrapped bank you hold shares of another venue; its risks, rates and exits apply on top.",
76680
+ "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."
76681
+ ]
76682
+ },
76683
+ borrow: {
76684
+ 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.",
76685
+ implications: [
76686
+ "The rate can change at any touch of the bank and is quoted on a 365-day year, simple interest.",
76687
+ "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.",
76688
+ "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.",
76689
+ "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.",
76690
+ "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."
76691
+ ]
76692
+ }
76693
+ }),
76522
76694
  // ── Vaults ───────────────────────────────────────────────────────────────
76523
76695
  P({
76524
76696
  id: "vault.lending@v1",
@@ -76698,6 +76870,7 @@ function resolveVaultProfileId(provider, solvency) {
76698
76870
 
76699
76871
  // src/terms/types.ts
76700
76872
  var TERM_SHEET_SCHEMA_VERSION = 1;
76873
+ var termAddressKey = (chainId, address) => chainId === void 0 || isEvmChainId(String(chainId)) ? address.toLowerCase() : address;
76701
76874
 
76702
76875
  // src/terms/buildTermSheet.ts
76703
76876
  var isNum = (v) => typeof v === "number" && Number.isFinite(v);
@@ -76705,7 +76878,10 @@ var clamp013 = (v) => Math.max(0, Math.min(1, v));
76705
76878
  function assetRef(input, now) {
76706
76879
  const a = input.asset ?? {};
76707
76880
  const chainId = String(a.chainId ?? input.chainId);
76708
- const address = String(a.address ?? input.underlying ?? "").toLowerCase();
76881
+ const address = termAddressKey(
76882
+ chainId,
76883
+ String(a.address ?? input.underlying ?? "")
76884
+ );
76709
76885
  return {
76710
76886
  chainId,
76711
76887
  address,
@@ -76734,7 +76910,10 @@ function instrumentOf(props, chainId, address, now) {
76734
76910
  const bridged = typeof pendle.bridgedFrom === "string" && pendle.bridgedFrom;
76735
76911
  const origin = pendle.origin && typeof pendle.origin.chainId === "string" && typeof pendle.origin.address === "string" ? {
76736
76912
  chainId: String(pendle.origin.chainId),
76737
- address: String(pendle.origin.address).toLowerCase()
76913
+ address: termAddressKey(
76914
+ String(pendle.origin.chainId),
76915
+ String(pendle.origin.address)
76916
+ )
76738
76917
  } : void 0;
76739
76918
  const originChain = origin?.chainId ?? (bridged ? PENDLE_ORIGIN_CHAIN_BY_CODE[bridged] : void 0);
76740
76919
  return {
@@ -76796,7 +76975,10 @@ function rewardTerms(input, side) {
76796
76975
  if (!apr) continue;
76797
76976
  const isPoints = r.kind === "points" || !r.asset;
76798
76977
  out.push({
76799
- asset: r.asset ? { chainId: input.chainId, address: String(r.asset).toLowerCase() } : void 0,
76978
+ asset: r.asset ? {
76979
+ chainId: input.chainId,
76980
+ address: termAddressKey(input.chainId, String(r.asset))
76981
+ } : void 0,
76800
76982
  kind: isPoints ? "points" : "token",
76801
76983
  apr,
76802
76984
  side,
@@ -77278,6 +77460,26 @@ function buildCoverage(sheet) {
77278
77460
  pending: Object.keys(pending).length ? pending : void 0
77279
77461
  };
77280
77462
  }
77463
+ function mergeAdapterCoverage(base, patch) {
77464
+ if (!patch) return base;
77465
+ const present = new Set(base.present);
77466
+ const pending = { ...base.pending ?? {} };
77467
+ const notApplicable = {
77468
+ ...base.notApplicable ?? {}
77469
+ };
77470
+ for (const [k, v] of Object.entries(patch.pending ?? {}))
77471
+ if (typeof v === "string" && !present.has(k)) pending[k] = v;
77472
+ for (const [k, v] of Object.entries(patch.notApplicable ?? {}))
77473
+ if (typeof v === "string" && !present.has(k)) {
77474
+ notApplicable[k] = v;
77475
+ delete pending[k];
77476
+ }
77477
+ return {
77478
+ present: base.present,
77479
+ notApplicable: Object.keys(notApplicable).length ? notApplicable : void 0,
77480
+ pending: Object.keys(pending).length ? pending : void 0
77481
+ };
77482
+ }
77281
77483
  function buildTermSheet(input, opts = {}) {
77282
77484
  const now = opts.now ?? Math.floor(Date.now() / 1e3);
77283
77485
  const siblings = opts.siblings ?? [];
@@ -77304,7 +77506,10 @@ function buildTermSheet(input, opts = {}) {
77304
77506
  if (merged[side] && !base[side]) merged[side] = void 0;
77305
77507
  }
77306
77508
  const withInfo = finalizeInfo(merged);
77307
- withInfo.coverage = buildCoverage(withInfo);
77509
+ withInfo.coverage = mergeAdapterCoverage(
77510
+ buildCoverage(withInfo),
77511
+ opts.patch?.coverage
77512
+ );
77308
77513
  return withInfo;
77309
77514
  }
77310
77515
 
@@ -78058,8 +78263,6 @@ var FALLBACK_TRAITS = {
78058
78263
  hasDecomposableBacking: false,
78059
78264
  hasUtilization: false
78060
78265
  };
78061
-
78062
- // src/earn/uid.ts
78063
78266
  var VAULT_VENUE_PREFIX = "vault.";
78064
78267
  function isVaultVenue(uidOrVenue) {
78065
78268
  return uidOrVenue.startsWith(VAULT_VENUE_PREFIX);
@@ -78073,7 +78276,7 @@ function buildVaultEarnUid(provider, chainId, address) {
78073
78276
  `Invalid earnUid parameters: provider=${provider}, chainId=${chainId}, address=${address}`
78074
78277
  );
78075
78278
  }
78076
- return `${vaultVenue(provider)}:${chainId}:${address.toLowerCase()}`;
78279
+ return `${vaultVenue(provider)}:${chainId}:${refKey(chainId, address)}`;
78077
78280
  }
78078
78281
  function earnUidFromMarketUid(marketUid) {
78079
78282
  const parts = splitUid(marketUid);
@@ -78102,9 +78305,10 @@ function parseEarnUid(earnUid, knownProviders) {
78102
78305
  kind: "lending",
78103
78306
  venue,
78104
78307
  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(),
78308
+ // Canonicalized like `normalizeMarketUid` / `createMarketUid`: lower-cased
78309
+ // on EVM (harmless for Dolomite's integer id), VERBATIM elsewhere — a
78310
+ // base58 ref is case-significant.
78311
+ ref: refKey(chainId, ref),
78108
78312
  marketUid: earnUid
78109
78313
  };
78110
78314
  }
@@ -78122,7 +78326,7 @@ function parseEarnUid(earnUid, knownProviders) {
78122
78326
  venue,
78123
78327
  provider,
78124
78328
  chainId,
78125
- address: ref.toLowerCase()
78329
+ address: refKey(chainId, ref)
78126
78330
  };
78127
78331
  }
78128
78332
  function tryParseEarnUid(earnUid, knownProviders) {
@@ -78143,6 +78347,7 @@ function splitUid(uid) {
78143
78347
  if (!venue || !chainId || !ref) return void 0;
78144
78348
  return { venue, chainId, ref };
78145
78349
  }
78350
+ var refKey = (chainId, ref) => isEvmChainId(chainId) ? ref.toLowerCase() : ref;
78146
78351
  var VENUE_KIND_LABELS = {
78147
78352
  lending: "Lending markets",
78148
78353
  vault: "Vaults"
@@ -79020,11 +79225,27 @@ function toVaultTermInput(vault, provider, chainId) {
79020
79225
  exposures: Array.isArray(row.exposures) ? row.exposures : void 0
79021
79226
  };
79022
79227
  }
79228
+ function savingsCuration(provider, chainId, address) {
79229
+ if (provider !== "savings") return {};
79230
+ const lc2 = address.toLowerCase();
79231
+ const e = getSavingsRegistry(chainId).find((x) => x.address === lc2);
79232
+ if (!e) return {};
79233
+ return {
79234
+ // `''` is how an entry says "no curated copy"; it must not beat the
79235
+ // template, so it is normalized to absent.
79236
+ description: e.description || void 0,
79237
+ solvency: e.solvency,
79238
+ accrual: e.accrual,
79239
+ yieldWarmupSeconds: e.yieldWarmupSeconds,
79240
+ needsDepositApproval: e.needsDepositApproval
79241
+ };
79242
+ }
79023
79243
  function vaultTermInputFromEarnMarket(m) {
79024
79244
  if (m.venueKind !== "vault") return void 0;
79025
79245
  const provider = m.venue.startsWith(VAULT_VENUE_PREFIX) ? m.venue.slice(VAULT_VENUE_PREFIX.length) : void 0;
79026
79246
  if (!provider) return void 0;
79027
79247
  const meta = m.providerMeta ?? {};
79248
+ const curated = savingsCuration(provider, m.chainId, m.ref);
79028
79249
  return {
79029
79250
  provider,
79030
79251
  chainId: m.chainId,
@@ -79033,7 +79254,7 @@ function vaultTermInputFromEarnMarket(m) {
79033
79254
  name: m.name,
79034
79255
  brand: m.brand,
79035
79256
  curatorName: m.brand,
79036
- description: str7(meta.description),
79257
+ description: str7(meta.description) ?? curated.description,
79037
79258
  asset: {
79038
79259
  chainId: m.chainId,
79039
79260
  address: m.asset.address,
@@ -79063,9 +79284,9 @@ function vaultTermInputFromEarnMarket(m) {
79063
79284
  swapFeeRate: num14(meta.feeRate),
79064
79285
  redemptionDiscountBps: num14(meta.redemptionDiscountBps),
79065
79286
  instantRedeemEnabled: bool2(meta.instantRedeemEnabled),
79066
- yieldWarmupSeconds: num14(meta.yieldWarmupSeconds),
79067
- accrual: str7(meta.accrual),
79068
- needsDepositApproval: bool2(meta.needsDepositApproval),
79287
+ yieldWarmupSeconds: num14(meta.yieldWarmupSeconds) ?? curated.yieldWarmupSeconds,
79288
+ accrual: str7(meta.accrual) ?? curated.accrual,
79289
+ needsDepositApproval: bool2(meta.needsDepositApproval) ?? curated.needsDepositApproval,
79069
79290
  // `canDeposit` already folds in the cap, the pause and the gate, so it is
79070
79291
  // the authoritative answer — but the REASON is what a disabled CTA renders,
79071
79292
  // and that only survives in the raw fields.
@@ -79083,7 +79304,7 @@ function vaultTermInputFromEarnMarket(m) {
79083
79304
  curator: str7(meta.curator),
79084
79305
  guardian: str7(meta.guardian),
79085
79306
  feeRecipient: str7(meta.feeRecipient),
79086
- solvency: m.risk?.counterparty,
79307
+ solvency: m.risk?.counterparty ?? curated.solvency,
79087
79308
  navOracle: str7(meta.navOracle),
79088
79309
  yieldProfile: m.risk?.yieldProfile,
79089
79310
  exposures: m.refs?.exposures
@@ -79110,6 +79331,7 @@ function vaultTermInputFromSourceRow(row, chainId) {
79110
79331
  const info = row.vaultInfo ?? {};
79111
79332
  const assetInfo = row.underlyingInfo?.asset;
79112
79333
  const assetDecimals = num14(row.assetDecimals) ?? num14(assetInfo?.decimals) ?? num14(row.decimals);
79334
+ const curated = savingsCuration(provider, chainId, address);
79113
79335
  return {
79114
79336
  provider,
79115
79337
  chainId,
@@ -79118,7 +79340,7 @@ function vaultTermInputFromSourceRow(row, chainId) {
79118
79340
  name: str7(info.name) ?? str7(row.displayName) ?? str7(row.name),
79119
79341
  brand: str7(row.curatorName) ?? str7(meta.brand),
79120
79342
  curatorName: str7(row.curatorName),
79121
- description: str7(meta.description),
79343
+ description: str7(meta.description) ?? curated.description,
79122
79344
  asset: {
79123
79345
  chainId,
79124
79346
  address: str7(row.underlying)?.toLowerCase() ?? "",
@@ -79146,9 +79368,9 @@ function vaultTermInputFromSourceRow(row, chainId) {
79146
79368
  swapFeeRate: num14(meta.feeRate),
79147
79369
  redemptionDiscountBps: num14(meta.redemptionDiscountBps),
79148
79370
  instantRedeemEnabled: bool2(meta.instantRedeemEnabled),
79149
- yieldWarmupSeconds: num14(meta.yieldWarmupSeconds),
79150
- accrual: str7(meta.accrual),
79151
- needsDepositApproval: bool2(meta.needsDepositApproval),
79371
+ yieldWarmupSeconds: num14(meta.yieldWarmupSeconds) ?? curated.yieldWarmupSeconds,
79372
+ accrual: str7(meta.accrual) ?? curated.accrual,
79373
+ needsDepositApproval: bool2(meta.needsDepositApproval) ?? curated.needsDepositApproval,
79152
79374
  isMintable: bool2(meta.isMintable),
79153
79375
  depositCapacity: str7(meta.depositCapacity) ?? str7(meta.maxDeposit),
79154
79376
  supplyCap: str7(meta.supplyCap),
@@ -79164,7 +79386,7 @@ function vaultTermInputFromSourceRow(row, chainId) {
79164
79386
  curator: str7(meta.curator),
79165
79387
  guardian: str7(meta.guardian),
79166
79388
  feeRecipient: str7(meta.feeRecipient),
79167
- solvency: str7(meta.solvency),
79389
+ solvency: str7(meta.solvency) ?? curated.solvency,
79168
79390
  navOracle: str7(meta.navOracle),
79169
79391
  yieldProfile: str7(info.yieldProfile),
79170
79392
  exposures: Array.isArray(row.exposures) ? row.exposures : Array.isArray(meta.exposures) ? meta.exposures : void 0
@@ -80001,7 +80223,15 @@ function toTermSheetInput(row, ctx = {}) {
80001
80223
  closeFactor: num15(v?.closeFactor),
80002
80224
  targetHealthFactor: num15(v?.targetHealthFactor),
80003
80225
  collateralDisabled: v?.collateralDisabled === true,
80004
- debtDisabled: v?.debtDisabled === true
80226
+ debtDisabled: v?.debtDisabled === true,
80227
+ // the mode-level position fields (UNIFIED_API_AUDIT §11) — set
80228
+ // only where the row carries them, so EVM inputs are unchanged
80229
+ ...v?.liquidationBorrowFactor != null ? { liquidationBorrowFactor: num15(v.liquidationBorrowFactor) } : {},
80230
+ ...v?.debtCapacity != null ? { debtCapacity: num15(v.debtCapacity) } : {},
80231
+ ...v?.collateralDebtCapacity != null ? { collateralDebtCapacity: num15(v.collateralDebtCapacity) } : {},
80232
+ ...v?.maxCollateralAssets != null ? { maxCollateralAssets: num15(v.maxCollateralAssets) } : {},
80233
+ ...v?.exclusiveCollateral != null ? { exclusiveCollateral: v.exclusiveCollateral === true } : {},
80234
+ ...v?.openParameter ? { openParameter: v.openParameter } : {}
80005
80235
  }
80006
80236
  ])
80007
80237
  ) : void 0;
@@ -80072,6 +80302,9 @@ function toTermSheetInput(row, ctx = {}) {
80072
80302
  "variableBorrowDisabled",
80073
80303
  "flags.variableBorrowDisabled"
80074
80304
  ),
80305
+ ...pick2(row, "siloedBorrowing", "flags.siloedBorrowing") != null ? {
80306
+ siloedBorrowing: pick2(row, "siloedBorrowing", "flags.siloedBorrowing") === true
80307
+ } : {},
80075
80308
  config,
80076
80309
  // `caps.` is NOT optional here. `/pools/latest` serializes both of these as
80077
80310
  // TOP-LEVEL row fields, while `/lending/latest` — the endpoint the lending
@@ -81818,6 +82051,753 @@ function num17(v) {
81818
82051
  const n = typeof v === "string" ? Number(v) : v;
81819
82052
  return Number.isFinite(n) && n > 0 ? n : void 0;
81820
82053
  }
82054
+ var KLEND_PROGRAM_ID = "KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD";
82055
+ var KAMINO_MAIN_MARKET = "7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF";
82056
+ var KAMINO_PROFILE_ID = "kamino.klend@v1";
82057
+ var MAIN_MARKET_FULL_LIQUIDATION = {
82058
+ aboveLtv: 0.95,
82059
+ belowDebtValueUsd: 2,
82060
+ maxPerLiquidationUsd: 25e5,
82061
+ verifiedAt: "2026-09-28"
82062
+ };
82063
+ var OBLIGATION_MAX_DEPOSITS = 8;
82064
+ var OBLIGATION_MAX_BORROWS = 5;
82065
+ var isNum3 = (v) => typeof v === "number" && Number.isFinite(v);
82066
+ function elevationGroups(input) {
82067
+ const out = [];
82068
+ for (const [id, raw] of Object.entries(input.config ?? {})) {
82069
+ if (id === "0") continue;
82070
+ const c = raw;
82071
+ const role = !c.collateralDisabled ? "collateral" : !c.debtDisabled ? "debt" : "none";
82072
+ out.push({
82073
+ id,
82074
+ label: c.label,
82075
+ role,
82076
+ ...role === "collateral" ? {
82077
+ ltv: c.borrowCollateralFactor,
82078
+ liquidationLtv: c.collateralFactor
82079
+ } : {},
82080
+ ...isNum3(c.maxCollateralAssets) ? { maxCollateralAssets: c.maxCollateralAssets } : {},
82081
+ ...typeof c.exclusiveCollateral === "boolean" ? { exclusiveCollateral: c.exclusiveCollateral } : {},
82082
+ ...role === "collateral" && isNum3(c.collateralDebtCapacity) ? { collateralDebtCapacity: c.collateralDebtCapacity } : {}
82083
+ });
82084
+ }
82085
+ return out;
82086
+ }
82087
+ function build(input) {
82088
+ const market = kaminoMarketFromKey(input.lender);
82089
+ const isMain = market === KAMINO_MAIN_MARKET;
82090
+ const base = input.config?.["0"];
82091
+ const groups = elevationGroups(input);
82092
+ const address = input.asset?.address ?? input.underlying;
82093
+ const pending = {
82094
+ "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",
82095
+ "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",
82096
+ "supply.fees": "the protocol take rate (already netted out of the supply APR) is not served",
82097
+ "supply.exit.withdrawalCap": "the reserve's net-withdrawal cap (capacity, interval, current total) is not served",
82098
+ "borrow.availability.debtWithdrawalCap": "the reserve's net-borrow cap (`debtWithdrawalCap`) is not served",
82099
+ "borrow.fees.flash-loan": "the flash-loan fee is not served",
82100
+ "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",
82101
+ "governance.controller": "the market owner (Kamino, or a third-party curator) is not served",
82102
+ oracle: "Scope / Pyth / Switchboard per reserve (`config.tokenInfo`) \u2014 not served and not classified"
82103
+ };
82104
+ if (!isMain)
82105
+ 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)";
82106
+ if (!isNum3(input.closeFactor) && !isNum3(base?.closeFactor))
82107
+ 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";
82108
+ if (!isNum3(input.originationFee))
82109
+ pending["borrow.fees"] = "the origination fee lives in the reserve account, which this row was not built from";
82110
+ if (!isNum3(base?.debtCapacity))
82111
+ pending["borrow.availability.debtCapacityOutsideGroups"] = "the remaining outside-group borrow limit (`config.debtCapacity`) is not on the input";
82112
+ if (groups.some(
82113
+ (g) => g.maxCollateralAssets === void 0 || g.exclusiveCollateral === void 0
82114
+ ))
82115
+ pending["borrow.modes.constraints"] = "maxCollateralAssets / exclusiveCollateral per elevation group are served on `config` but not on the input";
82116
+ if (groups.some(
82117
+ (g) => g.role === "collateral" && g.collateralDebtCapacity === void 0
82118
+ ))
82119
+ 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";
82120
+ const originationFee = isNum3(input.originationFee) && input.originationFee > 0 ? [
82121
+ {
82122
+ id: "origination",
82123
+ label: "Borrow origination fee",
82124
+ when: "entry",
82125
+ unit: "percent",
82126
+ basis: "principal",
82127
+ value: input.originationFee,
82128
+ payee: "protocol",
82129
+ mutable: true,
82130
+ description: "Taken out of the borrowed amount: the wallet receives the borrow less this fee."
82131
+ }
82132
+ ] : void 0;
82133
+ const collateralOnlyInGroups = base?.borrowCollateralFactor === 0 && (base.collateralFactor ?? 0) > 0;
82134
+ return {
82135
+ ...address ? { asset: { address: String(address) } } : {},
82136
+ supply: {
82137
+ // klend accrues and compounds interest per slot.
82138
+ rate: { compounding: "per-slot" },
82139
+ ext: {
82140
+ kamino: {
82141
+ ...collateralOnlyInGroups ? {
82142
+ noBorrowingPowerOutsideGroups: "LTV 0 outside every elevation group: this deposit adds no borrowing power there but still counts at its liquidation threshold"
82143
+ } : {},
82144
+ elevationGroups: groups.filter((g) => g.role === "collateral")
82145
+ }
82146
+ }
82147
+ },
82148
+ borrow: {
82149
+ rate: { compounding: "per-slot" },
82150
+ liquidation: {
82151
+ model: "repay-seize",
82152
+ absorber: "liquidator",
82153
+ reversible: false,
82154
+ // Auto-deleverage would make it price-and-time; it is not served, so
82155
+ // the ordinary price trigger stands and the rest is pending.
82156
+ trigger: "price",
82157
+ seizure: "proportional",
82158
+ ...isNum3(base?.liquidationPenalty) ? {
82159
+ penalties: [
82160
+ {
82161
+ id: "bonus-min",
82162
+ label: "Liquidation bonus (at the threshold)",
82163
+ value: base.liquidationPenalty,
82164
+ 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)."
82165
+ }
82166
+ ]
82167
+ } : {}
82168
+ },
82169
+ ...originationFee ? { fees: originationFee } : {},
82170
+ ext: {
82171
+ kamino: {
82172
+ closeFactorSource: "LendingMarket.liquidationMaxDebtCloseFactorPct",
82173
+ 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.",
82174
+ ...isMain ? { fullLiquidation: MAIN_MARKET_FULL_LIQUIDATION } : {},
82175
+ ...isNum3(base?.debtCapacity) ? { debtCapacityOutsideGroups: base.debtCapacity } : {},
82176
+ elevationGroups: groups,
82177
+ elevationGroupRules: {
82178
+ oneGroupPerObligation: true,
82179
+ onlyDebtReserveBorrowable: true,
82180
+ everyDepositMustBeMember: true,
82181
+ debtReserveCannotBeDeposit: true,
82182
+ borrowFactorInsideGroup: 1,
82183
+ allowNewLoansGatesRequestAndBorrow: true,
82184
+ zeroGroupCapClosesNewDebtOnly: true,
82185
+ selection: "per obligation (`request_elevation_group`)"
82186
+ }
82187
+ }
82188
+ }
82189
+ },
82190
+ constraints: {
82191
+ crossMargin: true,
82192
+ positionModel: "sub-account",
82193
+ 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.`
82194
+ },
82195
+ ext: {
82196
+ kamino: {
82197
+ program: KLEND_PROGRAM_ID,
82198
+ ...market ? { market } : {},
82199
+ isMainMarket: isMain,
82200
+ /** The marketUid ref is the RESERVE pubkey, not the mint. */
82201
+ marketUidRef: "reserve"
82202
+ }
82203
+ },
82204
+ coverage: { pending }
82205
+ };
82206
+ }
82207
+ var kaminoAdapter = {
82208
+ id: "kamino",
82209
+ matches: isKamino,
82210
+ profileId: () => KAMINO_PROFILE_ID,
82211
+ build
82212
+ };
82213
+ var JUPITER_LEND_PROFILE_ID = "jupiter-lend.vault@v1";
82214
+ var FLUID_VAULT_TYPE_T1 = 1e4;
82215
+ var JL_MAX_BORROW_FEE_PERCENT = 2.55;
82216
+ var JL_MAIN_PROGRAMS = {
82217
+ liquidity: "jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC",
82218
+ vaults: "jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi",
82219
+ oracle: "jupnw4B6Eqs7ft6rxpzYLJZYSnrpRgPcr589n5Kv4oc",
82220
+ flashloan: "jupgfSgfuAXv4B6R2Uxu85Z1qdzgju79s6MfZekN6XS"
82221
+ };
82222
+ var isNum4 = (v) => typeof v === "number" && Number.isFinite(v);
82223
+ function build2(input) {
82224
+ const vault = jupiterLendVaultFromKey(input.lender);
82225
+ const address = input.asset?.address ?? input.underlying;
82226
+ const pending = {
82227
+ "borrow.liquidation.liquidationMaxLimit": "the max liquidation limit (the LTV past which a position is liquidated ENTIRELY) is not served",
82228
+ "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",
82229
+ "supply.exit.withdrawalLimit": "the expanding per-position withdrawal limit and the vault's withdrawal gap are not served",
82230
+ "borrow.availability.minSize": "the vault's minimum borrow is not served",
82231
+ "borrow.fees.flash-loan": "the market flashloan program's fee and flashable set are not served",
82232
+ "borrow.ext.rateMagnifiers": "the vault's additive supply / borrow magnifiers are not served (the row's rates already include them)",
82233
+ oracle: "the vault's oracle (sources, hops) is not served; its price is borrow-per-supply in HUMAN units \xD7 1e15",
82234
+ "governance.controller": "the vault admin / rate-model authority is not on the public API"
82235
+ };
82236
+ if (!isNum4(input.originationFee) && input.borrowingEnabled === true)
82237
+ pending["borrow.fees"] = "the vault's borrow fee is not on the row";
82238
+ const fees = isNum4(input.originationFee) && input.originationFee > 0 ? [
82239
+ {
82240
+ id: "origination",
82241
+ label: "Borrow fee",
82242
+ when: "entry",
82243
+ unit: "percent",
82244
+ basis: "principal",
82245
+ value: input.originationFee,
82246
+ payee: "protocol",
82247
+ mutable: true,
82248
+ cap: JL_MAX_BORROW_FEE_PERCENT,
82249
+ description: "Charged once on the amount borrowed; the vault stores it as a u8 at 1e4, so it can never exceed 2.55 %."
82250
+ }
82251
+ ] : void 0;
82252
+ return {
82253
+ ...address ? { asset: { address: String(address) } } : {},
82254
+ // Rates are set on the Liquidity Layer — claim that basis only when the
82255
+ // layer totals are actually on the row (the fluid adapter's rule). Only
82256
+ // REFINES a block the builder made: a patch with no base would become a
82257
+ // utilization block without a utilization.
82258
+ ...isNum4(input.utilization) ? {
82259
+ utilization: input.irmTotalDeposits != null && input.irmTotalDebt != null ? { basis: "liquidity-layer", lockupRatio: input.lockupRatio } : { lockupRatio: input.lockupRatio }
82260
+ } : {},
82261
+ borrow: {
82262
+ liquidation: {
82263
+ model: "repay-seize",
82264
+ absorber: "liquidator",
82265
+ reversible: false,
82266
+ trigger: "price",
82267
+ seizure: "proportional"
82268
+ },
82269
+ ...fees ? { fees } : {},
82270
+ ext: {
82271
+ jupiterLend: {
82272
+ 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.",
82273
+ rateMagnifier: {
82274
+ additive: true,
82275
+ unit: "bps",
82276
+ includedInRowRates: true,
82277
+ note: "A signed APR offset ADDED to the layer's per-token rate (vault 101: \u2212200) \u2014 not EVM Fluid's multiplier."
82278
+ },
82279
+ 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."
82280
+ }
82281
+ }
82282
+ },
82283
+ constraints: {
82284
+ crossMargin: false,
82285
+ positionModel: "nft",
82286
+ 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."
82287
+ },
82288
+ ext: {
82289
+ jupiterLend: {
82290
+ ...vault ? { market: vault.market, vaultId: vault.vaultId } : {},
82291
+ fluidVaultType: FLUID_VAULT_TYPE_T1,
82292
+ ...vault?.market === "main" ? { programs: JL_MAIN_PROGRAMS } : {},
82293
+ /** The marketUid ref is the leg's MINT. */
82294
+ marketUidRef: "mint"
82295
+ }
82296
+ },
82297
+ coverage: { pending }
82298
+ };
82299
+ }
82300
+ var jupiterLendAdapter = {
82301
+ id: "jupiter-lend",
82302
+ matches: isJupiterLend,
82303
+ profileId: () => JUPITER_LEND_PROFILE_ID,
82304
+ build: build2
82305
+ };
82306
+ var SAVE_PROGRAM_ID = "So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo";
82307
+ var SAVE_PROFILE_ID = "save.pool@v1";
82308
+ var SAVE_LIQUIDATION_CLOSE_FACTOR = 0.2;
82309
+ var SAVE_MAX_LIQUIDATABLE_VALUE_USD = 5e5;
82310
+ var SAVE_FULL_LIQUIDATION_VALUE_USD = 1;
82311
+ var SAVE_MAX_PENALTY = 0.25;
82312
+ var SAVE_SLOTS_PER_YEAR = 63072e3;
82313
+ var SAVE_MAX_OBLIGATION_RESERVES = 10;
82314
+ var SAVE_POSITION_LIMIT = 6;
82315
+ var isNum5 = (v) => typeof v === "number" && Number.isFinite(v);
82316
+ function build3(input) {
82317
+ const market = saveMarketFromKey(input.lender);
82318
+ const base = input.config?.["0"];
82319
+ const siloed = input.siloedBorrowing;
82320
+ const address = input.asset?.address ?? input.underlying;
82321
+ const pending = {
82322
+ "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",
82323
+ "borrow.liquidation.penaltySplit": "the row carries bonus + protocol fee as one figure; the split is not served",
82324
+ "supply.fees": "the protocol take rate on interest is not served (it is already netted out of the supply APR)",
82325
+ "borrow.fees.flash-loan": "the flash-loan fee is not served",
82326
+ "borrow.fees.host": "the host (referrer) share of the origination fee is not served",
82327
+ "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",
82328
+ "borrow.rate.bounds": "the three-segment curve (min / optimal / max / super-max rates) is not served",
82329
+ "governance.controller": "the market owner (Save's key for Main, a third party elsewhere) is not served",
82330
+ oracle: "Pyth pull / Switchboard per reserve, and the owner-set SOL-price ratio some LST reserves are valued with, are not served",
82331
+ "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"
82332
+ };
82333
+ if (typeof siloed !== "boolean")
82334
+ pending["constraints.siloedBorrowing"] = "the isolated-reserve flag (`siloedBorrowing`) is served on the row but not on the input";
82335
+ if (!isNum5(input.originationFee))
82336
+ pending["borrow.fees"] = "the origination fee is not on the row";
82337
+ const originationFee = isNum5(input.originationFee) && input.originationFee > 0 ? [
82338
+ {
82339
+ id: "origination",
82340
+ label: "Borrow (origination) fee",
82341
+ when: "entry",
82342
+ unit: "percent",
82343
+ basis: "principal",
82344
+ value: input.originationFee,
82345
+ payee: "protocol",
82346
+ mutable: true,
82347
+ description: "Deducted from the amount received; part of it goes to the referring host account when one is named."
82348
+ }
82349
+ ] : void 0;
82350
+ return {
82351
+ ...address ? { asset: { address: String(address) } } : {},
82352
+ supply: {
82353
+ rate: { compounding: "per-slot" },
82354
+ counterparty: {
82355
+ kind: "pool",
82356
+ solvency: "overcollateralized",
82357
+ socializedLoss: true
82358
+ },
82359
+ principal: { protected: false, risks: ["bad-debt"] }
82360
+ },
82361
+ borrow: {
82362
+ rate: { compounding: "per-slot" },
82363
+ liquidation: {
82364
+ model: "repay-seize",
82365
+ absorber: "liquidator",
82366
+ reversible: false,
82367
+ trigger: "price",
82368
+ // A program constant — the row carries the same 0.2.
82369
+ closeFactor: SAVE_LIQUIDATION_CLOSE_FACTOR,
82370
+ seizure: "proportional",
82371
+ permissioned: false,
82372
+ badDebt: "socialized",
82373
+ ...isNum5(base?.liquidationPenalty) ? {
82374
+ penalties: [
82375
+ {
82376
+ id: "bonus-plus-protocol-fee",
82377
+ label: "Liquidator bonus + protocol fee (at the threshold)",
82378
+ value: base.liquidationPenalty,
82379
+ 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} %.`
82380
+ }
82381
+ ]
82382
+ } : {}
82383
+ },
82384
+ counterparty: {
82385
+ kind: "pool",
82386
+ solvency: "overcollateralized",
82387
+ socializedLoss: true
82388
+ },
82389
+ ...originationFee ? { fees: originationFee } : {},
82390
+ ext: {
82391
+ save: {
82392
+ closeFactor: {
82393
+ fraction: SAVE_LIQUIDATION_CLOSE_FACTOR,
82394
+ basis: "the obligation's WEIGHTED borrow value",
82395
+ maxPerCallUsd: SAVE_MAX_LIQUIDATABLE_VALUE_USD,
82396
+ fullLiquidationAtOrBelowUsd: SAVE_FULL_LIQUIDATION_VALUE_USD
82397
+ },
82398
+ maxPenalty: SAVE_MAX_PENALTY,
82399
+ /** The row's `borrowFactor`: the debt multiplier (`borrowed_value += value × borrow_weight`). */
82400
+ ...isNum5(base?.borrowFactor) ? { borrowWeight: base.borrowFactor } : {},
82401
+ 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.",
82402
+ ...typeof siloed === "boolean" ? { isolated: siloed } : {},
82403
+ slotYear: {
82404
+ slotsPerYear: SAVE_SLOTS_PER_YEAR,
82405
+ note: "The curve compounds per slot on a 0.5 s slot-year; the row publishes it scaled to the measured slot time."
82406
+ }
82407
+ }
82408
+ }
82409
+ },
82410
+ constraints: {
82411
+ crossMargin: true,
82412
+ positionModel: "sub-account",
82413
+ 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}).`,
82414
+ ...typeof siloed === "boolean" ? { siloedBorrowing: siloed } : {}
82415
+ },
82416
+ ext: {
82417
+ save: {
82418
+ program: SAVE_PROGRAM_ID,
82419
+ ...market ? { market } : {},
82420
+ /** The marketUid ref is the RESERVE pubkey, not the mint. */
82421
+ marketUidRef: "reserve"
82422
+ }
82423
+ },
82424
+ coverage: { pending }
82425
+ };
82426
+ }
82427
+ var saveAdapter = {
82428
+ id: "save",
82429
+ matches: isSave,
82430
+ profileId: () => SAVE_PROFILE_ID,
82431
+ build: build3
82432
+ };
82433
+ var LOOPSCALE_PROFILE_ID = "loopscale.creditbook@v1";
82434
+ var LOOPSCALE_PROGRAM_ID = "1oopBoJG58DgkUVKkEzKgyG9dvRmpgeEm1AVjoHkF78";
82435
+ var LOOPSCALE_BEAM_ORACLE_PROGRAM_ID = "beamVVkNmKeXcuZ6zLpC9eM5YgVyAn4Z9xdPrz3gCW2";
82436
+ var LOOPSCALE_GRACE_PERIOD_SECS = 172800;
82437
+ var LOOPSCALE_REFINANCE_TERM_DAYS = 1;
82438
+ var LOOPSCALE_MAX_COLLATERALS = 5;
82439
+ var LOOPSCALE_MAX_LEDGERS = 5;
82440
+ var LS_NO_ACCOUNT = "11111111111111111111111111111111";
82441
+ var DAY2 = 86400;
82442
+ var isNum6 = (v) => typeof v === "number" && Number.isFinite(v);
82443
+ function menuOf(input) {
82444
+ if (!input.terms?.length) return void 0;
82445
+ return input.terms.map((t) => ({
82446
+ ...t,
82447
+ durationSecs: isNum6(t.durationSecs) ? t.durationSecs : Math.round(t.durationDays * DAY2)
82448
+ }));
82449
+ }
82450
+ function build4(input) {
82451
+ const pair = loopscaleMarketFromKey(input.lender);
82452
+ const m = input.market ?? {};
82453
+ const cfg = input.config?.["0"];
82454
+ const address = input.asset?.address ?? input.underlying;
82455
+ const menu = menuOf(input);
82456
+ const durations = (menu ?? []).map((t) => t.durationSecs).filter(isNum6);
82457
+ const tenor = durations.length ? {
82458
+ minDurationSecs: Math.min(...durations),
82459
+ maxDurationSecs: Math.max(...durations)
82460
+ } : {};
82461
+ const oracleAccount = typeof m.oracle === "string" && m.oracle !== LS_NO_ACCOUNT ? m.oracle : void 0;
82462
+ const lltvRaw = m.lltv != null ? Number(m.lltv) : void 0;
82463
+ const bestOneDayLqt = lltvRaw != null && Number.isFinite(lltvRaw) && lltvRaw > 0 ? lltvRaw / 1e18 : void 0;
82464
+ const openParameter = cfg?.openParameter;
82465
+ const pending = {
82466
+ "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",
82467
+ "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",
82468
+ "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",
82469
+ "borrow.counterparty.curator": "which strategy rests the best offer (and its vault) is not served",
82470
+ "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"
82471
+ };
82472
+ if (!oracleAccount)
82473
+ pending.oracle = "no oracle account is on params.market for this collateral (the MarketInformation read did not name one)";
82474
+ else
82475
+ pending.oracle = `the program reads ${oracleAccount} (BEAM: Pyth / Switchboard / Chainlink / RedStone + component pricing); not classified`;
82476
+ if (!isNum6(input.originationFee) && input.borrowingEnabled === true)
82477
+ pending["borrow.fees"] = "no curated vault offers this pair \u2014 the resting strategy\u2019s fees are not on the public API";
82478
+ if (!cfg?.openParameter && cfg?.collateralDisabled === false)
82479
+ 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";
82480
+ const isLoanLeg = cfg?.debtDisabled === false || input.rateModel === "fixedTerm" || !!input.terms?.length;
82481
+ const originationFee = isNum6(input.originationFee) ? input.originationFee > 0 ? [
82482
+ {
82483
+ id: "origination",
82484
+ label: "Origination fee",
82485
+ when: "entry",
82486
+ unit: "percent",
82487
+ basis: "principal",
82488
+ value: input.originationFee,
82489
+ payee: "curator",
82490
+ mutable: true,
82491
+ 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."
82492
+ }
82493
+ ] : [] : void 0;
82494
+ const fixedRate = {
82495
+ kind: "fixed-term",
82496
+ source: "orderbook",
82497
+ isLocked: true,
82498
+ compounding: "none",
82499
+ ...menu ? { menu } : {}
82500
+ };
82501
+ return {
82502
+ ...address ? { asset: { address: String(address) } } : {},
82503
+ // An order book has no pool utilization; the row's 0 is a placeholder.
82504
+ // `null`, not `undefined`: the deep merge skips `undefined`, so only
82505
+ // `null` removes the builder's block (the type has no "remove" spelling).
82506
+ utilization: null,
82507
+ supply: isLoanLeg ? {
82508
+ // What an advanced lender resting at the best 1-day rate earns.
82509
+ rate: fixedRate,
82510
+ maturity: {
82511
+ kind: "rolling-duration",
82512
+ ...tenor,
82513
+ // The ledger is repaid out of the refinancing offer, or runs the
82514
+ // grace period at the same rate.
82515
+ atMaturity: "refinanced",
82516
+ graceSecs: LOOPSCALE_GRACE_PERIOD_SECS
82517
+ },
82518
+ exit: {
82519
+ // Before maturity a ledger leaves only by being sold to another
82520
+ // strategy at a negotiated price — and there may be no buyer.
82521
+ mode: "market-sale",
82522
+ settlement: "sync",
82523
+ priceRisk: "may-be-impossible",
82524
+ partialAllowed: true
82525
+ },
82526
+ counterparty: { kind: "orderbook", solvency: "overcollateralized" },
82527
+ principal: { protected: false, risks: ["bad-debt"] },
82528
+ ext: {
82529
+ loopscale: {
82530
+ exitBeforeMaturity: "sell-ledger",
82531
+ passiveLenders: "Deposit into a curated vault (its own earn row), which rests the offers and charges a fee on the interest"
82532
+ }
82533
+ }
82534
+ } : {
82535
+ ...openParameter ? {
82536
+ ext: {
82537
+ loopscale: {
82538
+ // Each loan pins the LTV / LQT of the offer it filled;
82539
+ // `modes[<loan pubkey>]` carries the value per position.
82540
+ openParameter
82541
+ }
82542
+ }
82543
+ } : {}
82544
+ },
82545
+ borrow: {
82546
+ rate: fixedRate,
82547
+ maturity: {
82548
+ kind: "rolling-duration",
82549
+ ...tenor,
82550
+ atMaturity: "refinanced",
82551
+ graceSecs: LOOPSCALE_GRACE_PERIOD_SECS
82552
+ },
82553
+ // Interest accrues to date; repaying early costs the interest so far.
82554
+ debtShape: "accruing",
82555
+ exit: {
82556
+ earlyRepay: "free",
82557
+ atMaturityCost: "accrued",
82558
+ // Not refinanced and past the grace period: liquidatable whatever
82559
+ // the health.
82560
+ lateBehaviour: "liquidatable",
82561
+ partialAllowed: true
82562
+ },
82563
+ liquidation: {
82564
+ model: "repay-seize",
82565
+ absorber: "liquidator",
82566
+ reversible: false,
82567
+ trigger: "price-and-time",
82568
+ seizure: "proportional",
82569
+ // Distance-based: there is no headline penalty. The row's 0 is the
82570
+ // converter's placeholder; `null` removes it (see `utilization`).
82571
+ penalty: null,
82572
+ penalties: [
82573
+ {
82574
+ id: "distance-past-threshold",
82575
+ label: "Distance past the liquidation LTV",
82576
+ value: 0,
82577
+ 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."
82578
+ }
82579
+ ]
82580
+ },
82581
+ counterparty: { kind: "orderbook", solvency: "overcollateralized" },
82582
+ ...originationFee ? { fees: originationFee } : {},
82583
+ ext: {
82584
+ loopscale: {
82585
+ autoRefinance: {
82586
+ termDays: LOOPSCALE_REFINANCE_TERM_DAYS,
82587
+ bestEffort: true,
82588
+ fallback: "no matching offer \u21D2 a 48-hour grace period at the same rate, then partial liquidation"
82589
+ },
82590
+ gracePeriodSecs: LOOPSCALE_GRACE_PERIOD_SECS,
82591
+ healthCountsInterestToMaturity: true,
82592
+ ltvPinnedAtOrigination: true,
82593
+ ...bestOneDayLqt !== void 0 ? {
82594
+ bestOneDayLiquidationLtv: bestOneDayLqt,
82595
+ bestOneDayLiquidationLtvNote: "params.market.lltv: the best 1-day offer's threshold today \u2014 a moving proxy, not a market constant"
82596
+ } : {}
82597
+ }
82598
+ }
82599
+ },
82600
+ constraints: {
82601
+ crossMargin: true,
82602
+ positionModel: "loan-id",
82603
+ 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.`
82604
+ },
82605
+ ext: {
82606
+ loopscale: {
82607
+ program: LOOPSCALE_PROGRAM_ID,
82608
+ oracleProgram: LOOPSCALE_BEAM_ORACLE_PROGRAM_ID,
82609
+ ...pair ? { pair } : {},
82610
+ ...oracleAccount ? { oracleAccount } : {},
82611
+ /** The marketUid ref is the leg's MINT. */
82612
+ marketUidRef: "mint"
82613
+ }
82614
+ },
82615
+ coverage: {
82616
+ pending,
82617
+ notApplicable: { utilization: "order book \u2014 no pool utilization" }
82618
+ }
82619
+ };
82620
+ }
82621
+ var loopscaleAdapter = {
82622
+ id: "loopscale",
82623
+ matches: isLoopscale,
82624
+ profileId: () => LOOPSCALE_PROFILE_ID,
82625
+ build: build4
82626
+ };
82627
+ var PROJECT_0_PROFILE_ID = "project0.group@v1";
82628
+ var P0_PROGRAM_ID = "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA";
82629
+ var P0_MAIN_GROUP = "4qp6Fx6tnZkY5Wropq9wUYgtFxXKwE6viZxFHg3rdAG8";
82630
+ var P0_DEFAULT_LIQUIDATION_FEE = 0.025;
82631
+ var P0_LIQUIDATION_CLOSEOUT_USD = 5;
82632
+ var P0_MAX_BALANCES = 16;
82633
+ var P0_SECONDS_PER_YEAR = 365 * 24 * 60 * 60;
82634
+ var isNum7 = (v) => typeof v === "number" && Number.isFinite(v);
82635
+ function derivedModes(input) {
82636
+ const cfg = input.config;
82637
+ if (!cfg || Object.keys(cfg).length <= 1) return void 0;
82638
+ return Object.entries(cfg).map(([key3, c]) => {
82639
+ const isDefault = key3 === "0";
82640
+ return {
82641
+ modeId: key3,
82642
+ label: c.label,
82643
+ isDefault,
82644
+ entry: isDefault ? void 0 : "automatic",
82645
+ liquidation: {
82646
+ ltv: c.borrowCollateralFactor,
82647
+ liquidationLtv: c.collateralFactor,
82648
+ penalty: c.liquidationPenalty,
82649
+ closeFactor: c.closeFactor ?? input.closeFactor ?? 1,
82650
+ targetHealthFactor: c.targetHealthFactor ?? input.targetHealthFactor
82651
+ },
82652
+ ...c.debtDisabled ? { availability: { canOpen: false } } : {}
82653
+ };
82654
+ });
82655
+ }
82656
+ function build5(input) {
82657
+ const group = project0GroupFromKey(input.lender);
82658
+ const base = input.config?.["0"];
82659
+ const siloed = input.siloedBorrowing;
82660
+ const address = input.asset?.address ?? input.underlying;
82661
+ const penalty = base?.liquidationPenalty;
82662
+ const defaultFees = isNum7(penalty) && Math.abs(penalty - 2 * P0_DEFAULT_LIQUIDATION_FEE) < 1e-9;
82663
+ const liabilityWeightMaint = base?.liquidationBorrowFactor;
82664
+ const pending = {
82665
+ "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",
82666
+ "borrow.fees.interest": "the group, insurance and program fee legs on interest (and their fixed APRs) are not served",
82667
+ "supply.exit.rateLimiter": "the bank's hourly / daily outflow limiter (shared by withdrawals and borrows) and the group's USD limiter are not served",
82668
+ "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)",
82669
+ "borrow.liquidation.receivership": "the receivership path (a liquidator controls the account for one transaction, at a higher premium) is not modelled",
82670
+ "borrow.modes.sameAsset": "the group's same-asset e-mode leverage (and the 20\xD7 / 40\xD7 caps) is not served",
82671
+ oracle: "the oracle setup (Pyth push / Switchboard / fixed / Kamino Scope / staked), max age and confidence cap are not served",
82672
+ "governance.roles": "the group admin and its delegates (e-mode, curve, limit, risk admins) are not served; multisig status unverified"
82673
+ };
82674
+ if (!isNum7(liabilityWeightMaint) && base?.debtDisabled === false)
82675
+ 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";
82676
+ if (typeof siloed !== "boolean")
82677
+ pending["constraints.siloedBorrowing"] = "the isolated-tier flag (`siloedBorrowing`) is served on the row but not on the input";
82678
+ if (isNum7(penalty) && !defaultFees)
82679
+ pending["borrow.liquidation.penaltySplit"] = "the row carries liquidator + insurance fee as one figure; the split is not served";
82680
+ if (!isNum7(input.originationFee))
82681
+ pending["borrow.fees"] = "the origination fee is not on the row";
82682
+ const penalties = !isNum7(penalty) ? void 0 : defaultFees ? [
82683
+ {
82684
+ id: "liquidator-fee",
82685
+ label: "Liquidator premium",
82686
+ value: P0_DEFAULT_LIQUIDATION_FEE,
82687
+ description: "Read from the LIABILITY bank being repaid (a stored 0 is this 2.5 % default); it goes to the liquidator."
82688
+ },
82689
+ {
82690
+ id: "insurance-fee",
82691
+ label: "Insurance fund fee",
82692
+ value: P0_DEFAULT_LIQUIDATION_FEE,
82693
+ description: "Also read from the liability bank; the liquidatee pays both, the insurance fund keeps this one. `penalty` is the total the liquidatee loses."
82694
+ }
82695
+ ] : [
82696
+ {
82697
+ id: "liquidation-fees",
82698
+ label: "Liquidator premium + insurance fee",
82699
+ value: penalty,
82700
+ description: "Both read from the LIABILITY bank being repaid; the liquidatee pays the total."
82701
+ }
82702
+ ];
82703
+ const originationFee = isNum7(input.originationFee) && input.originationFee > 0 ? [
82704
+ {
82705
+ id: "origination",
82706
+ label: "Borrow origination fee",
82707
+ when: "entry",
82708
+ unit: "percent",
82709
+ basis: "principal",
82710
+ value: input.originationFee,
82711
+ payee: "protocol",
82712
+ mutable: true
82713
+ }
82714
+ ] : void 0;
82715
+ const modes = derivedModes(input);
82716
+ return {
82717
+ ...address ? { asset: { address: String(address) } } : {},
82718
+ supply: {
82719
+ // Simple interest settled into the share value at every touch.
82720
+ rate: { compounding: "on-touch" },
82721
+ counterparty: {
82722
+ kind: "pool",
82723
+ solvency: "overcollateralized",
82724
+ socializedLoss: true
82725
+ },
82726
+ principal: { protected: false, risks: ["bad-debt"] },
82727
+ ...modes ? { modes } : {}
82728
+ },
82729
+ borrow: {
82730
+ rate: { compounding: "on-touch" },
82731
+ liquidation: {
82732
+ model: "repay-seize",
82733
+ absorber: "liquidator",
82734
+ reversible: false,
82735
+ trigger: "price",
82736
+ seizure: "proportional",
82737
+ permissioned: false,
82738
+ // The insurance fund absorbs first; the rest is socialised to the
82739
+ // bank's depositors (`counterparty.socializedLoss`).
82740
+ badDebt: "insurance-fund",
82741
+ ...penalties ? { penalties } : {}
82742
+ },
82743
+ counterparty: {
82744
+ kind: "pool",
82745
+ solvency: "overcollateralized",
82746
+ socializedLoss: true
82747
+ },
82748
+ ...originationFee ? { fees: originationFee } : {},
82749
+ ...modes ? { modes } : {},
82750
+ ext: {
82751
+ project0: {
82752
+ liquidation: {
82753
+ partialToHealthZero: true,
82754
+ closeoutBelowEquityUsd: P0_LIQUIDATION_CLOSEOUT_USD,
82755
+ feesReadFrom: "the liability bank",
82756
+ defaultFeeEach: P0_DEFAULT_LIQUIDATION_FEE
82757
+ },
82758
+ liabilityWeights: {
82759
+ /** `borrowFactor`: the weight a NEW borrow is checked against. */
82760
+ ...isNum7(base?.borrowFactor) ? { init: base.borrowFactor } : {},
82761
+ /** `liquidationBorrowFactor`: the weight liquidation health uses. */
82762
+ ...isNum7(liabilityWeightMaint) ? { maint: liabilityWeightMaint } : {}
82763
+ },
82764
+ 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.",
82765
+ operationalStates: {
82766
+ Operational: "every action",
82767
+ ReduceOnly: "no deposits or borrows; withdrawals and repayments work; the collateral counts toward liquidation health only (initial weight 0)",
82768
+ ReduceOnlyWithBorrowingPower: "no deposits or borrows; the collateral keeps both weights",
82769
+ Paused: "no deposits, withdrawals, borrows, repayments or liquidations",
82770
+ accrual: "interest accrues at the curve rate in every state"
82771
+ },
82772
+ isolatedRule: "An isolated-tier bank can be borrowed only on its own and never counts as collateral.",
82773
+ ...typeof siloed === "boolean" ? { isolated: siloed } : {},
82774
+ secondsPerYear: P0_SECONDS_PER_YEAR
82775
+ }
82776
+ }
82777
+ },
82778
+ constraints: {
82779
+ crossMargin: true,
82780
+ positionModel: "sub-account",
82781
+ 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.`,
82782
+ ...typeof siloed === "boolean" ? { siloedBorrowing: siloed } : {}
82783
+ },
82784
+ ext: {
82785
+ project0: {
82786
+ program: P0_PROGRAM_ID,
82787
+ ...group ? { group, isMainGroup: group === P0_MAIN_GROUP } : {},
82788
+ /** The marketUid ref is the BANK pubkey, not the mint. */
82789
+ marketUidRef: "bank"
82790
+ }
82791
+ },
82792
+ coverage: { pending }
82793
+ };
82794
+ }
82795
+ var project0Adapter = {
82796
+ id: "project0",
82797
+ matches: isProject0,
82798
+ profileId: () => PROJECT_0_PROFILE_ID,
82799
+ build: build5
82800
+ };
81821
82801
 
81822
82802
  // src/terms/adapters/index.ts
81823
82803
  var TERM_ADAPTERS = [
@@ -81843,7 +82823,14 @@ var TERM_ADAPTERS = [
81843
82823
  twyneAdapter,
81844
82824
  fraxlendAdapter,
81845
82825
  morphoBlueAdapter,
81846
- aaveV4Adapter
82826
+ aaveV4Adapter,
82827
+ // Solana families — predicates match `<FAMILY>` / `<FAMILY>_<base58>` on an
82828
+ // `_` boundary, disjoint from every EVM key above.
82829
+ kaminoAdapter,
82830
+ jupiterLendAdapter,
82831
+ saveAdapter,
82832
+ loopscaleAdapter,
82833
+ project0Adapter
81847
82834
  ];
81848
82835
  function resolveAdapter(lender) {
81849
82836
  return TERM_ADAPTERS.find((a) => a.matches(lender));
@@ -81927,9 +82914,10 @@ function enrichmentIndexFromRows(rows) {
81927
82914
  }
81928
82915
  const token = breakdown.find((b) => b?.category === "token");
81929
82916
  const chainId = String(row?.chainId ?? uid.split(":")[1] ?? "");
81930
- const address = String(
81931
- row?.asset?.address ?? row?.underlying ?? uid.split(":")[2] ?? ""
81932
- ).toLowerCase();
82917
+ const address = termAddressKey(
82918
+ chainId,
82919
+ String(row?.asset?.address ?? row?.underlying ?? uid.split(":")[2] ?? "")
82920
+ );
81933
82921
  if (token?.score != null && chainId && address) {
81934
82922
  assetRisk[chainId] ??= {};
81935
82923
  assetRisk[chainId][address] = {
@@ -81955,6 +82943,7 @@ function toDigest(sheet) {
81955
82943
  settlement: sheet.supply.exit.settlement,
81956
82944
  canOpen: sheet.supply.availability.canOpen,
81957
82945
  headline: sheet.supply.info.headline,
82946
+ description: sheet.supply.info.description,
81958
82947
  tags: sheet.supply.info.tags,
81959
82948
  backedBy: strip(sheet.supply.backedBy)
81960
82949
  } : void 0,
@@ -81968,6 +82957,7 @@ function toDigest(sheet) {
81968
82957
  liquidationTrigger: sheet.borrow.liquidation.trigger,
81969
82958
  canOpen: sheet.borrow.availability.canOpen,
81970
82959
  headline: sheet.borrow.info.headline,
82960
+ description: sheet.borrow.info.description,
81971
82961
  tags: sheet.borrow.info.tags,
81972
82962
  acceptedCollateral: strip(sheet.borrow.acceptedCollateral)
81973
82963
  } : void 0,
@@ -81994,7 +82984,7 @@ function enrichTermSheet(sheet, index) {
81994
82984
  sheet.oracle = {
81995
82985
  ...sheet.oracle,
81996
82986
  kind: "price-feed",
81997
- address: oracleRow.oracle.toLowerCase(),
82987
+ address: termAddressKey(sheet.chainId, oracleRow.oracle),
81998
82988
  provider: oracleRow.provider,
81999
82989
  priceDescription: oracleRow.priceDescription,
82000
82990
  intendedPair: oracleRow.intendedPair,
@@ -82059,7 +83049,7 @@ function enrichTermSheet(sheet, index) {
82059
83049
  if (itemOracle?.oracle) {
82060
83050
  item.oracle = {
82061
83051
  kind: "price-feed",
82062
- address: itemOracle.oracle.toLowerCase(),
83052
+ address: termAddressKey(sheet.chainId, itemOracle.oracle),
82063
83053
  provider: itemOracle.provider,
82064
83054
  band: itemOracle.band,
82065
83055
  score: itemOracle.score,
@@ -82249,8 +83239,8 @@ function validateTermSheet(sheet) {
82249
83239
  `oracle.kind none but liquidation.trigger is ${t} with model ${m ?? "unset"}`
82250
83240
  );
82251
83241
  }
82252
- if (o.address && o.address !== o.address.toLowerCase())
82253
- fail("oracle-lowercase", "oracle.address must be lowercased");
83242
+ if (o.address && o.address !== termAddressKey(sheet.chainId, o.address))
83243
+ fail("oracle-lowercase", "oracle.address must be lowercased (EVM)");
82254
83244
  }
82255
83245
  const g = sheet.governance;
82256
83246
  if (g) {
@@ -82629,13 +83619,28 @@ function stampCapabilities(row) {
82629
83619
  row.capabilities = row.venueKind === "lending" ? lendingCapabilities(row) : vaultCapabilities(row);
82630
83620
  return row;
82631
83621
  }
83622
+ function nativeStandsIn(row) {
83623
+ const wrapped = getWrappedNativeAddressSafe(row.chainId);
83624
+ return !!wrapped && wrapped.toLowerCase() === String(row.asset?.address ?? "").toLowerCase() && isNativeWrapOneToOne(row.chainId);
83625
+ }
83626
+ var NO_NATIVE_PROVIDERS = /* @__PURE__ */ new Set(["gmx", "hypercore"]);
82632
83627
  function lendingCapabilities(row) {
82633
83628
  const caps = [];
83629
+ const native = nativeStandsIn(row) && !isLiquityFamily(row.venue) && !isFluid(row.venue);
83630
+ const fixedLendExit = isTermMax(row.venue) || isTerm(row.venue);
82634
83631
  if (row.availability.canDeposit) {
82635
- caps.push({ action: "deposit", acceptsPayAsset: true });
83632
+ caps.push({
83633
+ action: "deposit",
83634
+ acceptsPayAsset: true,
83635
+ acceptsNative: native
83636
+ });
82636
83637
  }
82637
83638
  if (row.availability.canWithdraw) {
82638
- caps.push({ action: "withdraw", acceptsReceiveAsset: true });
83639
+ caps.push({
83640
+ action: "withdraw",
83641
+ acceptsReceiveAsset: true,
83642
+ acceptsNative: native && !fixedLendExit
83643
+ });
82639
83644
  }
82640
83645
  return caps;
82641
83646
  }
@@ -82653,6 +83658,9 @@ var NON_4626_DEPOSIT_KINDS = /* @__PURE__ */ new Set([
82653
83658
  "frankencoin",
82654
83659
  "yieldbasis",
82655
83660
  "wren",
83661
+ // Vesper va* pools — `deposit(amount)` credits msg.sender only (mirrors the
83662
+ // worker's list, which had it and this one did not)
83663
+ "vesper",
82656
83664
  "hyperbeat",
82657
83665
  "native-wnlp",
82658
83666
  "bitway"
@@ -82693,7 +83701,8 @@ function swapRoutedCapabilities(row, opts) {
82693
83701
  action: "deposit",
82694
83702
  via: "swap",
82695
83703
  requires: ["slippage"],
82696
- acceptsPayAsset: true
83704
+ acceptsPayAsset: true,
83705
+ acceptsNative: nativeStandsIn(row)
82697
83706
  });
82698
83707
  }
82699
83708
  if (row.availability.canWithdraw) {
@@ -82701,7 +83710,8 @@ function swapRoutedCapabilities(row, opts) {
82701
83710
  action: "withdraw",
82702
83711
  via: "swap",
82703
83712
  requires: ["slippage"],
82704
- acceptsReceiveAsset: true
83713
+ acceptsReceiveAsset: true,
83714
+ acceptsNative: nativeStandsIn(row)
82705
83715
  });
82706
83716
  }
82707
83717
  return caps;
@@ -82724,21 +83734,33 @@ function vaultCapabilities(row) {
82724
83734
  // deposit — but ONLY for rows whose deposit is a plain synchronous
82725
83735
  // ERC-4626 call. Advertising it anywhere else builds a zap input that
82726
83736
  // 400s at submit, which is exactly what this flag existed to prevent.
82727
- acceptsPayAsset: acceptsVaultZap(row, provider)
83737
+ acceptsPayAsset: acceptsVaultZap(row, provider),
83738
+ // native for a wrapped-native deposit token is NOT a zap: the 4626 rows
83739
+ // take it through the composer, every single-token builder (Lagoon,
83740
+ // the non-4626 savings kinds, ERC-20-only LST mints) as a leading wrap
83741
+ acceptsNative: !NO_NATIVE_PROVIDERS.has(provider) && nativeStandsIn(row)
82728
83742
  });
82729
83743
  }
82730
83744
  if (!row.availability.canWithdraw) return caps;
82731
83745
  const mode = row.exit.mode;
82732
83746
  const isAsync = provider !== "hypercore" && (ASYNC_PROVIDERS.has(provider) || ASYNC_EXIT_MODES.has(mode));
82733
83747
  if (!isAsync) {
82734
- caps.push({ action: "withdraw", requires: withdrawRequires(provider) });
83748
+ caps.push({
83749
+ action: "withdraw",
83750
+ requires: withdrawRequires(provider),
83751
+ // the unwrap rides the composer's 4626 withdraw — the same rows the
83752
+ // deposit zap serves; the single-token exits have no unwrap leg yet
83753
+ acceptsNative: acceptsVaultZap(row, provider) && nativeStandsIn(row)
83754
+ });
82735
83755
  return caps;
82736
83756
  }
82737
83757
  if (mode === "fee-or-queued" && meta.instantRedeemEnabled !== false) {
82738
83758
  caps.push({
82739
83759
  action: "withdraw",
82740
83760
  requires: withdrawRequires(provider),
82741
- feeBps: num13(meta.withdrawFeeBps) ?? row.exit.feeBps
83761
+ feeBps: num13(meta.withdrawFeeBps) ?? row.exit.feeBps,
83762
+ // a fee-paying single-token exit: pays the vault's token only
83763
+ acceptsNative: false
82742
83764
  });
82743
83765
  }
82744
83766
  caps.push({
@@ -83056,6 +84078,6 @@ function earnPositionTotals(items) {
83056
84078
  };
83057
84079
  }
83058
84080
 
83059
- 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 };
84081
+ 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, 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, 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 };
83060
84082
  //# sourceMappingURL=index.js.map
83061
84083
  //# sourceMappingURL=index.js.map