@1delta/margin-fetcher 5.0.28 → 5.0.30

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,9 +1,9 @@
1
1
  import { parseAbi, keccak256, encodeAbiParameters, formatEther, BaseError, erc20Abi, stringToHex, isAddress, pad, encodeFunctionData, formatUnits, getAddress, decodeFunctionResult, decodeAbiParameters, concat, AbiEncodingLengthMismatchError, concatHex, toBytes, slice, hexToString, InvalidAddressError, boolToHex, integerRegex, numberToHex, bytesRegex, BytesSizeMismatchError, arrayRegex, UnsupportedPackedAbiType } from './chunk-YILYOOYB.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, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, isFraxlend, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, hasCrossMarginRisk, isEulerType, isAaveV4Type, isInit, isMorphoType, isCompoundV2Type, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isAaveV2Type, isAaveV32Type, isAaveV3Type, isUsdd, isSky, isYLDR, isLista, hasSubAccounts, isTectonicType, isKineticType, isBenqiType } from '@1delta/lender-registry';
4
+ import { Lender, isExactly, isMidnight, isTerm, isTermMax, isTeller, isListaDao, isLiquityFamily, isRiver, isInverse, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, isFraxlend, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, hasCrossMarginRisk, isEulerType, isAaveV4Type, isInit, isMorphoType, isCompoundV2Type, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isMorphoBlue, isAaveV2Type, isAaveV32Type, isAaveV3Type, isUsdd, isSky, 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
- import { fetchTokenLists, fetchTokenList, aavePools, compoundV3Pools, initConfig, morphoPools, compoundV2Pools, eulerVaults, siloMarkets, siloV2LenderKey, siloMarketsV3, siloV3LenderKey, aaveV4Spokes, aaveV4SpokeLenderKey, fluidResolvers, gearboxResolvers, dolomiteConfigs, midnightConfig, termConfig, termMarketsByChain, exactlyConfig, liquityLendersByChain, riverLendersByChain, inverseLendersByChain, llamaLendLendersByChain, usddLendersByChain, skyLendersByChain, frankencoinLendersByChain, resupplyLendersByChain, curvanceLendersByChain, tellerConfigByChain, tellerPoolsByChain, termMaxConfigByChain, aaveReserves, compoundV3Reserves, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, termMaxApiBaseUrl, termMaxLenderKey, inverseConfigFor, inverseChainData, llamaLendConfigFor, llamaLendChainData, llamaLendApiBaseUrl, resupplyConfigFor, fraxlendConfigFor, dssConfigFor, dssChainData, dssDebtToken, dssDebtJoin, frankencoinConfigFor, frankencoinChainData, aaveOracles, morphoTypeMarkets, resolveMidnightApiBase, resolveTermApiBase, llamaLendMarketByVault, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, curvanceConfigFor, aaveTokens, morphoTypeVaults, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxV3LenderKey, midnightMarketsByChain, parseAaveV4SpokeLenderKey, fraxlendPairsFor, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2TokenArray, compoundV2OraclesConfig, compoundV3OraclesData, compoundV3BaseData, compoundV2Reserves, aaveV4Oracles } from '@1delta/data-sdk';
6
+ import { fetchTokenLists, fetchTokenList, aavePools, compoundV3Pools, initConfig, morphoPools, compoundV2Pools, eulerVaults, siloMarkets, siloV2LenderKey, siloMarketsV3, siloV3LenderKey, aaveV4Spokes, aaveV4SpokeLenderKey, fluidResolvers, gearboxResolvers, dolomiteConfigs, midnightConfig, termConfig, termMarketsByChain, exactlyConfig, liquityLendersByChain, riverLendersByChain, inverseLendersByChain, llamaLendLendersByChain, usddLendersByChain, skyLendersByChain, frankencoinLendersByChain, resupplyLendersByChain, curvanceLendersByChain, fraxlendLendersByChain, tellerConfigByChain, tellerPoolsByChain, termMaxConfigByChain, aaveReserves, compoundV3Reserves, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, termMaxApiBaseUrl, termMaxLenderKey, inverseConfigFor, inverseChainData, llamaLendConfigFor, llamaLendChainData, llamaLendApiBaseUrl, resupplyConfigFor, fraxlendConfigFor, dssConfigFor, dssChainData, dssDebtToken, dssDebtJoin, frankencoinConfigFor, frankencoinChainData, aaveOracles, morphoTypeMarkets, resolveMidnightApiBase, resolveTermApiBase, llamaLendMarketByVault, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, curvanceConfigFor, aaveTokens, morphoTypeVaults, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxV3LenderKey, midnightMarketsByChain, parseAaveV4SpokeLenderKey, fraxlendPairsFor, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2TokenArray, compoundV2OraclesConfig, compoundV3OraclesData, compoundV3BaseData, compoundV2Reserves, aaveV4Oracles } from '@1delta/data-sdk';
7
7
  import lodash from 'lodash';
8
8
  import { Chain } from '@1delta/chain-registry';
9
9
  import { multicallRetryUniversal, getEvmClient, getEvmChain, getEvmClientUniversal } from '@1delta/providers';
@@ -6436,6 +6436,9 @@ var getLendersForChain = (c) => {
6436
6436
  for (const l of curvanceLendersByChain(c)) {
6437
6437
  lenders.push(l);
6438
6438
  }
6439
+ for (const l of fraxlendLendersByChain(c)) {
6440
+ lenders.push(l);
6441
+ }
6439
6442
  if (tellerConfigByChain(c)?.tellerV2 && tellerPoolsByChain(c).length > 0) {
6440
6443
  lenders.push(Lender.TELLER);
6441
6444
  }
@@ -21931,7 +21934,7 @@ async function fetchTellerMarkets(chainId) {
21931
21934
  }
21932
21935
  return null;
21933
21936
  };
21934
- const num15 = (i) => {
21937
+ const num16 = (i) => {
21935
21938
  const b = big18(i);
21936
21939
  return b === null ? null : Number(b);
21937
21940
  };
@@ -21941,9 +21944,9 @@ async function fetchTellerMarkets(chainId) {
21941
21944
  config,
21942
21945
  available: big18(base),
21943
21946
  committed: big18(base + 1),
21944
- minRateBps: num15(base + 2),
21947
+ minRateBps: num16(base + 2),
21945
21948
  collateralPerPrincipal: big18(base + 3),
21946
- maxLoanDuration: num15(base + 4),
21949
+ maxLoanDuration: num16(base + 4),
21947
21950
  marketId: big18(base + 5),
21948
21951
  totalAssets: big18(base + 6)
21949
21952
  };
@@ -22906,20 +22909,20 @@ async function fetchInverseMarkets(lender, chainId) {
22906
22909
  if (Object.keys(byAddr).length > 0) {
22907
22910
  const rows = markets.map((market) => {
22908
22911
  const m = byAddr[market.address.toLowerCase()];
22909
- const num15 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
22912
+ const num16 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
22910
22913
  return {
22911
22914
  market,
22912
- totalDebt: num15(m?.totalDebt),
22913
- dolaLiquidity: num15(m?.dolaLiquidity),
22914
- leftToBorrow: num15(m?.leftToBorrow),
22915
- price: num15(m?.price),
22915
+ totalDebt: num16(m?.totalDebt),
22916
+ dolaLiquidity: num16(m?.dolaLiquidity),
22917
+ leftToBorrow: num16(m?.leftToBorrow),
22918
+ price: num16(m?.price),
22916
22919
  borrowPaused: typeof m?.borrowPaused === "boolean" ? m.borrowPaused : null,
22917
- dailyBorrows: num15(m?.dailyBorrows),
22920
+ dailyBorrows: num16(m?.dailyBorrows),
22918
22921
  // The API serves it as a DECIMAL (`replenishmentIncentive: 0.1`),
22919
22922
  // unlike the on-chain bps — normalize here, and fall back to the
22920
22923
  // curated metadata value when the field is missing.
22921
22924
  replenishmentIncentiveBps: (() => {
22922
- const dec2 = num15(m?.replenishmentIncentive);
22925
+ const dec2 = num16(m?.replenishmentIncentive);
22923
22926
  if (dec2 !== null) return Math.round(dec2 * 1e4);
22924
22927
  const meta = Number(market.replenishmentIncentiveBps);
22925
22928
  return Number.isFinite(meta) ? meta : null;
@@ -43887,7 +43890,27 @@ var usddFetcher = {
43887
43890
  return out;
43888
43891
  }
43889
43892
  };
43890
- var FRANKENCOIN_SAVINGS_MODULE = "0x27d9ad987bde08a0d083ef7e0e4043c857a17b38";
43893
+ var ZCHF_ETHEREUM = "0xb58e61c3098d85632df34eecfb899a1ed80921cb";
43894
+ var ZCHF_BRIDGED = "0xd4dd9e2f021bb459d5a5f6c24c12fe09c5d45553";
43895
+ var FRANKENCOIN_SAVINGS_MODULES = [
43896
+ {
43897
+ chainId: Chain.ETHEREUM_MAINNET,
43898
+ // `savingsReferral`, NOT the config's `savingsV2` — see the header.
43899
+ module: "0x27d9ad987bde08a0d083ef7e0e4043c857a17b38",
43900
+ zchf: ZCHF_ETHEREUM
43901
+ },
43902
+ {
43903
+ chainId: Chain.GNOSIS,
43904
+ module: "0xbf594d0fed79ae56d910cb01b5dd4f4c57b04402",
43905
+ zchf: ZCHF_BRIDGED
43906
+ },
43907
+ {
43908
+ chainId: Chain.BASE,
43909
+ module: "0x6426324af1b14df3cd03b2d500529083c5ea61bc",
43910
+ zchf: ZCHF_BRIDGED
43911
+ }
43912
+ ];
43913
+ FRANKENCOIN_SAVINGS_MODULES[0].module;
43891
43914
  var SAVINGS_INFO_URL = "https://api.frankencoin.com/savings/core/info";
43892
43915
  var RATE_ABI2 = [
43893
43916
  {
@@ -43899,58 +43922,70 @@ var RATE_ABI2 = [
43899
43922
  }
43900
43923
  ];
43901
43924
  var ZCHF_SAVINGS_KEY = "ZCHF_SAVINGS";
43925
+ var zchfSavingsKey = (chainId) => chainId === Chain.ETHEREUM_MAINNET ? ZCHF_SAVINGS_KEY : `${ZCHF_SAVINGS_KEY}::${chainId}`;
43902
43926
  var aprFromRatePPM = (ppm) => Number(ppm) / 1e4;
43903
- var fetchRateOnChain = async () => {
43927
+ var fetchRateOnChain = async (d) => {
43904
43928
  const [ppm] = await multicallRetryUniversal({
43905
- chain: Chain.ETHEREUM_MAINNET,
43929
+ chain: d.chainId,
43906
43930
  abi: RATE_ABI2,
43907
- calls: [
43908
- {
43909
- address: FRANKENCOIN_SAVINGS_MODULE,
43910
- name: "currentRatePPM",
43911
- params: []
43912
- }
43913
- ],
43931
+ calls: [{ address: d.module, name: "currentRatePPM", params: [] }],
43914
43932
  allowFailure: false
43915
43933
  });
43916
43934
  if (ppm === void 0 || ppm === null) {
43917
- throw new Error("Frankencoin: unreadable currentRatePPM()");
43935
+ throw new Error(`Frankencoin: unreadable currentRatePPM() on ${d.chainId}`);
43918
43936
  }
43919
43937
  return aprFromRatePPM(ppm);
43920
43938
  };
43921
- var fetchRateFromApi = async () => {
43939
+ var fetchRatesFromApi = async () => {
43922
43940
  const res = await fetch(SAVINGS_INFO_URL, {
43923
43941
  headers: { accept: "application/json" },
43924
43942
  signal: AbortSignal.timeout(8e3)
43925
43943
  });
43926
43944
  if (!res.ok) throw new Error(`Frankencoin: savings info HTTP ${res.status}`);
43927
43945
  const body = await res.json();
43928
- const rate = body?.status?.[String(Chain.ETHEREUM_MAINNET)]?.[FRANKENCOIN_SAVINGS_MODULE]?.rate;
43929
- if (typeof rate !== "number" || !Number.isFinite(rate)) {
43930
- throw new Error("Frankencoin: savings info carried no rate for the module");
43946
+ const out = {};
43947
+ for (const d of FRANKENCOIN_SAVINGS_MODULES) {
43948
+ const perChain = body?.status?.[d.chainId];
43949
+ if (!perChain) continue;
43950
+ const entry = Object.entries(perChain).find(
43951
+ ([addr3]) => addr3.toLowerCase() === d.module.toLowerCase()
43952
+ )?.[1];
43953
+ const rate = entry?.rate;
43954
+ if (typeof rate === "number" && Number.isFinite(rate)) {
43955
+ out[d.chainId] = aprFromRatePPM(rate);
43956
+ }
43931
43957
  }
43932
- return aprFromRatePPM(rate);
43958
+ return out;
43933
43959
  };
43934
43960
  var frankencoinSavingsFetcher = {
43935
43961
  label: "FRANKENCOIN_SAVINGS",
43936
43962
  fetch: async () => {
43937
- const legs = await Promise.allSettled([
43938
- fetchRateOnChain(),
43939
- fetchRateFromApi()
43963
+ const [chainLegs, apiLeg] = await Promise.all([
43964
+ Promise.allSettled(FRANKENCOIN_SAVINGS_MODULES.map(fetchRateOnChain)),
43965
+ fetchRatesFromApi().catch((e) => e)
43940
43966
  ]);
43941
- const onChain = legs[0];
43942
- if (onChain.status === "fulfilled") {
43943
- return { [ZCHF_SAVINGS_KEY]: onChain.value };
43944
- }
43945
- const api = legs[1];
43946
- if (api.status === "fulfilled") {
43947
- return { [ZCHF_SAVINGS_KEY]: api.value };
43967
+ const apiRates = apiLeg instanceof Error ? {} : apiLeg;
43968
+ const out = {};
43969
+ const failures = [];
43970
+ FRANKENCOIN_SAVINGS_MODULES.forEach((d, i) => {
43971
+ const leg = chainLegs[i];
43972
+ if (leg.status === "fulfilled") {
43973
+ out[zchfSavingsKey(d.chainId)] = leg.value;
43974
+ return;
43975
+ }
43976
+ const fromApi = apiRates[d.chainId];
43977
+ if (fromApi !== void 0) {
43978
+ out[zchfSavingsKey(d.chainId)] = fromApi;
43979
+ return;
43980
+ }
43981
+ failures.push(`${d.chainId}: ${String(leg.reason)}`);
43982
+ });
43983
+ if (Object.keys(out).length === 0) {
43984
+ throw new Error(
43985
+ `Frankencoin: every savings module failed (${failures.join("; ")}${apiLeg instanceof Error ? `; api: ${apiLeg.message}` : ""})`
43986
+ );
43948
43987
  }
43949
- throw new Error(
43950
- `Frankencoin: both rate legs failed (chain: ${String(
43951
- onChain.reason
43952
- )}; api: ${String(api.reason)})`
43953
- );
43988
+ return out;
43954
43989
  }
43955
43990
  };
43956
43991
 
@@ -45473,6 +45508,32 @@ var sparkV2Base = (symbol, decimals) => ({
45473
45508
  yieldFetcher: sparkSavingsFetcher
45474
45509
  });
45475
45510
  var SPARK_V2_WITHDRAW_INTENTS = "0x592b7db9906e6f8924c4d74c2a0ab86ce44fdddf";
45511
+ var frankencoinSavingsBase = {
45512
+ reader: "frankencoin-savings",
45513
+ symbol: "ZCHF",
45514
+ brand: "Frankencoin",
45515
+ description: "ZCHF is Frankencoin's decentralised Swiss-franc stablecoin, minted against collateral in permissionless, auction-policed positions. The savings module pays a governance-set rate funded by borrower interest: deposits are never lent on (they sit segregated inside the module) and interest is minted by the protocol into your balance, so there are no shares and no share price. Withdrawals are instant and uncapped, but interest only starts accruing after 3 days and a top-up restarts that clock pro-rata, so a short stay can earn nothing.",
45516
+ decimals: 18,
45517
+ isRebasing: true,
45518
+ isMintable: true,
45519
+ withdrawalMode: "instant",
45520
+ // The exit is instant; the YIELD is not. `INTEREST_DELAY` is 3 days and a
45521
+ // top-up re-weights the whole position's clock, so a short stay earns zero.
45522
+ yieldWarmupSeconds: 3 * 86400,
45523
+ // `Δticks × saved / 1e6 / 365 days` — linear, compounding only when someone
45524
+ // calls `refresh`.
45525
+ accrual: "linear",
45526
+ // The module is a registered ZCHF minter, so the token already grants it an
45527
+ // implicit infinite allowance — verified on all three chains.
45528
+ needsDepositApproval: false,
45529
+ // Not an assumption: deposits are never lent on. They sit segregated inside
45530
+ // the module (`totalAssets` IS the module's own ZCHF balance) and the exit
45531
+ // is paid from it, so the PRINCIPAL is fully reserved rather than merely
45532
+ // over-collateralised. What is a claim on the protocol is the INTEREST,
45533
+ // which is minted on refresh — stated in the description.
45534
+ solvency: "overcollateralized",
45535
+ yieldFetcher: frankencoinSavingsFetcher
45536
+ };
45476
45537
  var ybMarket = (symbol, underlying, underlyingDecimals, address, capacityContract, yieldKey) => ({
45477
45538
  reader: "yieldbasis-lt",
45478
45539
  address,
@@ -46286,48 +46347,37 @@ var SINGLE_CHAIN_ENTRIES = {
46286
46347
  yieldKey: REUSDE_KEY
46287
46348
  },
46288
46349
  {
46289
- // Frankencoin savings module — a Swiss-franc savings account, not
46290
- // a vault. There is NO share token: `save(amount)` books ZCHF into
46291
- // an internal `savings(address)` account and `withdraw(target,
46292
- // amount)` pays it back out, so the position is a balance that
46293
- // grows in place (`isRebasing: true`, `exchangeRate` pinned at
46294
- // par) and the module's own ZCHF balance is the whole book. Hence
46295
- // the bespoke `frankencoin-savings` reader.
46350
+ // Frankencoin savings module, Ethereum the reference deployment
46351
+ // and 89 % of the 13.66M ZCHF book. See `frankencoinSavingsBase`.
46296
46352
  //
46297
- // TRAP — the published address config is stale. `@frankencoin/zchf`
46298
- // exports `savingsV2 = 0x3BF301B0…`, which now runs at 1 % and
46299
- // holds 17k ZCHF; the live module is the `savingsReferral`
46300
- // deployment below, at 3.5 % holding 12.17M (verified on-chain
46301
- // 2026-08-04, `currentRatePPM() = 35000`). Both answer
46302
- // `currentRatePPM()`, so only the balance distinguishes them.
46303
- //
46304
- // `symbol: 'ZCHF'` is deliberate. `fetchPublic` composes
46305
- // `displayName` from the *underlying's* token-list symbol
46306
- // (→ "Frankencoin ZCHF"), so `symbol` only drives `name` and the
46307
- // ticker a vault list renders — and the honest ticker for a
46308
- // position denominated 1:1 in ZCHF is ZCHF. Inventing `sZCHF`
46309
- // would name a token that does not exist, and `svZCHF` is already
46310
- // taken by an unrelated third-party ERC-4626 wrapper
46311
- // (0x637f00cA…, ~1 ZCHF of TVL) that would then be conflated with
46312
- // this row.
46353
+ // TRAP — the published address config is stale HERE and only here.
46354
+ // `@frankencoin/zchf` exports `savingsV2 = 0x3BF301B0…`, which now
46355
+ // runs at 1 % and holds 17k ZCHF; the live module is the
46356
+ // `savingsReferral` deployment below, at 3.5 % holding 12.13M
46357
+ // (re-verified 2026-08-12, `currentRatePPM() = 35000`). Both
46358
+ // answer `currentRatePPM()`, so only the balance distinguishes
46359
+ // them. The bridged chains have no such split.
46360
+ ...frankencoinSavingsBase,
46361
+ address: FRANKENCOIN_SAVINGS_MODULES[0].module,
46362
+ underlying: ZCHF_ETHEREUM,
46363
+ yieldKey: zchfSavingsKey(Chain.ETHEREUM_MAINNET)
46364
+ }
46365
+ ],
46366
+ "100": [
46367
+ {
46368
+ // Frankencoin savings module, Gnosis — 1,257,396 ZCHF at
46369
+ // 2026-08-12, the second-largest after Ethereum and by far the
46370
+ // most active bridged chain (4,853 saves / 13,249 withdrawals).
46371
+ // Its own module contract with its own stored rate, kept at the
46372
+ // Ethereum 35 000 ppm by a CCIP leadrate push.
46313
46373
  //
46314
- // Exit is instant and never short (withdrawals are paid from the
46315
- // module's own balance), but the YIELD is not instant:
46316
- // `INTEREST_DELAY` is 3 days and a top-up re-weights the account's
46317
- // tick counter, so exiting early can realise ~0 %.
46318
- reader: "frankencoin-savings",
46319
- address: "0x27d9ad987bde08a0d083ef7e0e4043c857a17b38",
46320
- underlying: "0xb58e61c3098d85632df34eecfb899a1ed80921cb",
46321
- // ZCHF
46322
- symbol: "ZCHF",
46323
- brand: "Frankencoin",
46324
- description: "ZCHF is Frankencoin's decentralised Swiss-franc stablecoin, minted against collateral in permissionless, auction-policed positions. The savings module pays a governance-set rate funded by borrower interest: deposits are never lent on (they sit segregated inside the module) and interest is minted by the protocol into your balance, so there are no shares and no share price. Withdrawals are instant and uncapped, but interest only starts accruing after 3 days and a top-up restarts that clock pro-rata, so a short stay can earn nothing.",
46325
- decimals: 18,
46326
- isRebasing: true,
46327
- isMintable: true,
46328
- withdrawalMode: "instant",
46329
- yieldFetcher: frankencoinSavingsFetcher,
46330
- yieldKey: ZCHF_SAVINGS_KEY
46374
+ // 62.8 % of this book belongs to the `svZCHF` ERC-4626 wrapper —
46375
+ // see the warning on `frankencoinSavingsBase` before adding a row
46376
+ // for it.
46377
+ ...frankencoinSavingsBase,
46378
+ address: FRANKENCOIN_SAVINGS_MODULES[1].module,
46379
+ underlying: ZCHF_BRIDGED,
46380
+ yieldKey: zchfSavingsKey(Chain.GNOSIS)
46331
46381
  }
46332
46382
  ],
46333
46383
  "42161": [
@@ -46364,6 +46414,17 @@ var SINGLE_CHAIN_ENTRIES = {
46364
46414
  withdrawalMode: "request-based",
46365
46415
  yieldFetcher: yoFetcher,
46366
46416
  yieldKey: "Yield Optimizer ETH::YOETH"
46417
+ },
46418
+ {
46419
+ // Frankencoin savings module, Base — 255,196 ZCHF at 2026-08-12.
46420
+ // Note the module address is the SAME on Base and Optimism
46421
+ // (`0x6426324a…`, one CREATE2 family); the Optimism twin holds
46422
+ // 1 ZCHF and is deliberately unregistered — see
46423
+ // `FRANKENCOIN_SAVINGS_MODULES`.
46424
+ ...frankencoinSavingsBase,
46425
+ address: FRANKENCOIN_SAVINGS_MODULES[2].module,
46426
+ underlying: ZCHF_BRIDGED,
46427
+ yieldKey: zchfSavingsKey(Chain.BASE)
46367
46428
  }
46368
46429
  ],
46369
46430
  "43114": [
@@ -53716,7 +53777,7 @@ async function fetchVaultSupplyShares(chainId, core, entries, marketIdsByVault,
53716
53777
  });
53717
53778
  return map;
53718
53779
  }
53719
- function computeVaultAllocation(vaultAddress, decimals, totalAssetsFormatted, feePercent, priceUsd, marketIds, rateMap, positionMap, tokenList, uidCtx) {
53780
+ function computeVaultAllocation(vaultAddress, decimals, totalAssetsFormatted, feePercent2, priceUsd, marketIds, rateMap, positionMap, tokenList, uidCtx) {
53720
53781
  if (totalAssetsFormatted <= 0) {
53721
53782
  return { depositRate: 0, exposures: [], liquidityFormatted: 0 };
53722
53783
  }
@@ -53761,13 +53822,13 @@ function computeVaultAllocation(vaultAddress, decimals, totalAssetsFormatted, fe
53761
53822
  const grossApr = weighted / totalAssetsFormatted;
53762
53823
  const idle = Math.max(0, totalAssetsFormatted - allocated);
53763
53824
  return {
53764
- depositRate: grossApr * (1 - feePercent / 100),
53825
+ depositRate: grossApr * (1 - feePercent2 / 100),
53765
53826
  // Tag uninvested deposits as an idle entry so the breakdown sums to ~100%.
53766
53827
  exposures: withIdleExposure(exposures, totalAssetsFormatted, priceUsd),
53767
53828
  liquidityFormatted: Math.min(totalAssetsFormatted, idle + withdrawable)
53768
53829
  };
53769
53830
  }
53770
- function computeV2Allocation(decimals, totalAssetsFormatted, feePercent, priceUsd, marketAssetsRaw, rateMap, tokenList, uidCtx) {
53831
+ function computeV2Allocation(decimals, totalAssetsFormatted, feePercent2, priceUsd, marketAssetsRaw, rateMap, tokenList, uidCtx) {
53771
53832
  if (totalAssetsFormatted <= 0) {
53772
53833
  return { depositRate: 0, exposures: [], liquidityFormatted: 0 };
53773
53834
  }
@@ -53808,7 +53869,7 @@ function computeV2Allocation(decimals, totalAssetsFormatted, feePercent, priceUs
53808
53869
  const grossApr = weighted / totalAssetsFormatted;
53809
53870
  const idle = Math.max(0, totalAssetsFormatted - allocated);
53810
53871
  return {
53811
- depositRate: grossApr * (1 - feePercent / 100),
53872
+ depositRate: grossApr * (1 - feePercent2 / 100),
53812
53873
  exposures: withIdleExposure(exposures, totalAssetsFormatted, priceUsd),
53813
53874
  liquidityFormatted: Math.min(totalAssetsFormatted, idle + withdrawable)
53814
53875
  };
@@ -55028,7 +55089,7 @@ function safeBigInt(v) {
55028
55089
  return ZERO3;
55029
55090
  }
55030
55091
  }
55031
- function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent, evkIndex) {
55092
+ function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent2, evkIndex) {
55032
55093
  if (!strategies?.length) return 0;
55033
55094
  const totalAssets = safeBigInt(totalAssetsRaw);
55034
55095
  if (totalAssets === ZERO3) return 0;
@@ -55045,7 +55106,7 @@ function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent, evkInd
55045
55106
  if (weightedRay === ZERO3) return 0;
55046
55107
  const apyRayPerAsset = weightedRay / totalAssets;
55047
55108
  const grossPercent = apyToAprPercent(Number(apyRayPerAsset) / RAY_TO_PERCENT3);
55048
- const netPercent = grossPercent * (1 - feePercent / 100);
55109
+ const netPercent = grossPercent * (1 - feePercent2 / 100);
55049
55110
  return Number.isFinite(netPercent) ? netPercent : 0;
55050
55111
  }
55051
55112
  function computeRealLiquidity(strategies, totalAssetsRaw, evkIndex) {
@@ -61503,6 +61564,12 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
61503
61564
  // queue window is per-asset and governance-mutable.
61504
61565
  withdrawalCooldownSeconds: state.withdrawalCooldownSeconds ?? entry.withdrawalCooldownSeconds,
61505
61566
  withdrawFeeBps: state.withdrawFeeBps,
61567
+ // Term-sheet inputs that no reader can derive — see the registry's
61568
+ // docstrings. Passed through verbatim so the sheet can stop hardcoding
61569
+ // "compounds per second" and "needs an approval" for every vault.
61570
+ yieldWarmupSeconds: entry.yieldWarmupSeconds,
61571
+ accrual: entry.accrual,
61572
+ needsDepositApproval: entry.needsDepositApproval,
61506
61573
  instantRedeemEnabled: state.instantRedeemEnabled,
61507
61574
  inventoryContract: entry.inventoryContract?.toLowerCase(),
61508
61575
  withdrawQueue: state.withdrawQueue ?? entry.withdrawQueue?.toLowerCase(),
@@ -64346,7 +64413,8 @@ function feePhrase(fee) {
64346
64413
  }
64347
64414
  const rebate = fee.value < 0 ? " rebate" : "";
64348
64415
  const qualifier = fee.indicative ? " (estimated, resolved at execution)" : "";
64349
- return `${fee.label}: ${amount3}${rebate}${qualifier}`;
64416
+ const bound = fee.mutable && fee.cap != null ? `, governance-set up to a maximum of ${fee.unit === "bps" ? `${fee.cap} bps` : pct(fee.cap)}` : fee.mutable ? ", governance-set" : "";
64417
+ return `${fee.label}: ${amount3}${rebate}${bound}${qualifier}`;
64350
64418
  }
64351
64419
  function maturityPhrase(m) {
64352
64420
  if (m.kind === "fixed-date" && m.maturity)
@@ -64440,7 +64508,8 @@ function supplyHeadline(s) {
64440
64508
  const exit = exitPhrase[String(s.exit.mode)] ?? (s.exit.settlement === "sync" ? "withdraw any time" : "delayed withdrawal");
64441
64509
  const cooldown = s.exit.cooldownSecs ? ` (${duration(s.exit.cooldownSecs)})` : "";
64442
64510
  const mat = s.maturity.kind === "perpetual" ? "" : ` ${maturityPhrase(s.maturity)}`;
64443
- return `${rate}${mat} \xB7 ${exit}${cooldown}`;
64511
+ const warmup = s.rate.warmupSecs ? ` \xB7 earns after ${duration(s.rate.warmupSecs)}` : "";
64512
+ return `${rate}${mat}${warmup} \xB7 ${exit}${cooldown}`;
64444
64513
  }
64445
64514
  function borrowHeadline(b) {
64446
64515
  const rate = b.rate.kind === "zero-interest" ? "No ongoing interest" : b.rate.kind === "user-set" ? (
@@ -64744,7 +64813,8 @@ var TERM_PROFILES = [
64744
64813
  borrow: {
64745
64814
  description: "A CDP where YOU set the interest rate. A one-off upfront fee is charged at open, and there is a minimum debt size.",
64746
64815
  implications: [
64747
- "Your collateral can be REDEEMED at par while the position is perfectly healthy, if you carry the lowest interest rate on the branch. Raising your rate is the only defence.",
64816
+ "Your collateral can be REDEEMED at par while the position is perfectly healthy, if you carry the lowest interest rate on the branch. Raising your rate is the defence \u2014 but note a redemption that leaves you under the minimum debt puts the trove in a ZOMBIE state that must be topped back up or closed.",
64817
+ "If the branch ever SHUTS DOWN (system collateral ratio below its floor, or an oracle failure), that changes: urgent redemptions then pay the redeemer a 2 % collateral bonus against any trove regardless of rate, so the queue position your rate bought is worth nothing and you are no longer left whole.",
64748
64818
  "You pay a one-off upfront fee equal to roughly a week of interest at open, and again whenever you adjust the rate.",
64749
64819
  "There is a minimum debt size; you cannot leave a position below it."
64750
64820
  ]
@@ -64758,7 +64828,9 @@ var TERM_PROFILES = [
64758
64828
  description: "A CDP with NO ongoing interest. The entire borrowing cost is a one-off decaying mint fee charged at open.",
64759
64829
  implications: [
64760
64830
  "There is no APR \u2014 the cost is the mint fee, so a short-held loan is expensive and a long-held one is cheap.",
64761
- "Your collateral can be redeemed at par while healthy."
64831
+ "Your collateral can be redeemed at par while the position is perfectly healthy \u2014 permissionlessly, by any holder of the stablecoin, whenever it trades below its target.",
64832
+ "Redemptions here hit the LOWEST-COLLATERALISED troves first. There is no interest rate to raise (this protocol charges none), so the only defence is adding collateral or repaying.",
64833
+ "If you are redeemed, collateral left over above the redeemed debt is NOT returned automatically \u2014 you have to claim it from the surplus balance."
64762
64834
  ]
64763
64835
  }
64764
64836
  }),
@@ -64835,6 +64907,27 @@ var TERM_PROFILES = [
64835
64907
  ]
64836
64908
  }
64837
64909
  }),
64910
+ P({
64911
+ id: "morpho.blue@v1",
64912
+ name: "Morpho Blue isolated market",
64913
+ family: "morpho-blue",
64914
+ supply: {
64915
+ description: "An isolated two-asset market whose parameters \u2014 collateral, oracle, interest-rate model and LLTV \u2014 are fixed when the market is created and cannot be changed afterwards.",
64916
+ implications: [
64917
+ "Nobody can raise this market\u2019s LLTV, swap its interest-rate model or point it at a different collateral. Those are set once, at creation.",
64918
+ "What CAN still change: the protocol fee on interest (governance-set, capped at 25 %), and \u2014 where the oracle contract behind the fixed oracle address is itself upgradeable \u2014 the price it reports. Check the oracle block.",
64919
+ "Immutability cuts both ways: a market created with a bad oracle or an aggressive LLTV cannot be fixed either, and nobody can pause it for you."
64920
+ ]
64921
+ },
64922
+ borrow: {
64923
+ description: "Borrow against a single collateral in an isolated market whose risk parameters are fixed at creation.",
64924
+ implications: [
64925
+ "Your liquidation threshold is the LLTV the market was created with and cannot be moved under you.",
64926
+ "There is no governance pause and no parameter rescue \u2014 the market runs as deployed."
64927
+ ]
64928
+ },
64929
+ docsUrl: "https://docs.morpho.org/morpho/concepts/markets"
64930
+ }),
64838
64931
  // ── Vaults ───────────────────────────────────────────────────────────────
64839
64932
  P({
64840
64933
  id: "vault.lending@v1",
@@ -65807,7 +65900,16 @@ function buildRate2(input, t, maturity) {
65807
65900
  },
65808
65901
  aprTotal: total,
65809
65902
  basis: "apr-nominal",
65810
- compounding: kind === "none" ? "none" : "per-second",
65903
+ // `per-second` is right for a vault whose share price grows continuously,
65904
+ // which is nearly all of them — but not for a LINEAR accrual. Frankencoin's
65905
+ // savings module books `Δticks × saved / 1e6 / 365 days` and only compounds
65906
+ // if someone happens to call `refresh`, so claiming per-second here would
65907
+ // imply an APY ~2 % relative above what it actually pays. Providers say so
65908
+ // through `accrual`.
65909
+ compounding: kind === "none" ? "none" : input.accrual === "linear" ? "none" : "per-second",
65910
+ // A warm-up is neither a withdrawal lock nor a governance notice period —
65911
+ // see `RateTerms.warmupSecs`. Absent ⇒ earns from the first block.
65912
+ warmupSecs: input.yieldWarmupSeconds && input.yieldWarmupSeconds > 0 ? input.yieldWarmupSeconds : void 0,
65811
65913
  source,
65812
65914
  // A PT's discount is fixed at purchase; every other vault floats.
65813
65915
  isLocked: kind === "fixed-term" && termIsBacked,
@@ -65988,7 +66090,13 @@ function buildAvailability2(input, now) {
65988
66090
  blockedBy,
65989
66091
  gating: gated ? "whitelist" : "permissionless",
65990
66092
  cap: cap != null && cap !== "0" ? cap : void 0,
65991
- requires: ["token-approval"],
66093
+ // Almost every vault pulls the deposit with `transferFrom` and therefore
66094
+ // needs an allowance — but not all. Frankencoin's savings modules are
66095
+ // registered ZCHF minters, and the token grants a registered minter an
66096
+ // implicit infinite allowance, so their deposit route emits NO approval.
66097
+ // Asserting one here would make the sheet contradict the envelope built
66098
+ // beside it, which is worse than saying nothing.
66099
+ requires: input.needsDepositApproval === false ? [] : ["token-approval"],
65992
66100
  opensWith: "standalone"
65993
66101
  };
65994
66102
  }
@@ -66281,8 +66389,6 @@ function splitUid(uid) {
66281
66389
  if (!venue || !chainId || !ref) return void 0;
66282
66390
  return { venue, chainId, ref };
66283
66391
  }
66284
-
66285
- // src/earn/labels.ts
66286
66392
  var VENUE_KIND_LABELS = {
66287
66393
  lending: "Lending markets",
66288
66394
  vault: "Vaults"
@@ -66350,38 +66456,40 @@ var RATE_SOURCE_LABELS = {
66350
66456
  oracle: "Oracle",
66351
66457
  realized: "Realized"
66352
66458
  };
66353
- var VENUE_BRANDS = {
66354
- MORPHO_BLUE: "Morpho Blue",
66355
- MORPHO_MIDNIGHT: "Morpho Midnight",
66356
- FLUID: "Fluid",
66357
- GEARBOX_V3: "Gearbox V3",
66358
- AAVE_V4: "Aave V4",
66359
- AAVE_V3: "Aave V3",
66360
- AAVE_V2: "Aave V2",
66361
- SKY: "Sky",
66362
- USDD: "USDD",
66363
- LIQUITY_V2: "Liquity V2",
66364
- SILO_V2: "Silo V2",
66365
- SILO_V3: "Silo V3",
66366
- EXACTLY: "Exactly",
66367
- TELLER: "Teller",
66368
- TERM_FINANCE: "Term Finance",
66369
- TERMMAX: "TermMax",
66370
- LLAMALEND: "LlamaLend",
66371
- CURVANCE: "Curvance",
66372
- INVERSE: "Inverse",
66373
- FRANKENCOIN: "Frankencoin",
66374
- RIVER: "River",
66375
- RESUPPLY: "Resupply",
66376
- TANGENT: "Tangent",
66377
- DOLOMITE: "Dolomite",
66459
+ var SYNTHETIC_FAMILIES = ["AAVE_V4", "COMPOUND_V3", "SWAYLEND"];
66460
+ var FAMILY_KEYS = [
66461
+ .../* @__PURE__ */ new Set([
66462
+ ...Object.values(Lender),
66463
+ ...SYNTHETIC_FAMILIES
66464
+ ])
66465
+ ].sort((a, b) => a.length - b.length || a.localeCompare(b));
66466
+ var BRAND_OVERRIDES = {
66378
66467
  LISTA_DAO: "Lista",
66379
66468
  FLUX_FINANCE: "Flux",
66380
- COMPOUND_V2: "Compound V2",
66381
- COMPOUND_V3: "Compound V3",
66382
- EULER_V2: "Euler V2",
66383
- INIT: "Init"
66384
- };
66469
+ TERMMAX: "TermMax",
66470
+ LLAMALEND: "LlamaLend",
66471
+ USDD: "USDD",
66472
+ USDAF: "USDaf",
66473
+ DTRINITY: "dTRINITY",
66474
+ DFORCE: "dForce",
66475
+ OVIX: "0VIX",
66476
+ WE_PIGGY: "WePiggy",
66477
+ ZEROLEND: "ZeroLend",
66478
+ HYPERLEND: "HyperLend",
66479
+ HYPURRFI: "HypurrFi",
66480
+ HYPERYIELD: "HyperYield",
66481
+ LAYERBANK_V3: "LayerBank V3",
66482
+ TAKOTAKO: "TakoTako",
66483
+ SWAYLEND: "Swaylend",
66484
+ BENQI: "BENQI",
66485
+ YLDR: "YLDR",
66486
+ YEI: "YEI",
66487
+ RMM: "RMM",
66488
+ PAC: "PAC"
66489
+ };
66490
+ function titleCaseKey(key3) {
66491
+ return key3.split(/[_-]/).filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase()).join(" ");
66492
+ }
66385
66493
  var VAULT_PROVIDER_BRANDS = {
66386
66494
  fluid: "Fluid",
66387
66495
  gearbox: "Gearbox",
@@ -66405,21 +66513,23 @@ function isInstanceSegment(seg) {
66405
66513
  if (/^0X[0-9A-F]+$/i.test(seg)) return true;
66406
66514
  return seg.length >= 8 && /^[0-9A-F]+$/i.test(seg);
66407
66515
  }
66408
- function venueBrand(venue) {
66409
- if (venue.startsWith("vault.")) {
66410
- const provider = venue.slice("vault.".length);
66411
- return VAULT_PROVIDER_BRANDS[provider] ?? provider;
66516
+ function venueBrandKey(venue) {
66517
+ if (venue.startsWith(VAULT_VENUE_PREFIX)) return venue;
66518
+ const key3 = venue.toUpperCase();
66519
+ for (const family of FAMILY_KEYS) {
66520
+ if (key3 === family || key3.startsWith(family + "_")) return family;
66412
66521
  }
66413
- const segments = venue.split("_");
66522
+ const segments = key3.split("_");
66414
66523
  const cut = segments.findIndex(isInstanceSegment);
66415
- const family = (cut > 0 ? segments.slice(0, cut) : segments).join("_");
66416
- if (VENUE_BRANDS[family]) return VENUE_BRANDS[family];
66417
- let best;
66418
- for (const key3 of Object.keys(VENUE_BRANDS)) {
66419
- if (family.startsWith(key3) && (!best || key3.length > best.length))
66420
- best = key3;
66524
+ return (cut > 0 ? segments.slice(0, cut) : segments).join("_");
66525
+ }
66526
+ function venueBrand(venue) {
66527
+ if (venue.startsWith(VAULT_VENUE_PREFIX)) {
66528
+ const provider = venue.slice(VAULT_VENUE_PREFIX.length);
66529
+ return VAULT_PROVIDER_BRANDS[provider] ?? titleCaseKey(provider);
66421
66530
  }
66422
- return best ? VENUE_BRANDS[best] : family;
66531
+ const family = venueBrandKey(venue);
66532
+ return BRAND_OVERRIDES[family] ?? titleCaseKey(family);
66423
66533
  }
66424
66534
  var EARN_LABELS = {
66425
66535
  venueKind: VENUE_KIND_LABELS,
@@ -66439,9 +66549,29 @@ function earnLabel(dimension, key3) {
66439
66549
  function earnDescription(dimension, key3) {
66440
66550
  return EARN_DESCRIPTIONS[dimension][key3];
66441
66551
  }
66552
+ function stripBrandWords(name, venue) {
66553
+ const brandWords = new Set(
66554
+ (venue ? `${venueBrand(venue)} ${venueBrandKey(venue)}` : "").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean)
66555
+ );
66556
+ const words = name.trim().split(/\s+/);
66557
+ let i = 0;
66558
+ while (i < words.length && brandWords.has(words[i].toLowerCase())) i++;
66559
+ return words.slice(i).join(" ").trim();
66560
+ }
66561
+ function namesToken(text, token) {
66562
+ const wanted = token.toLowerCase();
66563
+ return text.split(/[^a-zA-Z0-9]+/).some((t) => t.toLowerCase() === wanted);
66564
+ }
66442
66565
  function earnMarketLabel(input) {
66443
66566
  const asset = input.assetSymbol?.trim();
66444
66567
  if (!asset) return input.fallbackName ?? "";
66568
+ const detail = stripBrandWords(
66569
+ input.lenderMarketName?.trim() ?? "",
66570
+ input.venue
66571
+ );
66572
+ if (detail && detail.toLowerCase() !== asset.toLowerCase()) {
66573
+ return namesToken(detail, asset) ? detail : `${asset} \xB7 ${detail}`;
66574
+ }
66445
66575
  const collaterals = (input.collateralSymbols ?? []).map((c) => c?.trim()).filter((c) => !!c);
66446
66576
  const distinct = [...new Set(collaterals)];
66447
66577
  if (distinct.length === 1) return `${asset} \xB7 vs ${distinct[0]}`;
@@ -66458,6 +66588,21 @@ function isIlliquid(input) {
66458
66588
  if (input.liquidityUsd === void 0) return false;
66459
66589
  return input.liquidityUsd <= 0;
66460
66590
  }
66591
+ var CATEGORY_PROVIDERS = /* @__PURE__ */ new Set(["savings", "lst"]);
66592
+ function resolveEarnIdentity(venue, brand) {
66593
+ const isVault = venue.startsWith(VAULT_VENUE_PREFIX);
66594
+ const provider = isVault ? venue.slice(VAULT_VENUE_PREFIX.length) : venue;
66595
+ const providerBrand = venueBrand(venue);
66596
+ const key3 = venueBrandKey(venue);
66597
+ if (isVault && CATEGORY_PROVIDERS.has(provider)) {
66598
+ return { protocol: { key: key3, name: brand?.trim() || providerBrand } };
66599
+ }
66600
+ const name = brand?.trim();
66601
+ if (!name || name.toLowerCase() === providerBrand.toLowerCase()) {
66602
+ return { protocol: { key: key3, name: providerBrand } };
66603
+ }
66604
+ return { protocol: { key: key3, name: providerBrand }, curator: { name } };
66605
+ }
66461
66606
 
66462
66607
  // src/earn/normalize.ts
66463
66608
  function num12(v) {
@@ -66604,6 +66749,15 @@ function earnMarketFromVault(row, chainId, opts = {}) {
66604
66749
  venueKind: "vault",
66605
66750
  // Curator first (it names the actual operator), then the provider brand.
66606
66751
  brand: str5(row.curatorName) ?? venueBrand(vaultVenue(provider)),
66752
+ // What the vault is BUILT ON, kept apart from who runs it — see
66753
+ // `resolveEarnIdentity` for why this is not simply provider-vs-brand.
66754
+ ...withCuratorEntity(
66755
+ resolveEarnIdentity(
66756
+ vaultVenue(provider),
66757
+ str5(row.curatorName)
66758
+ ),
66759
+ str5(row.curatorEntity)
66760
+ ),
66607
66761
  name: str5(info.name) ?? str5(row.displayName) ?? str5(row.name),
66608
66762
  ref: address,
66609
66763
  logoURI: str5(info.logoURI) ?? str5(row.underlyingInfo?.asset?.logoURI),
@@ -66739,6 +66893,10 @@ function amount(raw, formatted, usd, decimals) {
66739
66893
  usd: num12(usd)
66740
66894
  };
66741
66895
  }
66896
+ function withCuratorEntity(id, entity) {
66897
+ if (!id.curator || !entity) return id;
66898
+ return { ...id, curator: { ...id.curator, entity } };
66899
+ }
66742
66900
  function sum(a, b) {
66743
66901
  if (a === void 0 && b === void 0) return void 0;
66744
66902
  return (a ?? 0) + (b ?? 0);
@@ -66824,6 +66982,9 @@ function toVaultTermInput(vault, provider, chainId) {
66824
66982
  swapFeeRate: num13(row.feeRate),
66825
66983
  redemptionDiscountBps: num13(row.redemptionDiscountBps),
66826
66984
  instantRedeemEnabled: bool2(row.instantRedeemEnabled),
66985
+ yieldWarmupSeconds: num13(row.yieldWarmupSeconds),
66986
+ accrual: str6(row.accrual),
66987
+ needsDepositApproval: bool2(row.needsDepositApproval),
66827
66988
  isMintable: bool2(row.isMintable),
66828
66989
  depositCapacity: str6(row.depositCapacity),
66829
66990
  supplyCap: str6(row.supplyCap),
@@ -66885,6 +67046,9 @@ function vaultTermInputFromEarnMarket(m) {
66885
67046
  swapFeeRate: num13(meta.feeRate),
66886
67047
  redemptionDiscountBps: num13(meta.redemptionDiscountBps),
66887
67048
  instantRedeemEnabled: bool2(meta.instantRedeemEnabled),
67049
+ yieldWarmupSeconds: num13(meta.yieldWarmupSeconds),
67050
+ accrual: str6(meta.accrual),
67051
+ needsDepositApproval: bool2(meta.needsDepositApproval),
66888
67052
  // `canDeposit` already folds in the cap, the pause and the gate, so it is
66889
67053
  // the authoritative answer — but the REASON is what a disabled CTA renders,
66890
67054
  // and that only survives in the raw fields.
@@ -66962,6 +67126,9 @@ function vaultTermInputFromSourceRow(row, chainId) {
66962
67126
  swapFeeRate: num13(meta.feeRate),
66963
67127
  redemptionDiscountBps: num13(meta.redemptionDiscountBps),
66964
67128
  instantRedeemEnabled: bool2(meta.instantRedeemEnabled),
67129
+ yieldWarmupSeconds: num13(meta.yieldWarmupSeconds),
67130
+ accrual: str6(meta.accrual),
67131
+ needsDepositApproval: bool2(meta.needsDepositApproval),
66965
67132
  isMintable: bool2(meta.isMintable),
66966
67133
  depositCapacity: str6(meta.depositCapacity) ?? str6(meta.maxDeposit),
66967
67134
  supplyCap: str6(meta.supplyCap),
@@ -67913,7 +68080,12 @@ var ROW_DESCRIPTOR_KEYS = [
67913
68080
  "curvance",
67914
68081
  "broker",
67915
68082
  "collateralProvider",
67916
- "loanProvider"
68083
+ "loanProvider",
68084
+ // Morpho Blue's protocol fee — the ONE parameter of an otherwise immutable
68085
+ // market that governance can move. Nested under `params.market` on the
68086
+ // in-package shape but a top-level field on `/pools/latest`, so without it
68087
+ // here the flat path reports a confident 0 % on every Blue market.
68088
+ "fee"
67917
68089
  ];
67918
68090
  function resolveMarketDescriptors(row, ctxMarket) {
67919
68091
  const fromParams = pick2(row, "params.market");
@@ -68571,6 +68743,7 @@ var liquityAdapter = {
68571
68743
  const minDebt = liquity.minDebt != null ? String(liquity.minDebt) : void 0;
68572
68744
  const minApr = typeof liquity.minAnnualInterestRate === "string" || typeof liquity.minAnnualInterestRate === "number" ? Number(liquity.minAnnualInterestRate) / 1e18 * 100 : void 0;
68573
68745
  const maxApr = typeof liquity.maxAnnualInterestRate === "string" || typeof liquity.maxAnnualInterestRate === "number" ? Number(liquity.maxAnnualInterestRate) / 1e18 * 100 : void 0;
68746
+ const shutdown = Boolean(liquity.shutdown);
68574
68747
  const wadPct = (v) => v == null ? void 0 : Number(v) / 1e18;
68575
68748
  const spPenalty = wadPct(liquity.liquidationPenaltySP);
68576
68749
  const redistPenalty = wadPct(liquity.liquidationPenaltyRedistribution);
@@ -68639,20 +68812,41 @@ var liquityAdapter = {
68639
68812
  penalties: penalties.length ? penalties : void 0,
68640
68813
  badDebt: "redistributed",
68641
68814
  redeemable: true,
68642
- redemption: {
68643
- // Not governance and not a liquidation: any holder of the stable
68644
- // may redeem it for collateral at any time.
68815
+ // Two different mechanisms share the word "redemption", and the
68816
+ // ordinary one stops applying the moment a branch shuts down.
68817
+ //
68818
+ // NORMAL: rate-ordered, fee stays in the trove, borrower ~USD-neutral.
68819
+ // SHUTDOWN (TCR < SCR or oracle failure, permanent): **urgent
68820
+ // redemptions** run at a 2 % collateral BONUS to the redeemer, against
68821
+ // any trove — so the queue position a borrower bought with their rate
68822
+ // is worthless, and they are no longer neutral, they are down 2 %.
68823
+ //
68824
+ // Asserting the normal terms unconditionally told exactly the wrong
68825
+ // story to the only borrowers who could still act on it.
68826
+ redemption: shutdown ? {
68645
68827
  trigger: "permissionless-arbitrage",
68646
- // It only pays while the stable trades under its target — which is
68647
- // the point: redemptions are what push it back up.
68828
+ // No longer peg-driven: the 2 % bonus pays regardless.
68829
+ driver: "always",
68830
+ // Urgent redemptions ignore the interest-rate ordering.
68831
+ order: "pro-rata",
68832
+ valueImpact: "loss",
68833
+ defence: "This branch is shut down and urgent redemptions pay a 2 % collateral bonus, so your interest rate no longer protects you. Closing or repaying the position is the only way out from under it."
68834
+ } : {
68835
+ // Not governance and not a liquidation: any holder of the
68836
+ // stable can trigger it, without permission.
68837
+ trigger: "permissionless-arbitrage",
68838
+ // Permissionless does NOT mean constant — it only pays while
68839
+ // the stable trades under target, which is the point:
68840
+ // redemptions are what push it back up.
68648
68841
  driver: "below-peg",
68649
68842
  // The rate you chose IS your position in the queue.
68650
68843
  order: "lowest-rate-first",
68651
- // The redemption fee stays in the position as extra collateral, so
68844
+ // The redemption fee stays in the trove as extra collateral, so
68652
68845
  // the borrower is ~USD-neutral; what is lost is EXPOSURE.
68653
68846
  valueImpact: "usd-neutral",
68654
- // The ordering is already stated by `order`; say only what to DO.
68655
- defence: "Raising your rate moves you back in that queue."
68847
+ // The ordering is already stated by `order`; say what to DO
68848
+ // including the trap that follows a partial redemption.
68849
+ defence: "Raising your rate moves you back in that queue. If a redemption leaves you below the minimum debt your trove goes ZOMBIE \u2014 removed from the queue, and only recoverable by topping it back above the floor or closing it."
68656
68850
  }
68657
68851
  },
68658
68852
  counterparty: { kind: "cdp", solvency: "overcollateralized" }
@@ -68689,14 +68883,28 @@ var riverAdapter = {
68689
68883
  seizure: "proportional",
68690
68884
  redeemable: true,
68691
68885
  redemption: {
68692
- // Not governance and not a liquidation: any holder of the stable may
68693
- // redeem it for collateral at any time.
68886
+ // Not governance and not a liquidation: any holder of the stable can
68887
+ // trigger it, without permission and without targeting anyone.
68694
68888
  trigger: "permissionless-arbitrage",
68889
+ // Permissionless does NOT mean constant: it only pays the redeemer
68890
+ // while the stable trades under target, which is what makes it a peg
68891
+ // defence rather than a standing claim on collateral.
68695
68892
  driver: "below-peg",
68696
- order: "lowest-rate-first",
68697
- valueImpact: "usd-neutral",
68698
- // The ordering is already stated by `order`; say only what to DO.
68699
- defence: "Raising your rate moves you back in that queue."
68893
+ // COLLATERAL-RATIO ordered, V1-style — NOT rate-ordered.
68894
+ //
68895
+ // This said `lowest-rate-first`, copied from the Liquity V2 shape,
68896
+ // and it was wrong twice over: River is Prisma/V1 lineage, which
68897
+ // redeems against the LOWEST-COLLATERALISED troves first, and River
68898
+ // charges no interest at all (`rate.kind: 'zero-interest'` above), so
68899
+ // the accompanying "raise your rate" advice pointed at a control that
68900
+ // does not exist on this protocol. A borrower following it would have
68901
+ // done nothing while sitting first in the real queue.
68902
+ order: "lowest-collateral-ratio",
68903
+ // Deliberately ABSENT rather than `usd-neutral`. The V1 mechanism
68904
+ // sends collateral above the redeemed debt to a surplus balance that
68905
+ // the borrower must CLAIM, so whether they end up whole depends on an
68906
+ // action they may not know to take — see `defence`.
68907
+ defence: "Add collateral or repay to raise your collateral ratio and move behind other troves in the queue. If you are redeemed, claim the leftover collateral from the surplus balance \u2014 it is not returned automatically."
68700
68908
  }
68701
68909
  },
68702
68910
  counterparty: { kind: "cdp", solvency: "overcollateralized" }
@@ -69010,7 +69218,18 @@ var resupplyAdapter = {
69010
69218
  // rate to raise. Offering "raise your rate" here would be actively
69011
69219
  // misleading.
69012
69220
  order: "pro-rata",
69013
- valueImpact: "usd-neutral"
69221
+ // `valueImpact` deliberately ABSENT — it is NOT `usd-neutral`.
69222
+ //
69223
+ // That was carried over from Liquity, where the redemption fee stays
69224
+ // IN the trove as extra collateral and leaves the borrower roughly
69225
+ // whole. Resupply does the opposite: `redeemCollateral` takes a 1 %
69226
+ // base fee with half of it going to the protocol, and writes the
69227
+ // collateral off across the pair via a `WriteOffToken` — so nothing
69228
+ // is credited back to the borrower and there is no surplus to claim.
69229
+ // Whether they end up neutral is not something we have established,
69230
+ // and an absent field says that where `usd-neutral` would have
69231
+ // promised it.
69232
+ defence: "Nothing \u2014 redemptions are skimmed pro-rata from every borrower in the pair, so there is no queue to move down and no action that exempts you. Your collateral can shrink with no transaction of your own."
69014
69233
  },
69015
69234
  badDebt: "socialized"
69016
69235
  },
@@ -69158,6 +69377,54 @@ var fraxlendAdapter = {
69158
69377
  }
69159
69378
  })
69160
69379
  };
69380
+ var MORPHO_BLUE_MAX_FEE_PERCENT = 25;
69381
+ function feePercent(raw) {
69382
+ if (raw == null) return void 0;
69383
+ const n = typeof raw === "string" ? Number(raw) : raw;
69384
+ if (!Number.isFinite(n) || n <= 0) return void 0;
69385
+ return n > 1 ? n / 1e18 * 100 : n * 100;
69386
+ }
69387
+ var morphoBlueAdapter = {
69388
+ id: "morpho-blue",
69389
+ matches: (lender) => isMorphoBlue(lender),
69390
+ profileId: () => "morpho.blue@v1",
69391
+ build: (input) => {
69392
+ const market = input.market ?? {};
69393
+ const fee = feePercent(market.fee);
69394
+ return {
69395
+ governance: {
69396
+ mutability: "immutable",
69397
+ // The ONE power that reaches an existing market. Listing the full owner
69398
+ // surface here would imply `enableLltv` could change THIS market's LLTV,
69399
+ // which is the misreading the whole adapter exists to prevent.
69400
+ powers: ["change-fees"]
69401
+ },
69402
+ supply: {
69403
+ // Stated as a FEE rather than left as a bare governance power, so the
69404
+ // bound travels with it: the number a supplier is exposed to is "0 %
69405
+ // today, never above 25 %", which a `change-fees` enum cannot express.
69406
+ //
69407
+ // Emitted even at 0 — the current Morpho default — because "this market
69408
+ // charges no fee, and the most it could ever charge is 25 %" is the
69409
+ // whole point, and an absent row would leave the power unexplained.
69410
+ fees: [
69411
+ {
69412
+ id: "reserve-factor",
69413
+ label: "Protocol fee on interest",
69414
+ when: "ongoing",
69415
+ unit: "percent",
69416
+ basis: "yield",
69417
+ value: fee ?? 0,
69418
+ payee: "protocol",
69419
+ mutable: true,
69420
+ cap: MORPHO_BLUE_MAX_FEE_PERCENT,
69421
+ description: "A share of the interest borrowers pay, taken before it reaches suppliers. Morpho governance can change it on a live market, but the contract refuses anything above 25 % \u2014 it is the only parameter of this market that can move."
69422
+ }
69423
+ ]
69424
+ }
69425
+ };
69426
+ }
69427
+ };
69161
69428
 
69162
69429
  // src/terms/adapters/index.ts
69163
69430
  var TERM_ADAPTERS = [
@@ -69178,7 +69445,8 @@ var TERM_ADAPTERS = [
69178
69445
  frankencoinAdapter,
69179
69446
  resupplyAdapter,
69180
69447
  curvanceAdapter,
69181
- fraxlendAdapter
69448
+ fraxlendAdapter,
69449
+ morphoBlueAdapter
69182
69450
  ];
69183
69451
  function resolveAdapter(lender) {
69184
69452
  return TERM_ADAPTERS.find((a) => a.matches(lender));
@@ -69344,7 +69612,9 @@ function enrichTermSheet(sheet, index) {
69344
69612
  }
69345
69613
  const govRow = index.governanceByMarketUid?.get(uid);
69346
69614
  if (govRow) {
69347
- const immutable = govRow.mode === "immutable";
69615
+ const assertedImmutable = sheet.governance?.mutability === "immutable";
69616
+ const immutable = govRow.mode === "immutable" || assertedImmutable;
69617
+ const adapterPowers = assertedImmutable ? sheet.governance?.powers : void 0;
69348
69618
  sheet.governance = {
69349
69619
  ...sheet.governance,
69350
69620
  mutability: immutable ? "immutable" : "governed",
@@ -69362,7 +69632,8 @@ function enrichTermSheet(sheet, index) {
69362
69632
  };
69363
69633
  if (immutable) {
69364
69634
  sheet.governance.timelockSecs = void 0;
69365
- sheet.governance.powers = void 0;
69635
+ sheet.governance.timelockUnknown = void 0;
69636
+ sheet.governance.powers = adapterPowers;
69366
69637
  }
69367
69638
  }
69368
69639
  const quality = index.assetRisk;
@@ -69592,8 +69863,12 @@ function validateTermSheet(sheet) {
69592
69863
  "immutable-timelock",
69593
69864
  "immutable governance must not carry a timelock"
69594
69865
  );
69595
- if (g.powers?.length)
69596
- fail("immutable-powers", "immutable governance must not carry powers");
69866
+ const disallowed = (g.powers ?? []).filter((p) => p !== "change-fees");
69867
+ if (disallowed.length)
69868
+ fail(
69869
+ "immutable-powers",
69870
+ `immutable governance must not carry powers: ${disallowed.join(", ")}`
69871
+ );
69597
69872
  }
69598
69873
  if (g.timelockSecs && g.controllerKind && g.controllerKind !== "TIMELOCK" && g.timelockSource !== "on-chain")
69599
69874
  fail(
@@ -69631,7 +69906,27 @@ var USER_SET_RATE_PREFIXES = [
69631
69906
  "SONETA",
69632
69907
  "EBISU"
69633
69908
  ];
69634
- function earnMarketFromPool(row, fallbackChainId) {
69909
+ function collateralSymbolsByVenue(rows, fallbackChainId) {
69910
+ const byVenue = /* @__PURE__ */ new Map();
69911
+ for (const row of rows) {
69912
+ const venue = str5(row.lender) ?? str5(row.lenderKey);
69913
+ const chainId = str5(row.chainId) ?? fallbackChainId;
69914
+ if (!venue || !chainId) continue;
69915
+ const collateralActive = row.flags?.collateralActive ?? row.collateralActive;
69916
+ if (collateralActive !== true) continue;
69917
+ const symbol = str5(row.underlyingInfo?.asset?.symbol) ?? str5(row.asset?.symbol);
69918
+ if (!symbol) continue;
69919
+ const key3 = venueGroupKey(chainId, venue);
69920
+ let set = byVenue.get(key3);
69921
+ if (!set) byVenue.set(key3, set = /* @__PURE__ */ new Set());
69922
+ set.add(symbol);
69923
+ }
69924
+ return new Map([...byVenue].map(([key3, set]) => [key3, [...set]]));
69925
+ }
69926
+ function venueGroupKey(chainId, venue) {
69927
+ return `${chainId}::${venue}`;
69928
+ }
69929
+ function earnMarketFromPool(row, fallbackChainId, venueCollaterals) {
69635
69930
  const marketUid = str5(row.marketUid);
69636
69931
  if (!marketUid) return void 0;
69637
69932
  let earnUid;
@@ -69675,7 +69970,25 @@ function earnMarketFromPool(row, fallbackChainId) {
69675
69970
  // The family brand ('Morpho Blue'), not the per-market key. The specific
69676
69971
  // market identity survives on `name`.
69677
69972
  brand: venueBrand(venue),
69678
- name: str5(row.name),
69973
+ // Same resolver as the vault half, so `protocol.key` means one thing
69974
+ // across the listing: the STABLE family key, never the per-market venue.
69975
+ // No lender publishes a curator today, hence the undefined.
69976
+ ...resolveEarnIdentity(venue, void 0),
69977
+ // Pair-aware: "USDT · vs wstETH" for an isolated market, plain "USDC" for
69978
+ // a shared pool. The fetcher's own name is only the fallback — it is the
69979
+ // leg-local "Loan USDC", which a chain repeats across 300 markets and
69980
+ // which says nothing about WHICH market this is. Identical to what the
69981
+ // origin's SQL route builds, so both paths agree.
69982
+ name: earnMarketLabel({
69983
+ assetSymbol: str5(assetInfo.symbol),
69984
+ lenderMarketName: str5(row.lenderInfo?.name),
69985
+ venue,
69986
+ // Minus this row's own leg: on the COLLATERAL row of an isolated market
69987
+ // the only collateral is itself, and "cbBTC · vs cbBTC" is nonsense.
69988
+ // Removing it leaves zero, i.e. the plain name — correct.
69989
+ collateralSymbols: venueCollaterals?.get(venueGroupKey(chainId, venue))?.filter((c) => c !== str5(assetInfo.symbol)),
69990
+ fallbackName: str5(row.name)
69991
+ }),
69679
69992
  // Never re-derived — the uid's third segment as the origin minted it.
69680
69993
  ref: marketUid.split(":")[2],
69681
69994
  logoURI: str5(assetInfo.logoURI),
@@ -69953,6 +70266,207 @@ function supportsCancel(provider, meta) {
69953
70266
  return typeof meta.withdrawQueue === "string" && meta.withdrawQueue.length > 0;
69954
70267
  }
69955
70268
 
69956
- export { ApiBookSource, DEFAULT_MIDNIGHT_API, DEFAULT_OUTLIER_GUARD, DEFAULT_PROFILE_ID, DEFAULT_STALE_REJECT_SECONDS, DEFAULT_TERMMAX_API, EARN_DESCRIPTIONS, EARN_LABELS, EMPTY_BALANCE, EXACTLY_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, SDK_FRACTION_RATE_PROVIDERS, STABLECOIN_SYMBOLS, STCELO_MANAGER_ADDRESS, TELLER_CALLS_PER_BID, TERMMAX_CALLS_PER_ACCOUNT, DECIMAL_BASE as TERMMAX_DECIMAL_BASE, TERMMAX_LIQUIDATION_PENALTY, TERMMAX_LIQUIDATION_WINDOW_SECS, TERMMAX_LIQUIDATOR_BONUS, 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_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, applyPositionDelta, attachImplications, attachPricesToFlashLiquidity, borrowDescription, borrowFindings, borrowHeadline, buildExposures2 as buildExposures, buildFluidFTokensCall, buildLiquityUserCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildSumerAccumulators, buildSummaries, buildTellerUserCall, buildTermMaxUserCall, buildTermSheet, buildTermSheetsForGroup, buildVaultEarnUid, buildVaultLookup, buildVaultTermSheet, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyFreshness, classifyReliability, classifyVault, clearPendleMarketsCache, 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, convertDssMarketsToResponse, convertExactlyMarketsToResponse, 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, dssIlkBytes32, dssKeyParts, dssLenderKey, duration, earnDescription, earnLabel, earnMarketFromPool, earnMarketFromVault, earnMarketLabel, earnUidFromMarketUid, earnVenueKind, encodeBalanceFetcherCalldata, enrichTermSheet, enrichmentIndexFromRows, exactlyPairLtv, exactlyPenaltyRateToAprPercent, exactlyWadRateToPercent, feePhrase, feedKeyOf, feedStatKey, fetchDolomiteAccountNumbers, fetchDssMarkets, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchExactlyMarkets, fetchFlashLiquidityForChain, fetchFluidFTokens, 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, fetchTellerMarkets, fetchTermMarkets, fetchTermMaxMarkets, fetchTokenBalances, fetchTokenMetadata, fetchUpshiftApiVaults, fetchUpshiftVaults, fetchUsddMarkets, fetchYearnApiVaults, fetchYearnVaults, filterActiveLenders, filterLendersByProtocol, finalizeInfo, findingsFor, formatRaw, frankencoinKeyParts, frankencoinLenderKey, fraxlendAssetPerCollateral, fraxlendKeyParts, fraxlendLenderKey, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, 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, getStCeloValidatorGroups, getSubAccountAddress, getSubAccountIndex, getTermProfile, getVaultPublicDataAll, getVaultWithdrawalRequests, hasCritical, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasPendleMarkets, hasUpshiftVaults, hasYearnVaults, ilkToKeySegment, implausibleRatePercent, inverseKeyParts, inverseLenderKey, isBoundNeed, isFailedCall, isIlliquid, isLiveMarket as isLivePendleMarket, isStablecoinSymbol, isVaultVenue, isYearnV3, keySegmentToIlk, keysFromMaps, lenderApiOnly, lenderFamily, liquityCandidateTroveIds, liquityKeyParts, liquityLenderKey, llamaLendKeyParts, llamaLendLenderKey, mergeDeep, multicall3Abi2 as multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, parseBalanceFetcherResult, parseEarnUid, parseMergedResult, parseMulticallRpcResponses, parseExpirySeconds as parsePendleExpirySeconds, parseRawRpcBatchResponses, parseRawRpcResponses, parseTermMaxLtv, parseTokenBalanceResult, pct, assetKey as pendleAssetKey, positivePart2 as positivePart, predictInverseEscrow, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, probeAaveFeedTimestamps, pruneFeedStats, rankFindings, ratePercent, readVaultSharePrices, rejectOutliers as rejectPriceOutliers, resolveAdapter, resolveDerivation, resolveStCeloDepositGroup, resolveVaultProfileId, resupplyKeyParts, resupplyLenderKey, resupplyMarketLabel, riverKeyParts, riverLenderKey, selectAssetGroupPrices, shortDate, splitChainScopedAddress as splitPendleChainScopedAddress, stampCapabilities, stampVaultClassification, stampVaultTermSheets, supplyDescription, supplyFindings, supplyHeadline, swapRoutedProvidersArePriceConsistent, tellerBpsToPercent, tellerImpliedLtv, tellerLenderKey, tellerPoolFromLenderKey, 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, tickToAprNumber, tickToPrice, toDigest, toTermSheetInput, toVaultTermInput, tryParseEarnUid, unflattenLenderData, updateFeedStats, usdValue, usddIlkBytes32, usddKeyParts, usddLenderKey, validateTermSheet, validateTermSheets, validateUserData, vaultTermInputFromEarnMarket, vaultTermInputFromSourceRow, vaultTraits, vaultVenue, venueBrand };
70269
+ // src/earn/positions.ts
70270
+ function buildLendingPositionUid(lender, chainId) {
70271
+ if (!lender || !chainId) {
70272
+ throw new Error(
70273
+ `Invalid lending positionUid parameters: lender=${lender}, chainId=${chainId}`
70274
+ );
70275
+ }
70276
+ if (isVaultVenue(lender)) {
70277
+ throw new Error(
70278
+ `Lender '${lender}' uses the reserved vault venue namespace`
70279
+ );
70280
+ }
70281
+ return `${lender}:${chainId}`;
70282
+ }
70283
+ function isVaultPosition(p) {
70284
+ return p.venueKind === "vault";
70285
+ }
70286
+ function isLendingPosition(p) {
70287
+ return p.venueKind === "lending";
70288
+ }
70289
+ function legEarnUid(marketUid) {
70290
+ if (!marketUid) return void 0;
70291
+ const parts = marketUid.split(":");
70292
+ if (parts.length !== 3 || parts.some((p) => !p)) return void 0;
70293
+ if (isVaultVenue(parts[0])) return void 0;
70294
+ return marketUid;
70295
+ }
70296
+ function num15(v) {
70297
+ const n = typeof v === "number" ? v : Number(v);
70298
+ return Number.isFinite(n) ? n : 0;
70299
+ }
70300
+ function legAsset(pos) {
70301
+ const asset = pos.underlyingInfo?.asset ?? {};
70302
+ const address = typeof asset.address === "string" ? asset.address.toLowerCase() : (
70303
+ // Fall back to the uid's third segment, which IS the underlying for
70304
+ // the default-format lenders and merely a harmless label for the rest.
70305
+ pos.marketUid?.split(":")[2] ?? ""
70306
+ );
70307
+ const decimals = typeof asset.decimals === "number" ? asset.decimals : void 0;
70308
+ const symbol = typeof asset.symbol === "string" ? asset.symbol : void 0;
70309
+ const logoURI = typeof asset.logoURI === "string" ? asset.logoURI : void 0;
70310
+ return {
70311
+ address,
70312
+ symbol,
70313
+ decimals,
70314
+ ...logoURI ? { logoURI } : {}
70315
+ };
70316
+ }
70317
+ function toLeg(pos) {
70318
+ const depositsUsd = num15(pos.depositsUSD);
70319
+ const debtUsd = num15(pos.debtUSD) + num15(pos.debtStableUSD);
70320
+ const hasSupply = depositsUsd !== 0 || num15(pos.deposits) !== 0;
70321
+ const hasDebt = debtUsd !== 0 || num15(pos.debt) !== 0 || num15(pos.debtStable) !== 0;
70322
+ return {
70323
+ earnUid: legEarnUid(pos.marketUid),
70324
+ marketUid: pos.marketUid,
70325
+ ...pos.loanId ? { loanId: pos.loanId } : {},
70326
+ asset: legAsset(pos),
70327
+ // An empty market is `'none'`, NOT `'supply'` — the old fallback quietly
70328
+ // reported every market the account was merely configured in as a holding.
70329
+ side: hasSupply && hasDebt ? "both" : hasDebt ? "borrow" : hasSupply ? "supply" : "none",
70330
+ deposits: pos.deposits ?? "0",
70331
+ depositsUsd,
70332
+ debt: pos.debt ?? "0",
70333
+ debtUsd,
70334
+ collateralEnabled: pos.collateralEnabled ?? false,
70335
+ ...pos.withdrawable !== void 0 ? { withdrawable: pos.withdrawable } : {}
70336
+ };
70337
+ }
70338
+ function isCountable(leg) {
70339
+ return leg.loanId === void 0;
70340
+ }
70341
+ function earnPositionFromLenderEntry(entry) {
70342
+ const subs = entry.data ?? [];
70343
+ const subAccounts = subs.map((sub) => {
70344
+ const legs = (sub.positions ?? []).map(toLeg);
70345
+ const counted = legs.filter(isCountable);
70346
+ const suppliedUsd2 = counted.reduce((a, l) => a + l.depositsUsd, 0);
70347
+ const borrowedUsd2 = counted.reduce((a, l) => a + l.debtUsd, 0);
70348
+ return {
70349
+ accountId: sub.accountId,
70350
+ health: sub.health ?? null,
70351
+ suppliedUsd: suppliedUsd2,
70352
+ borrowedUsd: borrowedUsd2,
70353
+ netUsd: suppliedUsd2 - borrowedUsd2,
70354
+ legs
70355
+ };
70356
+ });
70357
+ const active = subAccounts.filter(
70358
+ (s) => s.legs.some((l) => l.side !== "none") || s.netUsd !== 0
70359
+ );
70360
+ const crossMargin = active.length <= 1;
70361
+ const suppliedUsd = num15(entry.balanceData?.deposits);
70362
+ const borrowedUsd = num15(entry.balanceData?.debt);
70363
+ const aprBreakdown = {
70364
+ market: num15(entry.aprData?.apr),
70365
+ rewards: num15(entry.aprData?.rewardApr),
70366
+ intrinsic: num15(entry.aprData?.intrinsicApr)
70367
+ };
70368
+ return {
70369
+ positionUid: buildLendingPositionUid(entry.lender, entry.chainId),
70370
+ chainId: entry.chainId,
70371
+ venue: entry.lender,
70372
+ venueKind: "lending",
70373
+ lender: entry.lender,
70374
+ account: entry.account,
70375
+ brand: entry.lenderInfo?.name,
70376
+ name: entry.lenderInfo?.name,
70377
+ ...entry.lenderInfo?.logoUri ? { logoURI: entry.lenderInfo.logoUri } : {},
70378
+ suppliedUsd,
70379
+ borrowedUsd,
70380
+ netUsd: num15(entry.balanceData?.nav),
70381
+ apr: aprBreakdown.market + aprBreakdown.rewards + aprBreakdown.intrinsic,
70382
+ aprBreakdown,
70383
+ depositApr: num15(entry.aprData?.depositApr),
70384
+ borrowApr: num15(entry.aprData?.borrowApr),
70385
+ // Only a cross-margin account HAS one health factor. Publishing the first
70386
+ // sub-account's as the row's would be a number about a different position.
70387
+ health: crossMargin ? active[0]?.health ?? null : null,
70388
+ leverage: num15(entry.leverage),
70389
+ crossMargin,
70390
+ legs: subAccounts.flatMap((s) => s.legs),
70391
+ subAccounts: active,
70392
+ ...entry.incomplete ? { incomplete: true } : {},
70393
+ ...entry.stale ? { stale: true, staleAgeMs: entry.staleAgeMs } : {}
70394
+ };
70395
+ }
70396
+ function vaultSharesToAssets(sharesRaw, meta) {
70397
+ if (sharesRaw === 0n) return 0n;
70398
+ const totalSupply = BigInt(meta.totalSupply || "0");
70399
+ if (totalSupply === 0n) return 0n;
70400
+ return sharesRaw * BigInt(meta.totalAssets || "0") / totalSupply;
70401
+ }
70402
+ function earnPositionFromVaultBalance(meta, chainId, input, format) {
70403
+ const assetsRaw = vaultSharesToAssets(input.sharesRaw, meta);
70404
+ const assetDecimals = meta.assetDecimals ?? meta.decimals;
70405
+ const assets = format(assetsRaw, assetDecimals);
70406
+ const priceUsd = input.priceUsd ?? 0;
70407
+ const suppliedUsd = priceUsd * parseFloat(assets);
70408
+ const market = input.market;
70409
+ const uid = buildVaultEarnUid(meta.provider, chainId, meta.address);
70410
+ return {
70411
+ positionUid: uid,
70412
+ earnUid: uid,
70413
+ chainId,
70414
+ venue: `vault.${meta.provider}`,
70415
+ venueKind: "vault",
70416
+ provider: meta.provider,
70417
+ vault: meta.address,
70418
+ // The catalogue's identity resolution (curator, brand, branded icon) beats
70419
+ // the raw share-token name where it resolved.
70420
+ name: market?.name ?? meta.name,
70421
+ ...market?.brand ? { brand: market.brand } : {},
70422
+ ...market?.logoURI ?? meta.logoURI ? { logoURI: market?.logoURI ?? meta.logoURI } : {},
70423
+ asset: {
70424
+ address: meta.underlying,
70425
+ ...market?.asset.symbol ? { symbol: market.asset.symbol } : {},
70426
+ decimals: assetDecimals,
70427
+ priceUsd
70428
+ },
70429
+ sharesRaw: input.sharesRaw.toString(),
70430
+ shares: format(input.sharesRaw, meta.decimals),
70431
+ assetsRaw: assetsRaw.toString(),
70432
+ assets,
70433
+ shareDecimals: meta.decimals,
70434
+ suppliedUsd,
70435
+ // A vault share is a supply-only instrument — there is no borrow leg to
70436
+ // report, and `0` here is a fact rather than a missing read.
70437
+ borrowedUsd: 0,
70438
+ netUsd: suppliedUsd,
70439
+ // For a vault the position's APR IS the venue's rate — there is no borrow
70440
+ // leg to net off, so unlike the lending half the two never diverge.
70441
+ ...market?.rate?.total !== void 0 ? { apr: market.rate.total } : {},
70442
+ ...market?.rate ? { rate: market.rate } : {},
70443
+ ...market?.exit ? { exit: market.exit } : {},
70444
+ ...market?.availability ? { availability: market.availability } : {},
70445
+ ...market?.capabilities ? { capabilities: market.capabilities } : {},
70446
+ ...meta.yieldProfile ? { yieldProfile: meta.yieldProfile } : {},
70447
+ ...meta.denomination ? { denomination: meta.denomination } : {}
70448
+ };
70449
+ }
70450
+ function earnPositionTotals(items) {
70451
+ let suppliedUsd = 0;
70452
+ let borrowedUsd = 0;
70453
+ let lendingUsd = 0;
70454
+ let vaultUsd = 0;
70455
+ for (const it of items) {
70456
+ suppliedUsd += it.suppliedUsd;
70457
+ borrowedUsd += it.borrowedUsd;
70458
+ if (it.venueKind === "vault") vaultUsd += it.netUsd;
70459
+ else lendingUsd += it.netUsd;
70460
+ }
70461
+ return {
70462
+ suppliedUsd,
70463
+ borrowedUsd,
70464
+ netUsd: suppliedUsd - borrowedUsd,
70465
+ lendingUsd,
70466
+ vaultUsd
70467
+ };
70468
+ }
70469
+
70470
+ export { ApiBookSource, DEFAULT_MIDNIGHT_API, DEFAULT_OUTLIER_GUARD, DEFAULT_PROFILE_ID, DEFAULT_STALE_REJECT_SECONDS, DEFAULT_TERMMAX_API, EARN_DESCRIPTIONS, EARN_LABELS, EMPTY_BALANCE, EXACTLY_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, SDK_FRACTION_RATE_PROVIDERS, STABLECOIN_SYMBOLS, STCELO_MANAGER_ADDRESS, TELLER_CALLS_PER_BID, TERMMAX_CALLS_PER_ACCOUNT, DECIMAL_BASE as TERMMAX_DECIMAL_BASE, TERMMAX_LIQUIDATION_PENALTY, TERMMAX_LIQUIDATION_WINDOW_SECS, TERMMAX_LIQUIDATOR_BONUS, 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_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, applyPositionDelta, attachImplications, attachPricesToFlashLiquidity, borrowDescription, borrowFindings, borrowHeadline, buildExposures2 as buildExposures, buildFluidFTokensCall, buildLendingPositionUid, buildLiquityUserCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildSumerAccumulators, buildSummaries, buildTellerUserCall, buildTermMaxUserCall, buildTermSheet, buildTermSheetsForGroup, buildVaultEarnUid, buildVaultLookup, buildVaultTermSheet, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyFreshness, classifyReliability, classifyVault, clearPendleMarketsCache, 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, convertDssMarketsToResponse, convertExactlyMarketsToResponse, 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, dssIlkBytes32, dssKeyParts, dssLenderKey, duration, earnDescription, earnLabel, earnMarketFromPool, earnMarketFromVault, earnMarketLabel, earnPositionFromLenderEntry, earnPositionFromVaultBalance, earnPositionTotals, earnUidFromMarketUid, earnVenueKind, encodeBalanceFetcherCalldata, enrichTermSheet, enrichmentIndexFromRows, exactlyPairLtv, exactlyPenaltyRateToAprPercent, exactlyWadRateToPercent, feePhrase, feedKeyOf, feedStatKey, fetchDolomiteAccountNumbers, fetchDssMarkets, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchExactlyMarkets, fetchFlashLiquidityForChain, fetchFluidFTokens, 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, fetchTellerMarkets, fetchTermMarkets, fetchTermMaxMarkets, fetchTokenBalances, fetchTokenMetadata, fetchUpshiftApiVaults, fetchUpshiftVaults, fetchUsddMarkets, fetchYearnApiVaults, fetchYearnVaults, filterActiveLenders, filterLendersByProtocol, finalizeInfo, findingsFor, formatRaw, frankencoinKeyParts, frankencoinLenderKey, fraxlendAssetPerCollateral, fraxlendKeyParts, fraxlendLenderKey, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, 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, getStCeloValidatorGroups, getSubAccountAddress, getSubAccountIndex, getTermProfile, getVaultPublicDataAll, getVaultWithdrawalRequests, hasCritical, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasPendleMarkets, hasUpshiftVaults, hasYearnVaults, ilkToKeySegment, implausibleRatePercent, inverseKeyParts, inverseLenderKey, isBoundNeed, isFailedCall, isIlliquid, isLendingPosition, isLiveMarket as isLivePendleMarket, isStablecoinSymbol, isVaultPosition, isVaultVenue, isYearnV3, keySegmentToIlk, keysFromMaps, lenderApiOnly, lenderFamily, liquityCandidateTroveIds, liquityKeyParts, liquityLenderKey, llamaLendKeyParts, llamaLendLenderKey, mergeDeep, multicall3Abi2 as multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, parseBalanceFetcherResult, parseEarnUid, parseMergedResult, parseMulticallRpcResponses, parseExpirySeconds as parsePendleExpirySeconds, parseRawRpcBatchResponses, parseRawRpcResponses, parseTermMaxLtv, parseTokenBalanceResult, pct, assetKey as pendleAssetKey, positivePart2 as positivePart, predictInverseEscrow, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, probeAaveFeedTimestamps, pruneFeedStats, rankFindings, ratePercent, readVaultSharePrices, rejectOutliers as rejectPriceOutliers, resolveAdapter, resolveDerivation, resolveEarnIdentity, resolveStCeloDepositGroup, resolveVaultProfileId, resupplyKeyParts, resupplyLenderKey, resupplyMarketLabel, riverKeyParts, riverLenderKey, selectAssetGroupPrices, shortDate, splitChainScopedAddress as splitPendleChainScopedAddress, stampCapabilities, stampVaultClassification, stampVaultTermSheets, supplyDescription, supplyFindings, supplyHeadline, swapRoutedProvidersArePriceConsistent, tellerBpsToPercent, tellerImpliedLtv, tellerLenderKey, tellerPoolFromLenderKey, 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, tickToAprNumber, tickToPrice, toDigest, toTermSheetInput, toVaultTermInput, tryParseEarnUid, unflattenLenderData, updateFeedStats, usdValue, usddIlkBytes32, usddKeyParts, usddLenderKey, validateTermSheet, validateTermSheets, validateUserData, vaultSharesToAssets, vaultTermInputFromEarnMarket, vaultTermInputFromSourceRow, vaultTraits, vaultVenue, venueBrand, venueBrandKey };
69957
70471
  //# sourceMappingURL=index.js.map
69958
70472
  //# sourceMappingURL=index.js.map