@1delta/margin-fetcher 5.0.62 → 5.0.64
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.d.ts +185 -6
- package/dist/index.js +1161 -201
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parseAbi, keccak256, encodeAbiParameters, formatEther, BaseError, erc20Abi, stringToHex, isAddress, pad, encodeFunctionData, formatUnits, getAddress, decodeFunctionResult, decodeAbiParameters, concat, parseAbiParameters, AbiEncodingLengthMismatchError, concatHex, toBytes, slice, 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, isTwyne, isFraxlend, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isCompoundV2Type, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, isMorphoType, isUsdd, isSky, hasCrossMarginRisk, isEulerType,
|
|
4
|
+
import { Lender, isExactly, isMidnight, isTerm, isTermMax, isTeller, isListaDao, isLiquityFamily, isRiver, isInverse, isCooler, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, 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';
|
|
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, liquityLendersByChain, riverLendersByChain, inverseLendersByChain, coolerLendersByChain, llamaLendLendersByChain, usddLendersByChain, skyLendersByChain, frankencoinLendersByChain, resupplyLendersByChain, curvanceLendersByChain, fraxlendLendersByChain, twyneLendersByChain, tellerConfigByChain, tellerPoolsByChain, termMaxConfigByChain, aaveReserves, compoundV3Reserves, resolveTermApiBase, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, termMaxApiBaseUrl, termMaxLenderKey, inverseConfigFor, inverseChainData, coolerConfigFor, llamaLendConfigFor, llamaLendChainData, llamaLendApiBaseUrl, resupplyConfigFor, fraxlendConfigFor, dssConfigFor, dssChainData, dssDebtToken, dssDebtJoin, frankencoinConfigFor, frankencoinChainData, aaveOracles, morphoTypeMarkets, resolveMidnightApiBase, llamaLendMarketByVault, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, curvanceConfigFor, aaveTokens, morphoTypeVaults, listaCollateralProvider, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, compoundV2TokenArray, gearboxV3LenderKey, midnightMarketsByChain, twyneConfigFor, twyneChainData, parseAaveV4SpokeLenderKey, fraxlendPairsFor, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2OraclesConfig, compoundV3OraclesData, compoundV3BaseData, compoundV2Reserves, aaveV4Oracles, morphoTypeOracles } from '@1delta/data-sdk';
|
|
7
7
|
import lodash from 'lodash';
|
|
@@ -10951,9 +10951,9 @@ function applyPositionDelta(positions, targetMarketUid, depositsDeltaUSD, debtDe
|
|
|
10951
10951
|
}
|
|
10952
10952
|
|
|
10953
10953
|
// src/lending/margin/base/sumer/deposit.ts
|
|
10954
|
-
function computeSumerDepositDelta(
|
|
10954
|
+
function computeSumerDepositDelta(amount4, price2, targetMarketUid, balanceData2, positions, createNewSubAccount = false, apr, yieldParams) {
|
|
10955
10955
|
const base = createNewSubAccount ? EMPTY_BALANCE : balanceData2;
|
|
10956
|
-
const dollarAmount =
|
|
10956
|
+
const dollarAmount = amount4 * price2;
|
|
10957
10957
|
const updatedPositions = applyPositionDelta(
|
|
10958
10958
|
positions,
|
|
10959
10959
|
targetMarketUid,
|
|
@@ -11019,8 +11019,8 @@ function computeSumerDepositDelta(amount3, price2, targetMarketUid, balanceData2
|
|
|
11019
11019
|
}
|
|
11020
11020
|
|
|
11021
11021
|
// src/lending/margin/base/sumer/withdraw.ts
|
|
11022
|
-
function computeSumerWithdrawDelta(
|
|
11023
|
-
const dollarAmount =
|
|
11022
|
+
function computeSumerWithdrawDelta(amount4, price2, targetMarketUid, balanceData2, positions, apr, yieldParams) {
|
|
11023
|
+
const dollarAmount = amount4 * price2;
|
|
11024
11024
|
const updatedPositions = applyPositionDelta(
|
|
11025
11025
|
positions,
|
|
11026
11026
|
targetMarketUid,
|
|
@@ -11086,8 +11086,8 @@ function computeSumerWithdrawDelta(amount3, price2, targetMarketUid, balanceData
|
|
|
11086
11086
|
}
|
|
11087
11087
|
|
|
11088
11088
|
// src/lending/margin/base/sumer/borrow.ts
|
|
11089
|
-
function computeSumerBorrowDelta(
|
|
11090
|
-
const dollarAmount =
|
|
11089
|
+
function computeSumerBorrowDelta(amount4, price2, targetMarketUid, balanceData2, positions, apr, yieldParams, irMode) {
|
|
11090
|
+
const dollarAmount = amount4 * price2;
|
|
11091
11091
|
const mode = irMode ?? 2;
|
|
11092
11092
|
const updatedPositions = applyPositionDelta(
|
|
11093
11093
|
positions,
|
|
@@ -11157,8 +11157,8 @@ function computeSumerBorrowDelta(amount3, price2, targetMarketUid, balanceData2,
|
|
|
11157
11157
|
}
|
|
11158
11158
|
|
|
11159
11159
|
// src/lending/margin/base/sumer/repay.ts
|
|
11160
|
-
function computeSumerRepayDelta(
|
|
11161
|
-
const dollarAmount =
|
|
11160
|
+
function computeSumerRepayDelta(amount4, price2, targetMarketUid, balanceData2, positions, apr, yieldParams, irMode) {
|
|
11161
|
+
const dollarAmount = amount4 * price2;
|
|
11162
11162
|
const mode = irMode ?? 2;
|
|
11163
11163
|
const updatedPositions = applyPositionDelta(
|
|
11164
11164
|
positions,
|
|
@@ -16661,13 +16661,13 @@ var REPAIR_BACKOFF_JITTER_MS = 60;
|
|
|
16661
16661
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
16662
16662
|
var backoffForRound = (round) => REPAIR_BACKOFF_BASE_MS * 2 ** round + Math.random() * REPAIR_BACKOFF_JITTER_MS;
|
|
16663
16663
|
var endpointUrl = (client, rpcId) => client?.transport?.url ?? `rpc#${rpcId}`;
|
|
16664
|
-
var resolveEndpoint = (chainId,
|
|
16664
|
+
var resolveEndpoint = (chainId, getEvmClient19, startRpcId, tried, maxProbe = 12, timeoutMs) => {
|
|
16665
16665
|
let fallback = null;
|
|
16666
16666
|
for (let probe = 0; probe < maxProbe; probe++) {
|
|
16667
16667
|
const rpcId = startRpcId + probe;
|
|
16668
16668
|
let client;
|
|
16669
16669
|
try {
|
|
16670
|
-
client =
|
|
16670
|
+
client = getEvmClient19(chainId, rpcId, { timeoutMs });
|
|
16671
16671
|
} catch {
|
|
16672
16672
|
break;
|
|
16673
16673
|
}
|
|
@@ -16696,7 +16696,7 @@ var recordPermanentFailures = (slots, offset, collector) => {
|
|
|
16696
16696
|
if (slots[i].permanent) collector.add(offset + i);
|
|
16697
16697
|
}
|
|
16698
16698
|
};
|
|
16699
|
-
var repairFailedSlots = async (chainId, contracts, slots,
|
|
16699
|
+
var repairFailedSlots = async (chainId, contracts, slots, getEvmClient19, nextRpcId, batchSize, logs, rounds = MULTICALL_REPAIR_ROUNDS, options) => {
|
|
16700
16700
|
let searchFrom = nextRpcId;
|
|
16701
16701
|
for (let round = 0; round < rounds; round++) {
|
|
16702
16702
|
const failedIdx = [];
|
|
@@ -16706,7 +16706,7 @@ var repairFailedSlots = async (chainId, contracts, slots, getEvmClient18, nextRp
|
|
|
16706
16706
|
if (failedIdx.length === 0) return slots;
|
|
16707
16707
|
const endpoint = resolveEndpoint(
|
|
16708
16708
|
chainId,
|
|
16709
|
-
|
|
16709
|
+
getEvmClient19,
|
|
16710
16710
|
searchFrom,
|
|
16711
16711
|
options?.tried
|
|
16712
16712
|
);
|
|
@@ -16758,7 +16758,7 @@ var repairFailedSlots = async (chainId, contracts, slots, getEvmClient18, nextRp
|
|
|
16758
16758
|
}
|
|
16759
16759
|
return slots;
|
|
16760
16760
|
};
|
|
16761
|
-
var multicallShardedAbiArray = async (chainId, abi, calls,
|
|
16761
|
+
var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient19, poolSize, retries = maxRetries, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, logs = false, retryFailed = false, permanentFailures, options) => {
|
|
16762
16762
|
const abiIsArray = isArray(abi[0]);
|
|
16763
16763
|
const contracts = calls.map(({ address, name, params }, i) => ({
|
|
16764
16764
|
abi: abiIsArray ? abi?.[i] : abi,
|
|
@@ -16832,7 +16832,7 @@ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient18, poolS
|
|
|
16832
16832
|
const attemptHedged = async (items, startRpcId, tried) => {
|
|
16833
16833
|
const primary = resolveEndpoint(
|
|
16834
16834
|
chainId,
|
|
16835
|
-
|
|
16835
|
+
getEvmClient19,
|
|
16836
16836
|
startRpcId,
|
|
16837
16837
|
tried,
|
|
16838
16838
|
12,
|
|
@@ -16856,7 +16856,7 @@ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient18, poolS
|
|
|
16856
16856
|
clearTimeout(timer);
|
|
16857
16857
|
const alt = resolveEndpoint(
|
|
16858
16858
|
chainId,
|
|
16859
|
-
|
|
16859
|
+
getEvmClient19,
|
|
16860
16860
|
primary.rpcId + 1,
|
|
16861
16861
|
tried,
|
|
16862
16862
|
12,
|
|
@@ -16908,7 +16908,7 @@ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient18, poolS
|
|
|
16908
16908
|
chainId,
|
|
16909
16909
|
batch.items,
|
|
16910
16910
|
slots,
|
|
16911
|
-
|
|
16911
|
+
getEvmClient19,
|
|
16912
16912
|
won.rpcId + 1,
|
|
16913
16913
|
requestBytes,
|
|
16914
16914
|
logs,
|
|
@@ -16930,7 +16930,7 @@ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient18, poolS
|
|
|
16930
16930
|
const tried = /* @__PURE__ */ new Set();
|
|
16931
16931
|
const start = resolveEndpoint(
|
|
16932
16932
|
chainId,
|
|
16933
|
-
|
|
16933
|
+
getEvmClient19,
|
|
16934
16934
|
workerId,
|
|
16935
16935
|
void 0,
|
|
16936
16936
|
12,
|
|
@@ -18906,7 +18906,9 @@ function normalizeAaveV4(spokeDataList, chainId, spokeLenderKeyArg, prices, addi
|
|
|
18906
18906
|
// >= PERCENTAGE_FACTOR (README: "bonus ≥ 100% (= ≥ 0% bonus)"). Same
|
|
18907
18907
|
// semantics as V3's `liquidationBonus`, so penalty = bps/BPS - 1.
|
|
18908
18908
|
liquidationPenalty: Number.isFinite(dynCfg.maxLiquidationBonus) && dynCfg.maxLiquidationBonus > 0 ? dynCfg.maxLiquidationBonus / BPS - 1 : 0,
|
|
18909
|
-
|
|
18909
|
+
// No close factor in V4 — the ceiling is the whole debt. See the
|
|
18910
|
+
// field docstring on `AaveV4TokenEntry.closeFactor`.
|
|
18911
|
+
closeFactor: 1,
|
|
18910
18912
|
targetHealthFactor,
|
|
18911
18913
|
// _validateSetUsingAsCollateral: !paused && !frozen (frozen blocks enabling)
|
|
18912
18914
|
collateralDisabled: dynCfg.collateralFactor === 0 || reserve.config.paused || reserve.config.frozen,
|
|
@@ -18922,7 +18924,9 @@ function normalizeAaveV4(spokeDataList, chainId, spokeLenderKeyArg, prices, addi
|
|
|
18922
18924
|
collateralFactor: 0,
|
|
18923
18925
|
borrowFactor: 1,
|
|
18924
18926
|
liquidationPenalty: 0,
|
|
18925
|
-
|
|
18927
|
+
// No close factor in V4 — the ceiling is the whole debt. See the
|
|
18928
|
+
// field docstring on `AaveV4TokenEntry.closeFactor`.
|
|
18929
|
+
closeFactor: 1,
|
|
18926
18930
|
targetHealthFactor,
|
|
18927
18931
|
collateralDisabled: true,
|
|
18928
18932
|
debtDisabled: !reserve.config.borrowable || reserve.config.paused || reserve.config.frozen
|
|
@@ -18991,7 +18995,8 @@ function normalizeAaveV4(spokeDataList, chainId, spokeLenderKeyArg, prices, addi
|
|
|
18991
18995
|
borrowCap,
|
|
18992
18996
|
supplyCap,
|
|
18993
18997
|
debtCeiling: 0,
|
|
18994
|
-
|
|
18998
|
+
// No close factor in V4 — the ceiling is the whole debt.
|
|
18999
|
+
closeFactor: 1,
|
|
18995
19000
|
targetHealthFactor,
|
|
18996
19001
|
spokeActive,
|
|
18997
19002
|
spokeHalted,
|
|
@@ -19010,13 +19015,20 @@ function normalizeAaveV4(spokeDataList, chainId, spokeLenderKeyArg, prices, addi
|
|
|
19010
19015
|
};
|
|
19011
19016
|
}
|
|
19012
19017
|
if (Object.keys(data).length === 0) return void 0;
|
|
19018
|
+
const liqCfg = spokeData.liquidationConfig;
|
|
19019
|
+
const wad = (v) => v != null && v > 0n ? Number(v) / 1e18 : void 0;
|
|
19013
19020
|
return {
|
|
19014
19021
|
data,
|
|
19015
19022
|
chainId,
|
|
19016
19023
|
params: {
|
|
19017
19024
|
spoke: spokeAddr,
|
|
19018
19025
|
oracle: spokeData.oracle.toLowerCase(),
|
|
19019
|
-
label: spokeData.label
|
|
19026
|
+
label: spokeData.label,
|
|
19027
|
+
liquidation: {
|
|
19028
|
+
targetHealthFactor: wad(liqCfg?.targetHealthFactor),
|
|
19029
|
+
healthFactorForMaxBonus: wad(liqCfg?.healthFactorForMaxBonus),
|
|
19030
|
+
liquidationBonusFactorBps: liqCfg?.liquidationBonusFactor || void 0
|
|
19031
|
+
}
|
|
19020
19032
|
}
|
|
19021
19033
|
};
|
|
19022
19034
|
}
|
|
@@ -23272,7 +23284,7 @@ async function fetchTellerMarkets(chainId) {
|
|
|
23272
23284
|
}
|
|
23273
23285
|
return null;
|
|
23274
23286
|
};
|
|
23275
|
-
const
|
|
23287
|
+
const num19 = (i) => {
|
|
23276
23288
|
const b = big22(i);
|
|
23277
23289
|
return b === null ? null : Number(b);
|
|
23278
23290
|
};
|
|
@@ -23282,9 +23294,9 @@ async function fetchTellerMarkets(chainId) {
|
|
|
23282
23294
|
config,
|
|
23283
23295
|
available: big22(base),
|
|
23284
23296
|
committed: big22(base + 1),
|
|
23285
|
-
minRateBps:
|
|
23297
|
+
minRateBps: num19(base + 2),
|
|
23286
23298
|
collateralPerPrincipal: big22(base + 3),
|
|
23287
|
-
maxLoanDuration:
|
|
23299
|
+
maxLoanDuration: num19(base + 4),
|
|
23288
23300
|
marketId: big22(base + 5),
|
|
23289
23301
|
totalAssets: big22(base + 6)
|
|
23290
23302
|
};
|
|
@@ -24417,20 +24429,20 @@ async function fetchInverseMarkets(lender, chainId) {
|
|
|
24417
24429
|
if (Object.keys(byAddr).length > 0) {
|
|
24418
24430
|
const rows = markets.map((market) => {
|
|
24419
24431
|
const m = byAddr[market.address.toLowerCase()];
|
|
24420
|
-
const
|
|
24432
|
+
const num19 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
24421
24433
|
return {
|
|
24422
24434
|
market,
|
|
24423
|
-
totalDebt:
|
|
24424
|
-
dolaLiquidity:
|
|
24425
|
-
leftToBorrow:
|
|
24426
|
-
price:
|
|
24435
|
+
totalDebt: num19(m?.totalDebt),
|
|
24436
|
+
dolaLiquidity: num19(m?.dolaLiquidity),
|
|
24437
|
+
leftToBorrow: num19(m?.leftToBorrow),
|
|
24438
|
+
price: num19(m?.price),
|
|
24427
24439
|
borrowPaused: typeof m?.borrowPaused === "boolean" ? m.borrowPaused : null,
|
|
24428
|
-
dailyBorrows:
|
|
24440
|
+
dailyBorrows: num19(m?.dailyBorrows),
|
|
24429
24441
|
// The API serves it as a DECIMAL (`replenishmentIncentive: 0.1`),
|
|
24430
24442
|
// unlike the on-chain bps — normalize here, and fall back to the
|
|
24431
24443
|
// curated metadata value when the field is missing.
|
|
24432
24444
|
replenishmentIncentiveBps: (() => {
|
|
24433
|
-
const dec2 =
|
|
24445
|
+
const dec2 = num19(m?.replenishmentIncentive);
|
|
24434
24446
|
if (dec2 !== null) return Math.round(dec2 * 1e4);
|
|
24435
24447
|
const meta = Number(market.replenishmentIncentiveBps);
|
|
24436
24448
|
return Number.isFinite(meta) ? meta : null;
|
|
@@ -29662,8 +29674,9 @@ var LENS_FAMILY = {
|
|
|
29662
29674
|
*/
|
|
29663
29675
|
RESUPPLY: 15
|
|
29664
29676
|
};
|
|
29677
|
+
var V6_WITHHELD = /* @__PURE__ */ new Set([LENS_FAMILY.AAVE_V4]);
|
|
29665
29678
|
var ALL_FAMILIES = new Set(
|
|
29666
|
-
Object.values(LENS_FAMILY)
|
|
29679
|
+
Object.values(LENS_FAMILY).filter((f) => !V6_WITHHELD.has(f))
|
|
29667
29680
|
);
|
|
29668
29681
|
var v6 = () => ({
|
|
29669
29682
|
address: POSITION_LENS_V6,
|
|
@@ -34258,25 +34271,25 @@ var getFluidUserDataConverter = (lender, chainId, account, meta) => {
|
|
|
34258
34271
|
legRaw(leg, supplyRaw).toString(),
|
|
34259
34272
|
leg.decimals
|
|
34260
34273
|
);
|
|
34261
|
-
const
|
|
34274
|
+
const amount4 = Number(amountStr);
|
|
34262
34275
|
const e = entryFor(leg);
|
|
34263
34276
|
e.deposits = amountStr;
|
|
34264
|
-
e.depositsUSD =
|
|
34265
|
-
e.depositsUSDOracle =
|
|
34277
|
+
e.depositsUSD = amount4 * leg.displayPrice;
|
|
34278
|
+
e.depositsUSDOracle = amount4 * leg.oraclePrice;
|
|
34266
34279
|
e.collateralEnabled = supplyRaw > 0n;
|
|
34267
|
-
deposits24h +=
|
|
34280
|
+
deposits24h += amount4 * leg.priceHist;
|
|
34268
34281
|
}
|
|
34269
34282
|
for (const leg of debtLegs) {
|
|
34270
34283
|
const amountStr = parseRawAmount(
|
|
34271
34284
|
legRaw(leg, borrowRaw).toString(),
|
|
34272
34285
|
leg.decimals
|
|
34273
34286
|
);
|
|
34274
|
-
const
|
|
34287
|
+
const amount4 = Number(amountStr);
|
|
34275
34288
|
const e = entryFor(leg);
|
|
34276
34289
|
e.debt = amountStr;
|
|
34277
|
-
e.debtUSD =
|
|
34278
|
-
e.debtUSDOracle =
|
|
34279
|
-
debt24h +=
|
|
34290
|
+
e.debtUSD = amount4 * leg.displayPrice;
|
|
34291
|
+
e.debtUSDOracle = amount4 * leg.oraclePrice;
|
|
34292
|
+
debt24h += amount4 * leg.priceHist;
|
|
34280
34293
|
}
|
|
34281
34294
|
histData[nftId] = {
|
|
34282
34295
|
totalDeposits24h: deposits24h,
|
|
@@ -34529,10 +34542,10 @@ var getDolomiteUserDataConverter = (lender, chainId, account, metaMap) => {
|
|
|
34529
34542
|
const meta = metaMap?.[key3];
|
|
34530
34543
|
if (!meta) return;
|
|
34531
34544
|
const decimals = meta.asset?.decimals ?? 18;
|
|
34532
|
-
const
|
|
34545
|
+
const amount4 = parseRawAmount(wei.value, decimals);
|
|
34533
34546
|
const isSupply = wei.sign;
|
|
34534
|
-
const deposits = isSupply ?
|
|
34535
|
-
const debt = isSupply ? "0" :
|
|
34547
|
+
const deposits = isSupply ? amount4 : "0";
|
|
34548
|
+
const debt = isSupply ? "0" : amount4;
|
|
34536
34549
|
const debtPar = isSupply ? "0" : pars[k]?.value?.toString() ?? "0";
|
|
34537
34550
|
const price2 = getDisplayPrice(meta);
|
|
34538
34551
|
const oPrice = getOraclePrice(meta);
|
|
@@ -35965,11 +35978,11 @@ var big13 = (v) => {
|
|
|
35965
35978
|
};
|
|
35966
35979
|
function fraxlendToAmount(shares, totalAmount, totalShares, roundUp) {
|
|
35967
35980
|
if (totalShares === 0n) return shares;
|
|
35968
|
-
let
|
|
35969
|
-
if (roundUp && totalAmount > 0n &&
|
|
35970
|
-
|
|
35981
|
+
let amount4 = shares * totalAmount / totalShares;
|
|
35982
|
+
if (roundUp && totalAmount > 0n && amount4 * totalShares / totalAmount < shares) {
|
|
35983
|
+
amount4 = amount4 + 1n;
|
|
35971
35984
|
}
|
|
35972
|
-
return
|
|
35985
|
+
return amount4;
|
|
35973
35986
|
}
|
|
35974
35987
|
var getFraxlendUserDataConverter = (lender, chainId, account, meta) => {
|
|
35975
35988
|
const pairs = fraxlendPairsFor(lender, chainId);
|
|
@@ -41885,7 +41898,7 @@ function unflattenLenderData(pools) {
|
|
|
41885
41898
|
}
|
|
41886
41899
|
return result;
|
|
41887
41900
|
}
|
|
41888
|
-
var getLenderUserDataResult = async (chainId, queriesRaw,
|
|
41901
|
+
var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient19, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, retries = 3, logs = false, concurrency = 1, permanentFailures, onEndpointFailure) => {
|
|
41889
41902
|
const queries = organizeUserQueries(queriesRaw);
|
|
41890
41903
|
const builtCalls = await Promise.all(
|
|
41891
41904
|
queries.map(async (query3) => {
|
|
@@ -41895,7 +41908,7 @@ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient18, allowF
|
|
|
41895
41908
|
query3.lender,
|
|
41896
41909
|
query3.account,
|
|
41897
41910
|
query3.params,
|
|
41898
|
-
|
|
41911
|
+
getEvmClient19
|
|
41899
41912
|
);
|
|
41900
41913
|
return callData.map((call) => ({ call, abi: call.abi ?? abi }));
|
|
41901
41914
|
})
|
|
@@ -41905,7 +41918,7 @@ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient18, allowF
|
|
|
41905
41918
|
chainId,
|
|
41906
41919
|
calls.map((call) => call.abi),
|
|
41907
41920
|
calls.map((call) => call.call),
|
|
41908
|
-
|
|
41921
|
+
getEvmClient19,
|
|
41909
41922
|
concurrency,
|
|
41910
41923
|
retries,
|
|
41911
41924
|
allowFailure,
|
|
@@ -42204,29 +42217,29 @@ async function getMergedUserData(chainId, balanceQueries, permissionParams, lend
|
|
|
42204
42217
|
});
|
|
42205
42218
|
return parseMergedResult(chainId, rawResults, prepared, lenderState);
|
|
42206
42219
|
}
|
|
42207
|
-
function toCompoundV2Shares(entry,
|
|
42220
|
+
function toCompoundV2Shares(entry, amount4) {
|
|
42208
42221
|
const raw = entry.params?.exchangeRateCurrent;
|
|
42209
|
-
if (!raw || raw === "0x") return
|
|
42222
|
+
if (!raw || raw === "0x") return amount4;
|
|
42210
42223
|
try {
|
|
42211
42224
|
const exRate = BigInt(raw);
|
|
42212
|
-
if (exRate === 0n) return
|
|
42213
|
-
return
|
|
42225
|
+
if (exRate === 0n) return amount4;
|
|
42226
|
+
return amount4 * 10n ** 18n / exRate * 1001n / 1000n;
|
|
42214
42227
|
} catch {
|
|
42215
|
-
return
|
|
42228
|
+
return amount4;
|
|
42216
42229
|
}
|
|
42217
42230
|
}
|
|
42218
|
-
function toSiloShares(entry,
|
|
42231
|
+
function toSiloShares(entry, amount4, chainId, lender, tokenAddress) {
|
|
42219
42232
|
const raw = entry.params?.collateralRate;
|
|
42220
|
-
if (!raw || raw === "0x") return
|
|
42233
|
+
if (!raw || raw === "0x") return amount4;
|
|
42221
42234
|
try {
|
|
42222
42235
|
const rate = BigInt(raw);
|
|
42223
|
-
if (rate === 0n) return
|
|
42236
|
+
if (rate === 0n) return amount4;
|
|
42224
42237
|
const half = getSiloHalfForUnderlying(chainId, lender, tokenAddress);
|
|
42225
|
-
if (!half) return
|
|
42238
|
+
if (!half) return amount4;
|
|
42226
42239
|
const oneUnit = BigInt(10) ** BigInt(half.decimals);
|
|
42227
|
-
return
|
|
42240
|
+
return amount4 * oneUnit / rate * 1001n / 1000n;
|
|
42228
42241
|
} catch {
|
|
42229
|
-
return
|
|
42242
|
+
return amount4;
|
|
42230
42243
|
}
|
|
42231
42244
|
}
|
|
42232
42245
|
function resolveDebitDataKey(chainId, lender, tokenAddress, cToken, isProtected) {
|
|
@@ -42262,7 +42275,7 @@ function resolveDebitDataKey(chainId, lender, tokenAddress, cToken, isProtected)
|
|
|
42262
42275
|
return tokenAddress.toLowerCase();
|
|
42263
42276
|
}
|
|
42264
42277
|
function needsLenderApproval(params) {
|
|
42265
|
-
const { lender, lenderDebitData, tokenAddress, amount:
|
|
42278
|
+
const { lender, lenderDebitData, tokenAddress, amount: amount4, chainId, cToken, isProtected } = params;
|
|
42266
42279
|
if (!lenderDebitData) return true;
|
|
42267
42280
|
if (isAaveV4Type(lender)) {
|
|
42268
42281
|
const key4 = (params.aaveV4Spoke ?? tokenAddress).toLowerCase();
|
|
@@ -42279,33 +42292,33 @@ function needsLenderApproval(params) {
|
|
|
42279
42292
|
const entry = lenderDebitData[key3];
|
|
42280
42293
|
if (!entry || entry.amount === void 0) return true;
|
|
42281
42294
|
if (isCompoundV2Type(lender) || isVenusType(lender)) {
|
|
42282
|
-
const requiredShares = toCompoundV2Shares(entry,
|
|
42295
|
+
const requiredShares = toCompoundV2Shares(entry, amount4);
|
|
42283
42296
|
return entry.amount < requiredShares;
|
|
42284
42297
|
}
|
|
42285
42298
|
if (isSiloV2Type(lender) || isSiloV3Type(lender)) {
|
|
42286
|
-
const requiredShares = toSiloShares(entry,
|
|
42299
|
+
const requiredShares = toSiloShares(entry, amount4, chainId, lender, tokenAddress);
|
|
42287
42300
|
return entry.amount < requiredShares;
|
|
42288
42301
|
}
|
|
42289
42302
|
if (isCompoundV3(lender)) {
|
|
42290
42303
|
return entry.amount === 0n;
|
|
42291
42304
|
}
|
|
42292
|
-
return entry.amount <
|
|
42305
|
+
return entry.amount < amount4;
|
|
42293
42306
|
}
|
|
42294
42307
|
function needsTokenApproval(params) {
|
|
42295
|
-
const { debitData, spender, amount:
|
|
42308
|
+
const { debitData, spender, amount: amount4, chainId, usePermit2 } = params;
|
|
42296
42309
|
if (!debitData) return true;
|
|
42297
42310
|
const spenderLower = spender.toLowerCase();
|
|
42298
42311
|
if (usePermit2) {
|
|
42299
42312
|
const p2 = debitData.permit2?.[spenderLower];
|
|
42300
|
-
return !p2 || p2.amount <
|
|
42313
|
+
return !p2 || p2.amount < amount4;
|
|
42301
42314
|
}
|
|
42302
42315
|
const permit2Address = getPermit2ContractAddress(chainId).toLowerCase();
|
|
42303
42316
|
if (spenderLower === permit2Address) {
|
|
42304
42317
|
const p2 = debitData.permit2?.[spenderLower];
|
|
42305
|
-
if (p2 && p2.amount >=
|
|
42318
|
+
if (p2 && p2.amount >= amount4) return false;
|
|
42306
42319
|
}
|
|
42307
42320
|
const allowance = debitData.allowances?.[spenderLower] ?? 0n;
|
|
42308
|
-
return allowance <
|
|
42321
|
+
return allowance < amount4;
|
|
42309
42322
|
}
|
|
42310
42323
|
var MORPHO_USER_SUBGRAPH_URLS = {
|
|
42311
42324
|
[Chain.SEI_NETWORK]: "https://api.goldsky.com/api/public/project_cmiergfbv4vma01vb642yaeam/subgraphs/morphoblue-sei/1.0.1/gn",
|
|
@@ -42812,10 +42825,10 @@ function fuseLenderData(userDataResult, summary) {
|
|
|
42812
42825
|
}
|
|
42813
42826
|
|
|
42814
42827
|
// src/lending/margin/base/standard/deposit.ts
|
|
42815
|
-
function computeDepositDelta(
|
|
42828
|
+
function computeDepositDelta(amount4, price2, balanceData2, config, modeId, createNewSubAccount = false, apr, yieldParams) {
|
|
42816
42829
|
const { borrowCollateralFactor, collateralFactor } = getAssetConfig(config, modeId);
|
|
42817
42830
|
const base = createNewSubAccount ? EMPTY_BALANCE : balanceData2;
|
|
42818
|
-
const dollarAmount =
|
|
42831
|
+
const dollarAmount = amount4 * price2;
|
|
42819
42832
|
const postTrade = {
|
|
42820
42833
|
...base,
|
|
42821
42834
|
borrowDiscountedCollateral: base.borrowDiscountedCollateral + borrowCollateralFactor * dollarAmount,
|
|
@@ -42862,13 +42875,13 @@ function computeDepositDelta(amount3, price2, balanceData2, config, modeId, crea
|
|
|
42862
42875
|
}
|
|
42863
42876
|
|
|
42864
42877
|
// src/lending/margin/base/deposit.ts
|
|
42865
|
-
function computeDepositDelta2(lender,
|
|
42878
|
+
function computeDepositDelta2(lender, amount4, price2, balanceData2, config, modeId, createNewSubAccount, apr, yieldParams, targetMarketUid, positions) {
|
|
42866
42879
|
if (isSumerType(lender)) {
|
|
42867
42880
|
if (!positions || targetMarketUid === void 0) {
|
|
42868
42881
|
throw new Error("Sumer operations require positions and targetMarketUid");
|
|
42869
42882
|
}
|
|
42870
42883
|
return computeSumerDepositDelta(
|
|
42871
|
-
|
|
42884
|
+
amount4,
|
|
42872
42885
|
price2,
|
|
42873
42886
|
targetMarketUid,
|
|
42874
42887
|
balanceData2,
|
|
@@ -42882,7 +42895,7 @@ function computeDepositDelta2(lender, amount3, price2, balanceData2, config, mod
|
|
|
42882
42895
|
throw new Error("Standard operations require config and modeId");
|
|
42883
42896
|
}
|
|
42884
42897
|
return computeDepositDelta(
|
|
42885
|
-
|
|
42898
|
+
amount4,
|
|
42886
42899
|
price2,
|
|
42887
42900
|
balanceData2,
|
|
42888
42901
|
config,
|
|
@@ -42894,9 +42907,9 @@ function computeDepositDelta2(lender, amount3, price2, balanceData2, config, mod
|
|
|
42894
42907
|
}
|
|
42895
42908
|
|
|
42896
42909
|
// src/lending/margin/base/standard/withdraw.ts
|
|
42897
|
-
function computeWithdrawDelta(
|
|
42910
|
+
function computeWithdrawDelta(amount4, price2, balanceData2, config, modeId, apr, yieldParams) {
|
|
42898
42911
|
const { borrowCollateralFactor, collateralFactor } = getAssetConfig(config, modeId);
|
|
42899
|
-
const dollarAmount =
|
|
42912
|
+
const dollarAmount = amount4 * price2;
|
|
42900
42913
|
const postTrade = {
|
|
42901
42914
|
...balanceData2,
|
|
42902
42915
|
borrowDiscountedCollateral: balanceData2.borrowDiscountedCollateral - borrowCollateralFactor * dollarAmount,
|
|
@@ -42943,13 +42956,13 @@ function computeWithdrawDelta(amount3, price2, balanceData2, config, modeId, apr
|
|
|
42943
42956
|
}
|
|
42944
42957
|
|
|
42945
42958
|
// src/lending/margin/base/withdraw.ts
|
|
42946
|
-
function computeWithdrawDelta2(lender,
|
|
42959
|
+
function computeWithdrawDelta2(lender, amount4, price2, balanceData2, config, modeId, apr, yieldParams, targetMarketUid, positions) {
|
|
42947
42960
|
if (isSumerType(lender)) {
|
|
42948
42961
|
if (!positions || targetMarketUid === void 0) {
|
|
42949
42962
|
throw new Error("Sumer operations require positions and targetMarketUid");
|
|
42950
42963
|
}
|
|
42951
42964
|
return computeSumerWithdrawDelta(
|
|
42952
|
-
|
|
42965
|
+
amount4,
|
|
42953
42966
|
price2,
|
|
42954
42967
|
targetMarketUid,
|
|
42955
42968
|
balanceData2,
|
|
@@ -42962,7 +42975,7 @@ function computeWithdrawDelta2(lender, amount3, price2, balanceData2, config, mo
|
|
|
42962
42975
|
throw new Error("Standard operations require config and modeId");
|
|
42963
42976
|
}
|
|
42964
42977
|
return computeWithdrawDelta(
|
|
42965
|
-
|
|
42978
|
+
amount4,
|
|
42966
42979
|
price2,
|
|
42967
42980
|
balanceData2,
|
|
42968
42981
|
config,
|
|
@@ -42973,9 +42986,9 @@ function computeWithdrawDelta2(lender, amount3, price2, balanceData2, config, mo
|
|
|
42973
42986
|
}
|
|
42974
42987
|
|
|
42975
42988
|
// src/lending/margin/base/standard/borrow.ts
|
|
42976
|
-
function computeBorrowDelta(
|
|
42989
|
+
function computeBorrowDelta(amount4, price2, balanceData2, config, modeId, apr, yieldParams, irMode) {
|
|
42977
42990
|
const { borrowFactor } = getAssetConfig(config, modeId);
|
|
42978
|
-
const dollarAmount =
|
|
42991
|
+
const dollarAmount = amount4 * price2;
|
|
42979
42992
|
const postTrade = {
|
|
42980
42993
|
...balanceData2,
|
|
42981
42994
|
debt: balanceData2.debt + dollarAmount,
|
|
@@ -43024,13 +43037,13 @@ function computeBorrowDelta(amount3, price2, balanceData2, config, modeId, apr,
|
|
|
43024
43037
|
}
|
|
43025
43038
|
|
|
43026
43039
|
// src/lending/margin/base/borrow.ts
|
|
43027
|
-
function computeBorrowDelta2(lender,
|
|
43040
|
+
function computeBorrowDelta2(lender, amount4, price2, balanceData2, config, modeId, apr, yieldParams, irMode, targetMarketUid, positions) {
|
|
43028
43041
|
if (isSumerType(lender)) {
|
|
43029
43042
|
if (!positions || targetMarketUid === void 0) {
|
|
43030
43043
|
throw new Error("Sumer operations require positions and targetMarketUid");
|
|
43031
43044
|
}
|
|
43032
43045
|
return computeSumerBorrowDelta(
|
|
43033
|
-
|
|
43046
|
+
amount4,
|
|
43034
43047
|
price2,
|
|
43035
43048
|
targetMarketUid,
|
|
43036
43049
|
balanceData2,
|
|
@@ -43044,7 +43057,7 @@ function computeBorrowDelta2(lender, amount3, price2, balanceData2, config, mode
|
|
|
43044
43057
|
throw new Error("Standard operations require config and modeId");
|
|
43045
43058
|
}
|
|
43046
43059
|
return computeBorrowDelta(
|
|
43047
|
-
|
|
43060
|
+
amount4,
|
|
43048
43061
|
price2,
|
|
43049
43062
|
balanceData2,
|
|
43050
43063
|
config,
|
|
@@ -43056,9 +43069,9 @@ function computeBorrowDelta2(lender, amount3, price2, balanceData2, config, mode
|
|
|
43056
43069
|
}
|
|
43057
43070
|
|
|
43058
43071
|
// src/lending/margin/base/standard/repay.ts
|
|
43059
|
-
function computeRepayDelta(
|
|
43072
|
+
function computeRepayDelta(amount4, price2, balanceData2, config, modeId, apr, yieldParams, irMode) {
|
|
43060
43073
|
const { borrowFactor } = getAssetConfig(config, modeId);
|
|
43061
|
-
const dollarAmount =
|
|
43074
|
+
const dollarAmount = amount4 * price2;
|
|
43062
43075
|
const postTrade = {
|
|
43063
43076
|
...balanceData2,
|
|
43064
43077
|
debt: balanceData2.debt - dollarAmount,
|
|
@@ -43107,13 +43120,13 @@ function computeRepayDelta(amount3, price2, balanceData2, config, modeId, apr, y
|
|
|
43107
43120
|
}
|
|
43108
43121
|
|
|
43109
43122
|
// src/lending/margin/base/repay.ts
|
|
43110
|
-
function computeRepayDelta2(lender,
|
|
43123
|
+
function computeRepayDelta2(lender, amount4, price2, balanceData2, config, modeId, apr, yieldParams, irMode, targetMarketUid, positions) {
|
|
43111
43124
|
if (isSumerType(lender)) {
|
|
43112
43125
|
if (!positions || targetMarketUid === void 0) {
|
|
43113
43126
|
throw new Error("Sumer operations require positions and targetMarketUid");
|
|
43114
43127
|
}
|
|
43115
43128
|
return computeSumerRepayDelta(
|
|
43116
|
-
|
|
43129
|
+
amount4,
|
|
43117
43130
|
price2,
|
|
43118
43131
|
targetMarketUid,
|
|
43119
43132
|
balanceData2,
|
|
@@ -43127,7 +43140,7 @@ function computeRepayDelta2(lender, amount3, price2, balanceData2, config, modeI
|
|
|
43127
43140
|
throw new Error("Standard operations require config and modeId");
|
|
43128
43141
|
}
|
|
43129
43142
|
return computeRepayDelta(
|
|
43130
|
-
|
|
43143
|
+
amount4,
|
|
43131
43144
|
price2,
|
|
43132
43145
|
balanceData2,
|
|
43133
43146
|
config,
|
|
@@ -45044,6 +45057,42 @@ var wbethFetcher = {
|
|
|
45044
45057
|
}
|
|
45045
45058
|
};
|
|
45046
45059
|
|
|
45060
|
+
// src/yields/intrinsic/fetchers/treehouse.ts
|
|
45061
|
+
var TETH_POOL_ID = "5762f4a8-bb48-45d6-90ed-2d93d1777169";
|
|
45062
|
+
var TAVAX_POOL_ID = "40a1e447-058d-4c5b-b567-30543ea185c3";
|
|
45063
|
+
var TREEHOUSE_APY_URL = "https://api.treehouse.finance/apy";
|
|
45064
|
+
var TETH_KEYS = ["Treehouse ETH::TETH", "Treehouse ETH::tETH"];
|
|
45065
|
+
var fetchTethApr = async () => {
|
|
45066
|
+
try {
|
|
45067
|
+
const res = await fetch(TREEHOUSE_APY_URL, {
|
|
45068
|
+
headers: { accept: "application/json" },
|
|
45069
|
+
signal: AbortSignal.timeout(8e3)
|
|
45070
|
+
});
|
|
45071
|
+
if (!res.ok) throw new Error(`Treehouse HTTP ${res.status}`);
|
|
45072
|
+
const json = await res.json();
|
|
45073
|
+
const apr = json?.total_apr_teth;
|
|
45074
|
+
if (typeof apr === "number" && Number.isFinite(apr) && apr > 0) return apr;
|
|
45075
|
+
throw new Error("Treehouse: no total_apr_teth");
|
|
45076
|
+
} catch {
|
|
45077
|
+
return apyToAprPercent(await fetchDefiLlamaApy(TETH_POOL_ID));
|
|
45078
|
+
}
|
|
45079
|
+
};
|
|
45080
|
+
var tethFetcher = {
|
|
45081
|
+
label: "TETH",
|
|
45082
|
+
fetch: async () => {
|
|
45083
|
+
const apr = await fetchTethApr();
|
|
45084
|
+
return Object.fromEntries(TETH_KEYS.map((k) => [k, apr]));
|
|
45085
|
+
}
|
|
45086
|
+
};
|
|
45087
|
+
var tavaxFetcher = {
|
|
45088
|
+
label: "TAVAX",
|
|
45089
|
+
fetch: async () => ({
|
|
45090
|
+
"Treehouse AVAX::tAVAX": apyToAprPercent(
|
|
45091
|
+
await fetchDefiLlamaApy(TAVAX_POOL_ID)
|
|
45092
|
+
)
|
|
45093
|
+
})
|
|
45094
|
+
};
|
|
45095
|
+
|
|
45047
45096
|
// src/vaults/lst/registry.ts
|
|
45048
45097
|
var LST_REGISTRY = {
|
|
45049
45098
|
// Monad (143) — native-MON LSTs. shMON / aprMON are ERC-4626 over native
|
|
@@ -45132,6 +45181,50 @@ var LST_REGISTRY = {
|
|
|
45132
45181
|
}
|
|
45133
45182
|
],
|
|
45134
45183
|
"1": [
|
|
45184
|
+
{
|
|
45185
|
+
// Treehouse tETH — an ERC-4626 share over wstETH that runs a
|
|
45186
|
+
// leveraged staking carry (wstETH collateral on Aave Core / Aave
|
|
45187
|
+
// Prime / Spark, ETH borrowed against it, converted back to wstETH).
|
|
45188
|
+
//
|
|
45189
|
+
// THREE things the generic 4626 path gets wrong here:
|
|
45190
|
+
// 1. `asset()` is NOT wstETH — it returns
|
|
45191
|
+
// `InternalAccountingUnit_Wrapped liquid staked Ether 2.0`
|
|
45192
|
+
// (`IAU_wstETH`, 0x1b6238e9…), a synthetic unit minted 1:1
|
|
45193
|
+
// against the real underlying. The underlying below is
|
|
45194
|
+
// `Vault.getUnderlying()`; never read `asset()`.
|
|
45195
|
+
// 2. Entry is the `TreehouseRouter`, not the share token. It takes
|
|
45196
|
+
// native ETH (`depositETH()`) or any `Vault.isAllowableAsset`
|
|
45197
|
+
// ERC-20 (stETH / WETH / wstETH) via `deposit(asset, amount)`,
|
|
45198
|
+
// and **credits `msg.sender`** — there is no receiver argument.
|
|
45199
|
+
// 3. Exit is neither of the share's own 4626 legs: `maxWithdraw`
|
|
45200
|
+
// and `maxRedeem` both read 0. It is the Fastlane (instant,
|
|
45201
|
+
// 50 bps) or RedemptionV2 (queued, 5 bps) — hence
|
|
45202
|
+
// `fee-or-queued`, with `liquidity` measured by the reader off
|
|
45203
|
+
// `Fastlane.getRedeemableAmount()`.
|
|
45204
|
+
address: "0xd11c452fc99cf405034ee446803b6f6c1f6d5ed8",
|
|
45205
|
+
underlying: "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0",
|
|
45206
|
+
// wstETH
|
|
45207
|
+
symbol: "tETH",
|
|
45208
|
+
brand: "Treehouse",
|
|
45209
|
+
decimals: 18,
|
|
45210
|
+
reader: "treehouseTAsset",
|
|
45211
|
+
isErc4626: true,
|
|
45212
|
+
isRebasing: false,
|
|
45213
|
+
isMintable: true,
|
|
45214
|
+
isNativeUnderlying: true,
|
|
45215
|
+
mintContract: "0xefa3fa8e85d2b3cfdb250cdea156c2c6c90628f5",
|
|
45216
|
+
// TreehouseRouter
|
|
45217
|
+
mintInputAsset: "native",
|
|
45218
|
+
withdrawalMode: "fee-or-queued",
|
|
45219
|
+
// Read live by the reader (7 d today, and it is an owner dial).
|
|
45220
|
+
withdrawalCooldownSeconds: 7 * 86400,
|
|
45221
|
+
yieldFetcher: tethFetcher,
|
|
45222
|
+
yieldKey: "Treehouse ETH::TETH",
|
|
45223
|
+
readerExtras: {
|
|
45224
|
+
treehouseFastlane: "0x829525417cd78cba0f99a8736426fc299506c0d6",
|
|
45225
|
+
treehouseRedemption: "0xcd63a29faff07130d3af89bb4f40778938aabb85"
|
|
45226
|
+
}
|
|
45227
|
+
},
|
|
45135
45228
|
{
|
|
45136
45229
|
address: "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0",
|
|
45137
45230
|
underlying: "0x0000000000000000000000000000000000000000",
|
|
@@ -45804,6 +45897,38 @@ var LST_REGISTRY = {
|
|
|
45804
45897
|
}
|
|
45805
45898
|
],
|
|
45806
45899
|
"43114": [
|
|
45900
|
+
{
|
|
45901
|
+
// Treehouse tAVAX — the tETH design on Avalanche, denominated in
|
|
45902
|
+
// BENQI sAVAX. Same Router / Vault / RedemptionController stack; see
|
|
45903
|
+
// the tETH entry on chain 1 for the three traps.
|
|
45904
|
+
//
|
|
45905
|
+
// The Avalanche Router carries NO `depositETH()` (selector-scanned
|
|
45906
|
+
// against the live runtime), so native AVAX is not an entry here —
|
|
45907
|
+
// the allowable set is sAVAX and WAVAX only.
|
|
45908
|
+
address: "0x14a84f1a61ccd7d1be596a6cc11fe33a36bc1646",
|
|
45909
|
+
underlying: "0x2b2c81e08f1af8835a78bb2a90ae924ace0ea4be",
|
|
45910
|
+
// sAVAX
|
|
45911
|
+
symbol: "tAVAX",
|
|
45912
|
+
brand: "Treehouse",
|
|
45913
|
+
decimals: 18,
|
|
45914
|
+
reader: "treehouseTAsset",
|
|
45915
|
+
isErc4626: true,
|
|
45916
|
+
isRebasing: false,
|
|
45917
|
+
isMintable: true,
|
|
45918
|
+
isNativeUnderlying: false,
|
|
45919
|
+
mintContract: "0x5f4d2e6c118b5e3c74f0b61de40f627ca9873d6e",
|
|
45920
|
+
// TreehouseRouter
|
|
45921
|
+
mintInputAsset: "0x2b2c81e08f1af8835a78bb2a90ae924ace0ea4be",
|
|
45922
|
+
withdrawalMode: "fee-or-queued",
|
|
45923
|
+
// 17 d live — NOT the 7 d the docs describe. Read live by the reader.
|
|
45924
|
+
withdrawalCooldownSeconds: 17 * 86400,
|
|
45925
|
+
yieldFetcher: tavaxFetcher,
|
|
45926
|
+
yieldKey: "Treehouse AVAX::tAVAX",
|
|
45927
|
+
readerExtras: {
|
|
45928
|
+
treehouseFastlane: "0x3d00a639183b07e35efef044ee6cc14e8598a01c",
|
|
45929
|
+
treehouseRedemption: "0x765f6dc8496ca7ef1e4a391be10185229aacf04b"
|
|
45930
|
+
}
|
|
45931
|
+
},
|
|
45807
45932
|
{
|
|
45808
45933
|
address: "0x2b2c81e08f1af8835a78bb2a90ae924ace0ea4be",
|
|
45809
45934
|
underlying: "0x0000000000000000000000000000000000000000",
|
|
@@ -45845,6 +45970,40 @@ var LST_REGISTRY = {
|
|
|
45845
45970
|
}
|
|
45846
45971
|
],
|
|
45847
45972
|
"999": [
|
|
45973
|
+
{
|
|
45974
|
+
// Treehouse tHYPE — the tETH design on HyperEVM, denominated in
|
|
45975
|
+
// Kinetiq kHYPE. Same stack; see the tETH entry on chain 1.
|
|
45976
|
+
//
|
|
45977
|
+
// No `depositETH()` on this Router either (selector-scanned), so the
|
|
45978
|
+
// entry set is kHYPE and WHYPE (0x5555…), never native HYPE.
|
|
45979
|
+
//
|
|
45980
|
+
// NO yield fetcher: DefiLlama carries no `treehouse-protocol` pool
|
|
45981
|
+
// for tHYPE and Treehouse's own `/apy` route serves tETH only, so the
|
|
45982
|
+
// row reports a `supplyRate` of 0 rather than an invented number.
|
|
45983
|
+
// The vault launched recently (share price 1.0007) — revisit with an
|
|
45984
|
+
// archival `convertToAssets` delta once it has real history.
|
|
45985
|
+
address: "0xb83d27f0f4133a7b0377a88089583131a903fdc7",
|
|
45986
|
+
underlying: "0xfd739d4e423301ce9385c1fb8850539d657c296d",
|
|
45987
|
+
// kHYPE
|
|
45988
|
+
symbol: "tHYPE",
|
|
45989
|
+
brand: "Treehouse",
|
|
45990
|
+
decimals: 18,
|
|
45991
|
+
reader: "treehouseTAsset",
|
|
45992
|
+
isErc4626: true,
|
|
45993
|
+
isRebasing: false,
|
|
45994
|
+
isMintable: true,
|
|
45995
|
+
isNativeUnderlying: false,
|
|
45996
|
+
mintContract: "0x1620b7e5c9099c8bcbc326b55e0b8440eda9d30a",
|
|
45997
|
+
// TreehouseRouter
|
|
45998
|
+
mintInputAsset: "0xfd739d4e423301ce9385c1fb8850539d657c296d",
|
|
45999
|
+
withdrawalMode: "fee-or-queued",
|
|
46000
|
+
// 10 d live — again not the docs' 7 d. Read live by the reader.
|
|
46001
|
+
withdrawalCooldownSeconds: 10 * 86400,
|
|
46002
|
+
readerExtras: {
|
|
46003
|
+
treehouseFastlane: "0x3018e0747549835faa8d06cf4809b1a2519fab31",
|
|
46004
|
+
treehouseRedemption: "0xcebbb011c2f29b0ed25895c54662bd1ccad30280"
|
|
46005
|
+
}
|
|
46006
|
+
},
|
|
45848
46007
|
{
|
|
45849
46008
|
// hbHYPE Ultra — Hyperbeat's ERC-4626 staked HYPE vault.
|
|
45850
46009
|
// TokenizedAccount impl, 4626-compliant, accepts WHYPE.
|
|
@@ -47513,6 +47672,84 @@ var strataFetcher = {
|
|
|
47513
47672
|
return out;
|
|
47514
47673
|
}
|
|
47515
47674
|
};
|
|
47675
|
+
var thBill = "Theo Short Duration US Treasury Fund::THBILL";
|
|
47676
|
+
var THBILL_DEFILLAMA_POOL = "e17dab50-85b1-45e8-b4a5-b8ae7898c4a3";
|
|
47677
|
+
var thbillFetcher = {
|
|
47678
|
+
label: "THBILL",
|
|
47679
|
+
fetch: async () => {
|
|
47680
|
+
const apy = await fetchDefiLlamaApy(THBILL_DEFILLAMA_POOL);
|
|
47681
|
+
return { [thBill]: apyToAprPercent(apy) };
|
|
47682
|
+
}
|
|
47683
|
+
};
|
|
47684
|
+
var STHUSD_VAULT = "0xa808bc9775cb41c52c7842f8b50427fe7a770326";
|
|
47685
|
+
var STHUSD_UNIT = 10n ** 6n;
|
|
47686
|
+
var STHUSD_WINDOW_SECONDS = 30 * 24 * 60 * 60;
|
|
47687
|
+
var ETH_BLOCK_TIME_SECONDS = 12;
|
|
47688
|
+
var STHUSD_WINDOW_BLOCKS = BigInt(
|
|
47689
|
+
Math.floor(STHUSD_WINDOW_SECONDS / ETH_BLOCK_TIME_SECONDS)
|
|
47690
|
+
);
|
|
47691
|
+
var STHUSD_MAX_RPC_TRIES = 2;
|
|
47692
|
+
var STHUSD_DEADLINE_MS = 12e3;
|
|
47693
|
+
var STHUSD_KEY = "STHUSD";
|
|
47694
|
+
var STHUSD_GROUP_KEY = "Staked thUSD::STHUSD";
|
|
47695
|
+
var STHUSD_GROUP_KEY_OFT = "sthUSD::sthUSD";
|
|
47696
|
+
var CONVERT_TO_ASSETS_ABI4 = [
|
|
47697
|
+
{
|
|
47698
|
+
name: "convertToAssets",
|
|
47699
|
+
type: "function",
|
|
47700
|
+
stateMutability: "view",
|
|
47701
|
+
inputs: [{ type: "uint256" }],
|
|
47702
|
+
outputs: [{ type: "uint256" }]
|
|
47703
|
+
}
|
|
47704
|
+
];
|
|
47705
|
+
var readSthUsdRateAt = (client, blockNumber) => client.readContract({
|
|
47706
|
+
address: STHUSD_VAULT,
|
|
47707
|
+
abi: CONVERT_TO_ASSETS_ABI4,
|
|
47708
|
+
functionName: "convertToAssets",
|
|
47709
|
+
args: [STHUSD_UNIT],
|
|
47710
|
+
...blockNumber !== void 0 ? { blockNumber } : {}
|
|
47711
|
+
});
|
|
47712
|
+
var computeSthUsdApr = async () => {
|
|
47713
|
+
let lastErr;
|
|
47714
|
+
const deadline = Date.now() + STHUSD_DEADLINE_MS;
|
|
47715
|
+
for (let rpcId = 0; rpcId < STHUSD_MAX_RPC_TRIES; rpcId++) {
|
|
47716
|
+
if (Date.now() > deadline) break;
|
|
47717
|
+
try {
|
|
47718
|
+
const client = getEvmClient("1", rpcId);
|
|
47719
|
+
const head = await client.getBlockNumber();
|
|
47720
|
+
const pastBlock = head > STHUSD_WINDOW_BLOCKS ? head - STHUSD_WINDOW_BLOCKS : 0n;
|
|
47721
|
+
const [rateNow, rateThen, headBlock, thenBlock] = await Promise.all([
|
|
47722
|
+
readSthUsdRateAt(client),
|
|
47723
|
+
readSthUsdRateAt(client, pastBlock),
|
|
47724
|
+
client.getBlock({ blockNumber: head }),
|
|
47725
|
+
client.getBlock({ blockNumber: pastBlock })
|
|
47726
|
+
]);
|
|
47727
|
+
if (rateNow < STHUSD_UNIT || rateThen < STHUSD_UNIT) {
|
|
47728
|
+
throw new Error("sthUSD: share price below par \u2014 pruned or bad read");
|
|
47729
|
+
}
|
|
47730
|
+
if (rateNow < rateThen) {
|
|
47731
|
+
throw new Error("sthUSD: share price decreased \u2014 non-archival RPC");
|
|
47732
|
+
}
|
|
47733
|
+
const elapsed = Number(headBlock.timestamp - thenBlock.timestamp);
|
|
47734
|
+
if (elapsed <= 0) throw new Error("sthUSD: non-positive window");
|
|
47735
|
+
return annualizeRateDeltaPercent(rateNow, rateThen, elapsed);
|
|
47736
|
+
} catch (e) {
|
|
47737
|
+
lastErr = e;
|
|
47738
|
+
}
|
|
47739
|
+
}
|
|
47740
|
+
throw lastErr ?? new Error("sthUSD: no RPC served archive state");
|
|
47741
|
+
};
|
|
47742
|
+
var sthusdFetcher = {
|
|
47743
|
+
label: "STHUSD",
|
|
47744
|
+
fetch: async () => {
|
|
47745
|
+
const apr = await computeSthUsdApr().catch(() => 0);
|
|
47746
|
+
return {
|
|
47747
|
+
[STHUSD_KEY]: apr,
|
|
47748
|
+
[STHUSD_GROUP_KEY]: apr,
|
|
47749
|
+
[STHUSD_GROUP_KEY_OFT]: apr
|
|
47750
|
+
};
|
|
47751
|
+
}
|
|
47752
|
+
};
|
|
47516
47753
|
var RAY9 = 10n ** 27n;
|
|
47517
47754
|
var YEAR_SECONDS11 = 31536e3;
|
|
47518
47755
|
var DSR_ABI = [
|
|
@@ -50506,6 +50743,87 @@ var SINGLE_CHAIN_ENTRIES = {
|
|
|
50506
50743
|
solvency: "overcollateralized",
|
|
50507
50744
|
yieldFetcher: frankencoinSavingsFetcher,
|
|
50508
50745
|
yieldKey: zchfSavingsKey(Chain.ETHEREUM_MAINNET)
|
|
50746
|
+
},
|
|
50747
|
+
{
|
|
50748
|
+
// Theo **sthUSD** — the ERC-4626 staked wrapper over `thUSD`, Theo's
|
|
50749
|
+
// gold-yield stablecoin. Source Sourcify-verified on chain 1
|
|
50750
|
+
// (`contracts/thusd/SthUSD.sol` behind the UUPS proxy, impl
|
|
50751
|
+
// `0x342487f9…`), so every claim below is read off the code rather
|
|
50752
|
+
// than inferred.
|
|
50753
|
+
//
|
|
50754
|
+
// $24.20M held / 23.83M shares, price 1.015636 (2026-08-25). Ethereum
|
|
50755
|
+
// is the ONLY vault: `0xd1db2090…` is a LayerZero OFT Adapter that
|
|
50756
|
+
// LOCKS these shares and mints a bare OFT at the same address on
|
|
50757
|
+
// Stable (988), Arbitrum, BNB and Mantle — and **97 % of the supply
|
|
50758
|
+
// has left for Stable**, where the mirror is the largest Morpho Blue
|
|
50759
|
+
// collateral on the chain. See the `'988'` row for that side.
|
|
50760
|
+
//
|
|
50761
|
+
// **The yield is a PUSH, not a stream, and the row must not imply
|
|
50762
|
+
// otherwise.** A `yieldDistributor` calls `setYield(amount)`, which
|
|
50763
|
+
// reverts while `getUnvestedAmount() > 0`, so batches cannot overlap;
|
|
50764
|
+
// each vests over `vestingDuration` (10,800 s = 3 h) and then nothing
|
|
50765
|
+
// accrues until the next push. Measured daily on-chain, the share
|
|
50766
|
+
// price steps by at most +142e-6/day (≈ 5.10 % APR) with flat
|
|
50767
|
+
// stretches of up to nine days. `sthusdFetcher` reads a 30-day
|
|
50768
|
+
// trailing delta for exactly this reason — see its docstring before
|
|
50769
|
+
// reaching for a shorter window.
|
|
50770
|
+
//
|
|
50771
|
+
// **The exit is asynchronous and the wait is not free.**
|
|
50772
|
+
// `initiateRedeem(shares, owner)` is permissionless, but it BURNS the
|
|
50773
|
+
// shares immediately and snapshots `assets = convertToAssets(shares)`
|
|
50774
|
+
// at that block; the claim (`redeem`/`withdraw`) unlocks
|
|
50775
|
+
// `lockupPeriod` later and pays that frozen figure, so the five days
|
|
50776
|
+
// earn nothing and there is no cancel path. The claim additionally
|
|
50777
|
+
// requires `msg.sender == owner_` (`OwnerMustCompleteRedeem`), and
|
|
50778
|
+
// `initiateRedeem` books the request under the CALLER — so a
|
|
50779
|
+
// third-party redeem via allowance lands the request on the caller,
|
|
50780
|
+
// not the holder. Hence `request-based`, never `instant`.
|
|
50781
|
+
//
|
|
50782
|
+
// TRAP: **`previewRedeem` and `previewWithdraw` are hardcoded
|
|
50783
|
+
// `return 0`** — the protocol deprecated them in favour of
|
|
50784
|
+
// `maxWithdraw`/`maxRedeem`, which describe only a CLAIMABLE REQUEST
|
|
50785
|
+
// and so read 0 for every ordinary holder, including one sitting on
|
|
50786
|
+
// 23.2M shares for 27 days. Neither view can size an exit here, and
|
|
50787
|
+
// both are the obvious thing to reach for. `previewDeposit` is fine.
|
|
50788
|
+
//
|
|
50789
|
+
// `erc4626-cooldown` with `cooldownGetter: 'lockupPeriod'`: the pin
|
|
50790
|
+
// below is a snapshot of an `onlyOwner` dial with no timelock whose
|
|
50791
|
+
// `MAX_LOCKUP_PERIOD` is **30 days** — six times what is configured
|
|
50792
|
+
// today. Read it live, like Brix's.
|
|
50793
|
+
//
|
|
50794
|
+
// `nav-attested`, CURATED — the one field on this row that must not be
|
|
50795
|
+
// left to the builder's default. `totalAssets()` is honest about the
|
|
50796
|
+
// vault (its own thUSD balance, net of unvested yield and pending
|
|
50797
|
+
// redemptions), so the SHARES are backed by the asset; the trust
|
|
50798
|
+
// question sits one level down, in what backs thUSD — a gold-leasing
|
|
50799
|
+
// and CME-futures-roll book run off-chain and marked by the issuer,
|
|
50800
|
+
// with no on-chain solvency invariant anywhere. Absent, the builder
|
|
50801
|
+
// falls back to `overcollateralized` and only whispers the doubt
|
|
50802
|
+
// through `coverage.pending.counterparty`: a row that says
|
|
50803
|
+
// "overcollateralized" about attested gold is wrong in the one field a
|
|
50804
|
+
// reader checks before trusting the rate. Naming it also earns the
|
|
50805
|
+
// consequences — `nav-drawdown` in `principal.risks`, the
|
|
50806
|
+
// `nav-accrual` rate kind — which are all true here: the share price
|
|
50807
|
+
// moves only when a distributor chooses to push a batch. Same call as
|
|
50808
|
+
// Brix wiTRY.
|
|
50809
|
+
reader: "erc4626-cooldown",
|
|
50810
|
+
solvency: "nav-attested",
|
|
50811
|
+
cooldownGetter: "lockupPeriod",
|
|
50812
|
+
address: "0xa808bc9775cb41c52c7842f8b50427fe7a770326",
|
|
50813
|
+
underlying: "0xa3fe5c7596024e6811e14f029937d5bd8ae485b3",
|
|
50814
|
+
// thUSD
|
|
50815
|
+
symbol: "sthUSD",
|
|
50816
|
+
brand: "Theo",
|
|
50817
|
+
description: "thUSD is Theo's gold-yield stablecoin \u2014 the return comes from leasing physical gold and rolling CME futures, not from lending, and the book runs off-chain with no on-chain solvency invariant. sthUSD stakes it with an appreciating share price, but a distributor PUSHES each batch, so the price steps rather than streams and can sit flat for a week. Deposits are permissionless and uncapped. Exiting is a two-step request: initiating burns the shares and fixes the payout at that block's price, and the claim unlocks 5 days later \u2014 the wait earns nothing and cannot be cancelled.",
|
|
50818
|
+
decimals: 6,
|
|
50819
|
+
isRebasing: false,
|
|
50820
|
+
isMintable: true,
|
|
50821
|
+
withdrawalMode: "request-based",
|
|
50822
|
+
// `lockupPeriod()` = 432,000 s on 2026-08-25. Re-read live by the
|
|
50823
|
+
// reader; this is only the fallback if that call fails.
|
|
50824
|
+
withdrawalCooldownSeconds: 432e3,
|
|
50825
|
+
yieldFetcher: sthusdFetcher,
|
|
50826
|
+
yieldKey: STHUSD_KEY
|
|
50509
50827
|
}
|
|
50510
50828
|
],
|
|
50511
50829
|
"100": [
|
|
@@ -50731,6 +51049,70 @@ var SINGLE_CHAIN_ENTRIES = {
|
|
|
50731
51049
|
yieldKey: sparkVaultV2Key("43114", "spUSDC")
|
|
50732
51050
|
}
|
|
50733
51051
|
],
|
|
51052
|
+
// ---------------------------------------------------------------------
|
|
51053
|
+
// Stable (988) — a Tether-adjacent L1 whose whole lending surface is one
|
|
51054
|
+
// Morpho Blue deployment (`0xa40103…`), and whose largest market by an
|
|
51055
|
+
// order of magnitude is sthUSD/USDT0: $23.03M of collateral against
|
|
51056
|
+
// $18.59M supplied / $16.81M borrowed at 86 % LLTV. The earn row and that
|
|
51057
|
+
// collateral leg are the same asset, so registering it here is also what
|
|
51058
|
+
// gives the pair book a non-zero carry on the chain's biggest position.
|
|
51059
|
+
// ---------------------------------------------------------------------
|
|
51060
|
+
"988": [
|
|
51061
|
+
{
|
|
51062
|
+
// Theo **sthUSD**, bridged. This address is NOT the vault — it is the
|
|
51063
|
+
// LayerZero OFT minted against shares locked in the Ethereum OFT
|
|
51064
|
+
// Adapter at the same address, and it is a bare ERC-20 with a
|
|
51065
|
+
// blacklist and a pause: `asset()`, `totalAssets()`, `convertToAssets()`
|
|
51066
|
+
// and every `max*` view revert. See the chain-1 row for the vault,
|
|
51067
|
+
// its push-yield mechanism and its two-step exit.
|
|
51068
|
+
//
|
|
51069
|
+
// Priced by RedStone's **"RedStone Price Feed for sthUSD_FUNDAMENTAL"**
|
|
51070
|
+
// `0xb81131b6…` — the same feed Morpho's own oracle for this market
|
|
51071
|
+
// reads (`BASE_FEED_1` under a 1e28 `SCALE_FACTOR`), so the earn row
|
|
51072
|
+
// and the lending row cannot disagree about what a share is worth. It
|
|
51073
|
+
// is Chainlink-shaped and fresh, but answers in **8 decimals** (hence
|
|
51074
|
+
// `priceOracleDecimals`) and pins `roundId` at 1, i.e. NO round
|
|
51075
|
+
// history — an on-chain rate delta is impossible here, which is one
|
|
51076
|
+
// more reason `sthusdFetcher` measures the Ethereum vault instead.
|
|
51077
|
+
//
|
|
51078
|
+
// `underlying` is USDT0, the chain's dollar and this market's loan
|
|
51079
|
+
// asset: thUSD itself was never bridged to Stable, so there is no
|
|
51080
|
+
// local asset to name. Same call as Re's rows, which point at USDC.
|
|
51081
|
+
//
|
|
51082
|
+
// `isMintable: false` states a plain fact rather than a permission:
|
|
51083
|
+
// there is no mint function on an OFT and no vault on this chain, so
|
|
51084
|
+
// the only way in is to bridge from Ethereum. And it is deliberately
|
|
51085
|
+
// NOT `secondaryMarketOnly` — that flag promises a tradeable market,
|
|
51086
|
+
// and there isn't one: **23,216,009 of the 23,216,028 supply
|
|
51087
|
+
// (99.99997 %) sits inside Morpho Blue as collateral**, leaving ~19
|
|
51088
|
+
// sthUSD of free float across the whole chain. A `via: 'swap'` route
|
|
51089
|
+
// would advertise depth that does not exist.
|
|
51090
|
+
reader: "nav-oracle",
|
|
51091
|
+
// Same curated answer as the chain-1 row — one asset cannot have two
|
|
51092
|
+
// trust stories. Here it is doubly right: this side's price IS an
|
|
51093
|
+
// attestation, published by RedStone rather than derived from anything
|
|
51094
|
+
// the chain holds.
|
|
51095
|
+
solvency: "nav-attested",
|
|
51096
|
+
address: "0xd1db209087516883ec705cfeb99e80bb6032d540",
|
|
51097
|
+
underlying: "0x779ded0c9e1022225f8e0630b35a9b54be713736",
|
|
51098
|
+
// USDT0
|
|
51099
|
+
priceOracle: "0xb81131b6368b3f0a83af09db4e39ac23da96c2db",
|
|
51100
|
+
priceOracleDecimals: 8,
|
|
51101
|
+
symbol: "sthUSD",
|
|
51102
|
+
brand: "Theo",
|
|
51103
|
+
description: "Bridged sthUSD \u2014 Theo's staked gold-yield dollar, whose vault lives on Ethereum; this is the LayerZero token minted against shares locked there, priced by RedStone's sthUSD NAV feed. It holds 97 % of the supply and is the largest Morpho Blue collateral on Stable. There is no vault on this chain: entering and exiting both mean bridging to Ethereum, where redemption is a request that burns the shares at today's price and pays out 5 days later.",
|
|
51104
|
+
decimals: 6,
|
|
51105
|
+
underlyingDecimals: 6,
|
|
51106
|
+
isRebasing: false,
|
|
51107
|
+
isMintable: false,
|
|
51108
|
+
withdrawalMode: "request-based",
|
|
51109
|
+
// The Ethereum vault's `lockupPeriod`, plus a bridge hop each way that
|
|
51110
|
+
// this number does not include.
|
|
51111
|
+
withdrawalCooldownSeconds: 432e3,
|
|
51112
|
+
yieldFetcher: sthusdFetcher,
|
|
51113
|
+
yieldKey: STHUSD_KEY
|
|
51114
|
+
}
|
|
51115
|
+
],
|
|
50734
51116
|
"4663": [
|
|
50735
51117
|
{
|
|
50736
51118
|
// Spark Vaults V2 spUSDG on Robinhood Chain — the first V2 vault
|
|
@@ -50849,17 +51231,6 @@ var jitoSolFetcher = {
|
|
|
50849
51231
|
}
|
|
50850
51232
|
};
|
|
50851
51233
|
|
|
50852
|
-
// src/yields/intrinsic/fetchers/theo.ts
|
|
50853
|
-
var thBill = "Theo Short Duration US Treasury Fund::THBILL";
|
|
50854
|
-
var THBILL_DEFILLAMA_POOL = "e17dab50-85b1-45e8-b4a5-b8ae7898c4a3";
|
|
50855
|
-
var thbillFetcher = {
|
|
50856
|
-
label: "THBILL",
|
|
50857
|
-
fetch: async () => {
|
|
50858
|
-
const apy = await fetchDefiLlamaApy(THBILL_DEFILLAMA_POOL);
|
|
50859
|
-
return { [thBill]: apyToAprPercent(apy) };
|
|
50860
|
-
}
|
|
50861
|
-
};
|
|
50862
|
-
|
|
50863
51234
|
// src/yields/intrinsic/fetchers/superreturn.ts
|
|
50864
51235
|
var SSUPERUSD_URL = "https://www.superreturn.ai/api/trpc/cmc.getUSDCPrice,rewardBackend.getYield,rewardBackend.getTvlChange?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%2C%221%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%2C%222%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%7D";
|
|
50865
51236
|
var ssuperusd = "SuperReturn sSuperUSD::SSUPERUSD";
|
|
@@ -51574,25 +51945,14 @@ var lsethFetcher = {
|
|
|
51574
51945
|
}
|
|
51575
51946
|
};
|
|
51576
51947
|
|
|
51577
|
-
// src/yields/intrinsic/fetchers/treehouse.ts
|
|
51578
|
-
var TETH_POOL_ID = "5762f4a8-bb48-45d6-90ed-2d93d1777169";
|
|
51579
|
-
var KEYS2 = ["Treehouse ETH::tETH"];
|
|
51580
|
-
var tethFetcher = {
|
|
51581
|
-
label: "TETH",
|
|
51582
|
-
fetch: async () => {
|
|
51583
|
-
const apr = apyToAprPercent(await fetchDefiLlamaApy(TETH_POOL_ID));
|
|
51584
|
-
return Object.fromEntries(KEYS2.map((k) => [k, apr]));
|
|
51585
|
-
}
|
|
51586
|
-
};
|
|
51587
|
-
|
|
51588
51948
|
// src/yields/intrinsic/fetchers/anzen.ts
|
|
51589
51949
|
var SUSDZ_POOL_ID = "46518e93-8197-4539-9861-2340c2ac965a";
|
|
51590
|
-
var
|
|
51950
|
+
var KEYS2 = ["Anzen Staked USDz::SUSDZ", "Anzen Staked USDz::sUSDz", "Staked USDz::sUSDz"];
|
|
51591
51951
|
var susdzFetcher = {
|
|
51592
51952
|
label: "SUSDZ",
|
|
51593
51953
|
fetch: async () => {
|
|
51594
51954
|
const apr = apyToAprPercent(await fetchDefiLlamaApy(SUSDZ_POOL_ID));
|
|
51595
|
-
return Object.fromEntries(
|
|
51955
|
+
return Object.fromEntries(KEYS2.map((k) => [k, apr]));
|
|
51596
51956
|
}
|
|
51597
51957
|
};
|
|
51598
51958
|
|
|
@@ -51605,6 +51965,7 @@ var LENDING_ONLY_FETCHERS = [
|
|
|
51605
51965
|
ethZeroFetcher,
|
|
51606
51966
|
jitoSolFetcher,
|
|
51607
51967
|
thbillFetcher,
|
|
51968
|
+
sthusdFetcher,
|
|
51608
51969
|
ssuperusdFetcher,
|
|
51609
51970
|
hlpFetcher,
|
|
51610
51971
|
hwhlpFetcher,
|
|
@@ -51619,7 +51980,10 @@ var LENDING_ONLY_FETCHERS = [
|
|
|
51619
51980
|
// it reaches the global map via `collectVaultFetchers` (disjointness rule).
|
|
51620
51981
|
syzusdFetcher,
|
|
51621
51982
|
midasFetcher,
|
|
51622
|
-
capFetcher,
|
|
51983
|
+
// capFetcher is NOT here: the Cap stcUSD savings row vault-wires it, so it
|
|
51984
|
+
// reaches the global map via `collectVaultFetchers` (disjointness rule).
|
|
51985
|
+
// It was double-listed, which the registry test flags — the union dedupes
|
|
51986
|
+
// by reference, so removing it here changes nothing at runtime.
|
|
51623
51987
|
nestFetcher,
|
|
51624
51988
|
accountableFetcher,
|
|
51625
51989
|
upshiftFetcher,
|
|
@@ -51628,7 +51992,9 @@ var LENDING_ONLY_FETCHERS = [
|
|
|
51628
51992
|
yearnFetcher,
|
|
51629
51993
|
// DefiLlama-mapped intrinsic yields for classifier assets lacking a bespoke source
|
|
51630
51994
|
lsethFetcher,
|
|
51631
|
-
tethFetcher
|
|
51995
|
+
// tethFetcher / tavaxFetcher are NOT here: the Treehouse tAsset LST rows
|
|
51996
|
+
// vault-wire them, so they reach the global map via `collectVaultFetchers`
|
|
51997
|
+
// (disjointness rule).
|
|
51632
51998
|
// strataFetcher is NOT here: the Strata tranche savings rows vault-wire
|
|
51633
51999
|
// it, so it reaches the global map via `collectVaultFetchers`.
|
|
51634
52000
|
susdzFetcher
|
|
@@ -53455,9 +53821,9 @@ function getTermCalls(chainId) {
|
|
|
53455
53821
|
}
|
|
53456
53822
|
}
|
|
53457
53823
|
const results = [];
|
|
53458
|
-
for (const [token, { amount:
|
|
53824
|
+
for (const [token, { amount: amount4, repoKeys }] of byToken) {
|
|
53459
53825
|
const calls = [
|
|
53460
|
-
{ address: oracle, name: "usdValueOfTokens", params: [token,
|
|
53826
|
+
{ address: oracle, name: "usdValueOfTokens", params: [token, amount4] }
|
|
53461
53827
|
];
|
|
53462
53828
|
results.push({
|
|
53463
53829
|
calls,
|
|
@@ -61668,6 +62034,165 @@ var readerKintsuSMon = (entry) => ({
|
|
|
61668
62034
|
}
|
|
61669
62035
|
});
|
|
61670
62036
|
|
|
62037
|
+
// src/vaults/lst/abis/treehouse.ts
|
|
62038
|
+
var TreehouseFastlaneAbi = [
|
|
62039
|
+
{
|
|
62040
|
+
name: "getRedeemableAmount",
|
|
62041
|
+
type: "function",
|
|
62042
|
+
stateMutability: "view",
|
|
62043
|
+
inputs: [],
|
|
62044
|
+
outputs: [{ type: "uint256" }]
|
|
62045
|
+
},
|
|
62046
|
+
{
|
|
62047
|
+
// Delegates to a swappable fee contract, so it is a live read even
|
|
62048
|
+
// though the Fastlane itself is behind the timelock.
|
|
62049
|
+
name: "redemptionFee",
|
|
62050
|
+
type: "function",
|
|
62051
|
+
stateMutability: "view",
|
|
62052
|
+
inputs: [],
|
|
62053
|
+
outputs: [{ type: "uint256" }]
|
|
62054
|
+
},
|
|
62055
|
+
{
|
|
62056
|
+
name: "minRedeemInUnderlying",
|
|
62057
|
+
type: "function",
|
|
62058
|
+
stateMutability: "view",
|
|
62059
|
+
inputs: [],
|
|
62060
|
+
outputs: [{ type: "uint96" }]
|
|
62061
|
+
}
|
|
62062
|
+
];
|
|
62063
|
+
var TreehouseRedemptionAbi = [
|
|
62064
|
+
{
|
|
62065
|
+
name: "waitingPeriod",
|
|
62066
|
+
type: "function",
|
|
62067
|
+
stateMutability: "view",
|
|
62068
|
+
inputs: [],
|
|
62069
|
+
outputs: [{ type: "uint32" }]
|
|
62070
|
+
},
|
|
62071
|
+
{
|
|
62072
|
+
// The QUEUED leg charges too (5 bps). That contradicts the convention
|
|
62073
|
+
// `SavingsVault.withdrawFeeBps` documents — "the queued leg pays at par"
|
|
62074
|
+
// — which is exactly why the route list carries a fee PER LEG instead of
|
|
62075
|
+
// one field plus an assumption.
|
|
62076
|
+
name: "redemptionFee",
|
|
62077
|
+
type: "function",
|
|
62078
|
+
stateMutability: "view",
|
|
62079
|
+
inputs: [],
|
|
62080
|
+
outputs: [{ type: "uint32" }]
|
|
62081
|
+
},
|
|
62082
|
+
{
|
|
62083
|
+
// The gate that decides whether the cheap leg exists for a given holder:
|
|
62084
|
+
// 50 wstETH / 4,000 sAVAX / 1,000 kHYPE, checked against
|
|
62085
|
+
// `previewRedeem(shares)`, i.e. in UNDERLYING units.
|
|
62086
|
+
name: "minRedeemInUnderlying",
|
|
62087
|
+
type: "function",
|
|
62088
|
+
stateMutability: "view",
|
|
62089
|
+
inputs: [],
|
|
62090
|
+
outputs: [{ type: "uint96" }]
|
|
62091
|
+
}
|
|
62092
|
+
];
|
|
62093
|
+
|
|
62094
|
+
// src/vaults/lst/readers/treehouse.ts
|
|
62095
|
+
var asBps = (v) => v === void 0 ? void 0 : Number(v);
|
|
62096
|
+
var fmt = (raw, decimals) => raw === void 0 ? void 0 : Number(raw) / 10 ** decimals;
|
|
62097
|
+
var readerTreehouseTAsset = (entry) => {
|
|
62098
|
+
const fastlane = entry.readerExtras?.treehouseFastlane;
|
|
62099
|
+
const redemption = entry.readerExtras?.treehouseRedemption;
|
|
62100
|
+
const fl = fastlane ?? entry.address;
|
|
62101
|
+
const rd = redemption ?? entry.address;
|
|
62102
|
+
const underlyingDec = entry.underlyingDecimals ?? entry.decimals;
|
|
62103
|
+
return {
|
|
62104
|
+
calls: [
|
|
62105
|
+
{ address: entry.address, name: "totalAssets", params: [] },
|
|
62106
|
+
{ address: entry.address, name: "totalSupply", params: [] },
|
|
62107
|
+
{ address: entry.address, name: "convertToAssets", params: [ONE_E1811] },
|
|
62108
|
+
{ address: fl, name: "getRedeemableAmount", params: [] },
|
|
62109
|
+
{ address: fl, name: "redemptionFee", params: [] },
|
|
62110
|
+
{ address: fl, name: "minRedeemInUnderlying", params: [] },
|
|
62111
|
+
{ address: rd, name: "waitingPeriod", params: [] },
|
|
62112
|
+
{ address: rd, name: "redemptionFee", params: [] },
|
|
62113
|
+
{ address: rd, name: "minRedeemInUnderlying", params: [] }
|
|
62114
|
+
],
|
|
62115
|
+
abis: [
|
|
62116
|
+
Erc4626ReadAbi,
|
|
62117
|
+
TotalSupplyAbi,
|
|
62118
|
+
Erc4626ReadAbi,
|
|
62119
|
+
TreehouseFastlaneAbi,
|
|
62120
|
+
TreehouseFastlaneAbi,
|
|
62121
|
+
TreehouseFastlaneAbi,
|
|
62122
|
+
TreehouseRedemptionAbi,
|
|
62123
|
+
TreehouseRedemptionAbi,
|
|
62124
|
+
TreehouseRedemptionAbi
|
|
62125
|
+
],
|
|
62126
|
+
parse: (slice2) => {
|
|
62127
|
+
const [
|
|
62128
|
+
assets,
|
|
62129
|
+
supply,
|
|
62130
|
+
rate,
|
|
62131
|
+
redeemable,
|
|
62132
|
+
fastFee,
|
|
62133
|
+
fastMin,
|
|
62134
|
+
waiting,
|
|
62135
|
+
queueFee,
|
|
62136
|
+
queueMin
|
|
62137
|
+
] = slice2;
|
|
62138
|
+
const totalAssets = toBigInt13(assets);
|
|
62139
|
+
const totalSupply = toBigInt13(supply);
|
|
62140
|
+
const exchangeRate = toBigInt13(rate);
|
|
62141
|
+
if (totalAssets === void 0 || totalSupply === void 0 || exchangeRate === void 0) {
|
|
62142
|
+
return void 0;
|
|
62143
|
+
}
|
|
62144
|
+
const liquidity = toBigInt13(redeemable) ?? 0n;
|
|
62145
|
+
const wait = toBigInt13(waiting);
|
|
62146
|
+
const instantFeeBps = asBps(toBigInt13(fastFee));
|
|
62147
|
+
const queuedFeeBps = asBps(toBigInt13(queueFee));
|
|
62148
|
+
const instantMin = toBigInt13(fastMin);
|
|
62149
|
+
const queuedMin = toBigInt13(queueMin);
|
|
62150
|
+
const instant = {
|
|
62151
|
+
id: "instant",
|
|
62152
|
+
kind: "instant",
|
|
62153
|
+
label: "Fast redemption",
|
|
62154
|
+
settlement: "sync",
|
|
62155
|
+
feeBps: instantFeeBps,
|
|
62156
|
+
waitSeconds: 0,
|
|
62157
|
+
// `0` is the live value on all three chains and means "no floor" —
|
|
62158
|
+
// emitted rather than dropped, because on this protocol the ABSENCE
|
|
62159
|
+
// of a minimum on the expensive leg is the reason it is the only exit
|
|
62160
|
+
// most holders have.
|
|
62161
|
+
minAmount: instantMin?.toString(),
|
|
62162
|
+
minAmountFormatted: fmt(instantMin, underlyingDec),
|
|
62163
|
+
capacity: liquidity.toString(),
|
|
62164
|
+
capacityFormatted: Number(liquidity) / 10 ** underlyingDec,
|
|
62165
|
+
selfOnly: true,
|
|
62166
|
+
description: "Burns the tAsset and pays the underlying in the same transaction, out of the vault balance not already earmarked by queued requests. Bounded by that balance \u2014 a larger redemption reverts rather than partially filling."
|
|
62167
|
+
};
|
|
62168
|
+
const queued = {
|
|
62169
|
+
id: "queued",
|
|
62170
|
+
kind: "queued",
|
|
62171
|
+
label: wait !== void 0 ? `${Math.round(Number(wait) / 86400)}-day queue` : "Queued redemption",
|
|
62172
|
+
settlement: "async",
|
|
62173
|
+
feeBps: queuedFeeBps,
|
|
62174
|
+
waitSeconds: wait !== void 0 ? Number(wait) : void 0,
|
|
62175
|
+
minAmount: queuedMin?.toString(),
|
|
62176
|
+
minAmountFormatted: fmt(queuedMin, underlyingDec),
|
|
62177
|
+
selfOnly: true,
|
|
62178
|
+
description: "Escrows the shares now and pays after the wait. Far cheaper, but it enforces a minimum size, and it settles at the WORSE of the rate at request and at claim \u2014 so the amount quoted when you file it is a ceiling, not a quote."
|
|
62179
|
+
};
|
|
62180
|
+
return {
|
|
62181
|
+
totalAssets,
|
|
62182
|
+
totalSupply,
|
|
62183
|
+
exchangeRate,
|
|
62184
|
+
liquidity,
|
|
62185
|
+
withdrawalCooldownSeconds: wait !== void 0 ? Number(wait) : void 0,
|
|
62186
|
+
withdrawFeeBps: instantFeeBps,
|
|
62187
|
+
// Cheapest reachable leg first is the list's ordering rule, and here
|
|
62188
|
+
// the cheap one is second on purpose: it is gated by a minimum that
|
|
62189
|
+
// most holders do not clear, so the leg anyone can take leads.
|
|
62190
|
+
exitRoutes: [instant, queued]
|
|
62191
|
+
};
|
|
62192
|
+
}
|
|
62193
|
+
};
|
|
62194
|
+
};
|
|
62195
|
+
|
|
61671
62196
|
// src/vaults/lst/readers/index.ts
|
|
61672
62197
|
var buildReader = (entry) => {
|
|
61673
62198
|
switch (entry.reader) {
|
|
@@ -61729,6 +62254,8 @@ var buildReader = (entry) => {
|
|
|
61729
62254
|
return readerCoreStakedRatio(entry);
|
|
61730
62255
|
case "kintsuSMon":
|
|
61731
62256
|
return readerKintsuSMon(entry);
|
|
62257
|
+
case "treehouseTAsset":
|
|
62258
|
+
return readerTreehouseTAsset(entry);
|
|
61732
62259
|
}
|
|
61733
62260
|
};
|
|
61734
62261
|
|
|
@@ -62098,6 +62625,98 @@ var getLstValidators = async (chainId, shareToken) => {
|
|
|
62098
62625
|
return [];
|
|
62099
62626
|
};
|
|
62100
62627
|
|
|
62628
|
+
// src/vaults/exitRoutes.ts
|
|
62629
|
+
var asyncLabel = (secs) => {
|
|
62630
|
+
if (!secs || secs <= 0) return "Queued";
|
|
62631
|
+
const d = secs / 86400;
|
|
62632
|
+
if (d >= 1) return `${Number.isInteger(d) ? d : d.toFixed(1)}-day queue`;
|
|
62633
|
+
const h = secs / 3600;
|
|
62634
|
+
return h >= 1 ? `${Number.isInteger(h) ? h : h.toFixed(1)}-hour queue` : `${Math.round(secs / 60)}-minute queue`;
|
|
62635
|
+
};
|
|
62636
|
+
var instantRoute = (i, feeBps) => ({
|
|
62637
|
+
id: "instant",
|
|
62638
|
+
kind: "instant",
|
|
62639
|
+
label: feeBps ? "Instant (fee)" : "Instant",
|
|
62640
|
+
settlement: "sync",
|
|
62641
|
+
feeBps,
|
|
62642
|
+
waitSeconds: 0,
|
|
62643
|
+
capacity: i.liquidity,
|
|
62644
|
+
capacityFormatted: i.liquidityFormatted,
|
|
62645
|
+
capacityUsd: i.liquidityUsd
|
|
62646
|
+
});
|
|
62647
|
+
var queuedRoute = (i) => ({
|
|
62648
|
+
id: "queued",
|
|
62649
|
+
kind: "queued",
|
|
62650
|
+
label: asyncLabel(i.withdrawalCooldownSeconds),
|
|
62651
|
+
settlement: "async",
|
|
62652
|
+
waitSeconds: i.withdrawalCooldownSeconds
|
|
62653
|
+
});
|
|
62654
|
+
var deriveExitRoutes = (i) => {
|
|
62655
|
+
switch (i.withdrawalMode) {
|
|
62656
|
+
// The instant leg pays the fee; the queue pays at par. That is the
|
|
62657
|
+
// convention `SavingsVault.withdrawFeeBps` already documents — and
|
|
62658
|
+
// Treehouse is the counter-example, which is why its reader overrides
|
|
62659
|
+
// this rather than being described by it.
|
|
62660
|
+
case "fee-or-queued":
|
|
62661
|
+
return [
|
|
62662
|
+
{
|
|
62663
|
+
...instantRoute(i, i.withdrawFeeBps),
|
|
62664
|
+
// The mode's whole meaning is that THIS leg costs something. Say so
|
|
62665
|
+
// even when the size is unknown: an absent `feeBps` renders as
|
|
62666
|
+
// "leave instantly", which reads as free — the same failure the
|
|
62667
|
+
// term-sheet rules call out for `fees: []`.
|
|
62668
|
+
...i.withdrawFeeBps == null ? { feeUnknown: true, label: "Instant (fee)" } : {}
|
|
62669
|
+
},
|
|
62670
|
+
{ ...queuedRoute(i), feeBps: 0 }
|
|
62671
|
+
];
|
|
62672
|
+
// Same split with no fee on either leg — the instant leg is bounded by
|
|
62673
|
+
// inventory instead.
|
|
62674
|
+
case "instant-or-queued":
|
|
62675
|
+
return [instantRoute(i, i.withdrawFeeBps ?? 0), queuedRoute(i)];
|
|
62676
|
+
case "instant":
|
|
62677
|
+
return [
|
|
62678
|
+
{
|
|
62679
|
+
id: "instant",
|
|
62680
|
+
kind: "instant",
|
|
62681
|
+
label: "Instant",
|
|
62682
|
+
settlement: "sync",
|
|
62683
|
+
feeBps: i.withdrawFeeBps ?? 0,
|
|
62684
|
+
waitSeconds: 0
|
|
62685
|
+
}
|
|
62686
|
+
];
|
|
62687
|
+
case "instant-capped":
|
|
62688
|
+
return [instantRoute(i, i.withdrawFeeBps ?? 0)];
|
|
62689
|
+
case "fixed-cooldown":
|
|
62690
|
+
case "queued":
|
|
62691
|
+
case "request-based":
|
|
62692
|
+
return [{ ...queuedRoute(i), feeBps: i.withdrawFeeBps }];
|
|
62693
|
+
case "off-chain":
|
|
62694
|
+
return [
|
|
62695
|
+
{
|
|
62696
|
+
id: "off-chain",
|
|
62697
|
+
kind: "queued",
|
|
62698
|
+
label: "Off-chain redemption",
|
|
62699
|
+
settlement: "async",
|
|
62700
|
+
waitSeconds: i.withdrawalCooldownSeconds,
|
|
62701
|
+
description: "Redemption is handled by the issuer off-chain; there is no on-chain exit to call."
|
|
62702
|
+
}
|
|
62703
|
+
];
|
|
62704
|
+
case "dex-only":
|
|
62705
|
+
case "market-sale":
|
|
62706
|
+
return [
|
|
62707
|
+
{
|
|
62708
|
+
id: "market",
|
|
62709
|
+
kind: "market",
|
|
62710
|
+
label: "Sell on the market",
|
|
62711
|
+
settlement: "market",
|
|
62712
|
+
description: "There is no redemption \u2014 you leave by selling the token, at whatever price is bid and with price impact that grows with size."
|
|
62713
|
+
}
|
|
62714
|
+
];
|
|
62715
|
+
default:
|
|
62716
|
+
return [];
|
|
62717
|
+
}
|
|
62718
|
+
};
|
|
62719
|
+
|
|
62101
62720
|
// src/vaults/lst/fetchPublic.ts
|
|
62102
62721
|
var ONE_E1812 = 10n ** 18n;
|
|
62103
62722
|
var ERC20_BALANCE_ABI = parseAbi([
|
|
@@ -62225,6 +62844,7 @@ var fetchLstShareTokens = async (chainId, multicallRetry, prices = {}, tokenList
|
|
|
62225
62844
|
}
|
|
62226
62845
|
const liquidityFormatted = Number(liquidityRaw) / 10 ** underlyingDec;
|
|
62227
62846
|
const liquidityUsd = priceUsd !== void 0 ? liquidityFormatted * priceUsd : 0;
|
|
62847
|
+
const cooldownSecs = state.withdrawalCooldownSeconds ?? entry.withdrawalCooldownSeconds;
|
|
62228
62848
|
const displayName = composeVaultDisplayName(
|
|
62229
62849
|
entry.brand,
|
|
62230
62850
|
entry.brand,
|
|
@@ -62262,7 +62882,22 @@ var fetchLstShareTokens = async (chainId, multicallRetry, prices = {}, tokenList
|
|
|
62262
62882
|
delegation: delegationByAddress.get(addressLc),
|
|
62263
62883
|
validators: validatorsByAddress.get(addressLc),
|
|
62264
62884
|
withdrawalMode: entry.withdrawalMode,
|
|
62265
|
-
|
|
62885
|
+
// A reader-measured wait wins over the registry's static one — see
|
|
62886
|
+
// `LstOnChainState.withdrawalCooldownSeconds`.
|
|
62887
|
+
withdrawalCooldownSeconds: cooldownSecs,
|
|
62888
|
+
withdrawFeeBps: state.withdrawFeeBps,
|
|
62889
|
+
// A reader that reads its protocol's own per-leg dials publishes the
|
|
62890
|
+
// list itself; everything else gets the coarse derivation, which is
|
|
62891
|
+
// still strictly better than making every consumer reassemble the two
|
|
62892
|
+
// legs out of `withdrawalMode` + one cooldown + one liquidity number.
|
|
62893
|
+
exitRoutes: state.exitRoutes ?? deriveExitRoutes({
|
|
62894
|
+
withdrawalMode: entry.withdrawalMode,
|
|
62895
|
+
withdrawFeeBps: state.withdrawFeeBps,
|
|
62896
|
+
withdrawalCooldownSeconds: cooldownSecs,
|
|
62897
|
+
liquidity: liquidityRaw.toString(),
|
|
62898
|
+
liquidityFormatted,
|
|
62899
|
+
liquidityUsd
|
|
62900
|
+
}),
|
|
62266
62901
|
asset,
|
|
62267
62902
|
priceUsd,
|
|
62268
62903
|
totalAssetsFormatted,
|
|
@@ -62364,17 +62999,17 @@ var readerBeets = {
|
|
|
62364
62999
|
const out = [];
|
|
62365
63000
|
for (let i = 0; i < reqs.length; i++) {
|
|
62366
63001
|
const r = reqs[i];
|
|
62367
|
-
const
|
|
63002
|
+
const amount4 = toBigInt14(r.assetAmount);
|
|
62368
63003
|
const ts = toNumber(r.requestTimestamp);
|
|
62369
63004
|
const isWithdrawn = Boolean(r.isWithdrawn);
|
|
62370
|
-
if (
|
|
63005
|
+
if (amount4 === void 0 || ts === void 0) continue;
|
|
62371
63006
|
const readyAt = ts + delay;
|
|
62372
63007
|
out.push({
|
|
62373
63008
|
lst: entry.lst,
|
|
62374
63009
|
brand: entry.brand,
|
|
62375
63010
|
symbol: entry.symbol,
|
|
62376
63011
|
requestId: String(i),
|
|
62377
|
-
amountUnderlying:
|
|
63012
|
+
amountUnderlying: amount4.toString(),
|
|
62378
63013
|
status: isWithdrawn ? "claimed" : computeStatus(readyAt),
|
|
62379
63014
|
readyAt: isWithdrawn ? void 0 : readyAt
|
|
62380
63015
|
});
|
|
@@ -62825,8 +63460,8 @@ var readerIbera = {
|
|
|
62825
63460
|
const r = stage2[k];
|
|
62826
63461
|
if (!r) continue;
|
|
62827
63462
|
const receiver = Array.isArray(r) ? r[2] : r.receiver;
|
|
62828
|
-
const
|
|
62829
|
-
if (typeof receiver !== "string" || receiver.toLowerCase() !== target ||
|
|
63463
|
+
const amount4 = Array.isArray(r) ? toBigInt14(r[3]) : toBigInt14(r.amount);
|
|
63464
|
+
if (typeof receiver !== "string" || receiver.toLowerCase() !== target || amount4 === void 0 || amount4 === 0n) {
|
|
62830
63465
|
continue;
|
|
62831
63466
|
}
|
|
62832
63467
|
const id = BigInt(ids[k]);
|
|
@@ -62835,7 +63470,7 @@ var readerIbera = {
|
|
|
62835
63470
|
brand: entry.brand,
|
|
62836
63471
|
symbol: entry.symbol,
|
|
62837
63472
|
requestId: String(ids[k]),
|
|
62838
|
-
amountUnderlying:
|
|
63473
|
+
amountUnderlying: amount4.toString(),
|
|
62839
63474
|
status: id < frontier ? "claimable" : "pending"
|
|
62840
63475
|
});
|
|
62841
63476
|
}
|
|
@@ -63008,13 +63643,13 @@ var readerErc7540 = {
|
|
|
63008
63643
|
],
|
|
63009
63644
|
abi: [Erc7540Abi]
|
|
63010
63645
|
});
|
|
63011
|
-
const
|
|
63646
|
+
const amount4 = toBigInt14(stage2[0]) ?? claimable;
|
|
63012
63647
|
out.push({
|
|
63013
63648
|
lst: entry.lst,
|
|
63014
63649
|
brand: entry.brand,
|
|
63015
63650
|
symbol: entry.symbol,
|
|
63016
63651
|
requestId: "0",
|
|
63017
|
-
amountUnderlying:
|
|
63652
|
+
amountUnderlying: amount4.toString(),
|
|
63018
63653
|
// The 7540 claim (`redeem`) takes the share amount.
|
|
63019
63654
|
shares: claimable.toString(),
|
|
63020
63655
|
status: "claimable"
|
|
@@ -63063,15 +63698,15 @@ var readerEthenaCooldown = {
|
|
|
63063
63698
|
});
|
|
63064
63699
|
const cell = res[0];
|
|
63065
63700
|
let cooldownEnd;
|
|
63066
|
-
let
|
|
63701
|
+
let amount4;
|
|
63067
63702
|
if (Array.isArray(cell)) {
|
|
63068
63703
|
cooldownEnd = toBigInt14(cell[0]);
|
|
63069
|
-
|
|
63704
|
+
amount4 = toBigInt14(cell[1]);
|
|
63070
63705
|
} else if (cell && typeof cell === "object") {
|
|
63071
63706
|
cooldownEnd = toBigInt14(cell.cooldownEnd);
|
|
63072
|
-
|
|
63707
|
+
amount4 = toBigInt14(cell.underlyingAmount);
|
|
63073
63708
|
}
|
|
63074
|
-
if (!
|
|
63709
|
+
if (!amount4 || amount4 === 0n) return [];
|
|
63075
63710
|
const readyAt = Number(cooldownEnd ?? 0n);
|
|
63076
63711
|
const out = [
|
|
63077
63712
|
{
|
|
@@ -63079,7 +63714,7 @@ var readerEthenaCooldown = {
|
|
|
63079
63714
|
brand: entry.brand,
|
|
63080
63715
|
symbol: entry.symbol,
|
|
63081
63716
|
requestId: "0",
|
|
63082
|
-
amountUnderlying:
|
|
63717
|
+
amountUnderlying: amount4.toString(),
|
|
63083
63718
|
status: computeStatus(readyAt),
|
|
63084
63719
|
readyAt
|
|
63085
63720
|
}
|
|
@@ -63134,7 +63769,7 @@ var readerSusd3Cooldown = {
|
|
|
63134
63769
|
shares = toBigInt14(cell.shares);
|
|
63135
63770
|
}
|
|
63136
63771
|
if (!shares || shares === 0n) return [];
|
|
63137
|
-
let
|
|
63772
|
+
let amount4 = shares;
|
|
63138
63773
|
try {
|
|
63139
63774
|
const stage2 = await multicallRetry({
|
|
63140
63775
|
chain: chainId,
|
|
@@ -63143,7 +63778,7 @@ var readerSusd3Cooldown = {
|
|
|
63143
63778
|
],
|
|
63144
63779
|
abi: [Susd3CooldownStatusAbi]
|
|
63145
63780
|
});
|
|
63146
|
-
|
|
63781
|
+
amount4 = toBigInt14(stage2[0]) ?? shares;
|
|
63147
63782
|
} catch {
|
|
63148
63783
|
}
|
|
63149
63784
|
const readyAt = Number(cooldownEnd ?? 0n);
|
|
@@ -63154,7 +63789,7 @@ var readerSusd3Cooldown = {
|
|
|
63154
63789
|
brand: entry.brand,
|
|
63155
63790
|
symbol: entry.symbol,
|
|
63156
63791
|
requestId: "0",
|
|
63157
|
-
amountUnderlying:
|
|
63792
|
+
amountUnderlying: amount4.toString(),
|
|
63158
63793
|
shares: shares.toString(),
|
|
63159
63794
|
status: computeStatus(readyAt, expiresAt),
|
|
63160
63795
|
readyAt,
|
|
@@ -63350,14 +63985,14 @@ var readerEtherFi = {
|
|
|
63350
63985
|
const isValid = Boolean(stage3[i * 3 + 2]);
|
|
63351
63986
|
if (!req) continue;
|
|
63352
63987
|
if (!isValid) continue;
|
|
63353
|
-
const
|
|
63354
|
-
if (
|
|
63988
|
+
const amount4 = toBigInt14(req.amountOfEEth);
|
|
63989
|
+
if (amount4 === void 0) continue;
|
|
63355
63990
|
out.push({
|
|
63356
63991
|
lst: entry.lst,
|
|
63357
63992
|
brand: entry.brand,
|
|
63358
63993
|
symbol: entry.symbol,
|
|
63359
63994
|
requestId: id.toString(),
|
|
63360
|
-
amountUnderlying:
|
|
63995
|
+
amountUnderlying: amount4.toString(),
|
|
63361
63996
|
status: isFinalized ? "claimable" : "pending"
|
|
63362
63997
|
});
|
|
63363
63998
|
}
|
|
@@ -63687,15 +64322,15 @@ var readerLista = {
|
|
|
63687
64322
|
const isClaimable = Array.isArray(status) ? Boolean(status[0]) : Boolean(status._isClaimable);
|
|
63688
64323
|
const bnbAmount = Array.isArray(status) ? toBigInt14(status[1]) : toBigInt14(status._amount);
|
|
63689
64324
|
const snbnbAmount = Array.isArray(req) ? toBigInt14(req[1]) : toBigInt14(req?.amountInSnBnb);
|
|
63690
|
-
const
|
|
63691
|
-
if (
|
|
64325
|
+
const amount4 = bnbAmount ?? snbnbAmount;
|
|
64326
|
+
if (amount4 === void 0) continue;
|
|
63692
64327
|
const uuid = Array.isArray(req) ? toBigInt14(req[0]) : toBigInt14(req?.uuid);
|
|
63693
64328
|
out.push({
|
|
63694
64329
|
lst: entry.lst,
|
|
63695
64330
|
brand: entry.brand,
|
|
63696
64331
|
symbol: entry.symbol,
|
|
63697
64332
|
requestId: String(uuid ?? i),
|
|
63698
|
-
amountUnderlying:
|
|
64333
|
+
amountUnderlying: amount4.toString(),
|
|
63699
64334
|
status: isClaimable ? "claimable" : "pending"
|
|
63700
64335
|
});
|
|
63701
64336
|
}
|
|
@@ -63950,7 +64585,7 @@ var readerStaderMaticX2 = {
|
|
|
63950
64585
|
const out = [];
|
|
63951
64586
|
for (let i = 0; i < arr.length; i++) {
|
|
63952
64587
|
const r = arr[i];
|
|
63953
|
-
const
|
|
64588
|
+
const amount4 = toBigInt14(r.amount) ?? 0n;
|
|
63954
64589
|
const requestEpoch = toBigInt14(r.requestEpoch);
|
|
63955
64590
|
if (requestEpoch === void 0) continue;
|
|
63956
64591
|
const ready = stakeManager ? currentEpoch >= requestEpoch + delay : false;
|
|
@@ -63961,7 +64596,7 @@ var readerStaderMaticX2 = {
|
|
|
63961
64596
|
// Use array index as the request id (consistent with
|
|
63962
64597
|
// `claimWithdrawal(uint256 _idx)`).
|
|
63963
64598
|
requestId: String(i),
|
|
63964
|
-
amountUnderlying:
|
|
64599
|
+
amountUnderlying: amount4.toString(),
|
|
63965
64600
|
status: ready ? "claimable" : "pending"
|
|
63966
64601
|
});
|
|
63967
64602
|
}
|
|
@@ -64362,7 +64997,7 @@ var readerStakeWise = {
|
|
|
64362
64997
|
const out = [];
|
|
64363
64998
|
for (let i = 0; i < requests.length; i++) {
|
|
64364
64999
|
const r = requests[i];
|
|
64365
|
-
const
|
|
65000
|
+
const amount4 = toBigInt14(r.totalAssets) ?? 0n;
|
|
64366
65001
|
const onChainClaimed = claimedByIdx.get(i);
|
|
64367
65002
|
const claimable = onChainClaimed !== void 0 || r.isClaimable;
|
|
64368
65003
|
out.push({
|
|
@@ -64370,7 +65005,7 @@ var readerStakeWise = {
|
|
|
64370
65005
|
brand: entry.brand,
|
|
64371
65006
|
symbol: entry.symbol,
|
|
64372
65007
|
requestId: r.positionTicket,
|
|
64373
|
-
amountUnderlying: (onChainClaimed ??
|
|
65008
|
+
amountUnderlying: (onChainClaimed ?? amount4).toString(),
|
|
64374
65009
|
status: claimable ? "claimable" : "pending"
|
|
64375
65010
|
});
|
|
64376
65011
|
}
|
|
@@ -64419,15 +65054,15 @@ var readerStCelo2 = {
|
|
|
64419
65054
|
const timestamps = cell[1] ?? [];
|
|
64420
65055
|
const out = [];
|
|
64421
65056
|
for (let i = 0; i < values.length; i++) {
|
|
64422
|
-
const
|
|
65057
|
+
const amount4 = toBigInt14(values[i]);
|
|
64423
65058
|
const readyAt = toNumber(timestamps[i]);
|
|
64424
|
-
if (
|
|
65059
|
+
if (amount4 === void 0 || readyAt === void 0) continue;
|
|
64425
65060
|
out.push({
|
|
64426
65061
|
lst: entry.lst,
|
|
64427
65062
|
brand: entry.brand,
|
|
64428
65063
|
symbol: entry.symbol,
|
|
64429
65064
|
requestId: String(i),
|
|
64430
|
-
amountUnderlying:
|
|
65065
|
+
amountUnderlying: amount4.toString(),
|
|
64431
65066
|
status: computeStatus(readyAt),
|
|
64432
65067
|
readyAt
|
|
64433
65068
|
});
|
|
@@ -64528,15 +65163,15 @@ var readerSwell = {
|
|
|
64528
65163
|
const id = ids[i];
|
|
64529
65164
|
const r = stage3[i];
|
|
64530
65165
|
if (!r) continue;
|
|
64531
|
-
const
|
|
64532
|
-
if (
|
|
65166
|
+
const amount4 = toBigInt14(r.amount);
|
|
65167
|
+
if (amount4 === void 0) continue;
|
|
64533
65168
|
const claimable = id <= lastProcessed;
|
|
64534
65169
|
out.push({
|
|
64535
65170
|
lst: entry.lst,
|
|
64536
65171
|
brand: entry.brand,
|
|
64537
65172
|
symbol: entry.symbol,
|
|
64538
65173
|
requestId: id.toString(),
|
|
64539
|
-
amountUnderlying:
|
|
65174
|
+
amountUnderlying: amount4.toString(),
|
|
64540
65175
|
status: claimable ? "claimable" : "pending"
|
|
64541
65176
|
});
|
|
64542
65177
|
}
|
|
@@ -64602,15 +65237,15 @@ var readerValantis = {
|
|
|
64602
65237
|
for (let i = 0; i < burns.length; i++) {
|
|
64603
65238
|
const b = burns[i];
|
|
64604
65239
|
if (!b) continue;
|
|
64605
|
-
const
|
|
65240
|
+
const amount4 = Array.isArray(b) ? toBigInt14(b[0]) : toBigInt14(b.amount);
|
|
64606
65241
|
const completed = Array.isArray(b) ? Boolean(b[2]) : Boolean(b.completed);
|
|
64607
|
-
if (
|
|
65242
|
+
if (amount4 === void 0 || completed) continue;
|
|
64608
65243
|
out.push({
|
|
64609
65244
|
lst: entry.lst,
|
|
64610
65245
|
brand: entry.brand,
|
|
64611
65246
|
symbol: entry.symbol,
|
|
64612
65247
|
requestId: String(toBigInt14(ids[i]) ?? i),
|
|
64613
|
-
amountUnderlying:
|
|
65248
|
+
amountUnderlying: amount4.toString(),
|
|
64614
65249
|
status: redeemable[i] ? "claimable" : "pending"
|
|
64615
65250
|
});
|
|
64616
65251
|
}
|
|
@@ -64618,6 +65253,84 @@ var readerValantis = {
|
|
|
64618
65253
|
}
|
|
64619
65254
|
};
|
|
64620
65255
|
|
|
65256
|
+
// src/vaults/lst/withdrawals/abis/treehouse.ts
|
|
65257
|
+
var TreehouseRedemptionQueueAbi = [
|
|
65258
|
+
{
|
|
65259
|
+
name: "getPendingRedeems",
|
|
65260
|
+
type: "function",
|
|
65261
|
+
stateMutability: "view",
|
|
65262
|
+
inputs: [{ type: "address", name: "user" }],
|
|
65263
|
+
outputs: [
|
|
65264
|
+
{
|
|
65265
|
+
type: "tuple[]",
|
|
65266
|
+
components: [
|
|
65267
|
+
{ type: "uint64", name: "startTime" },
|
|
65268
|
+
{ type: "uint96", name: "shares" },
|
|
65269
|
+
{ type: "uint128", name: "assets" },
|
|
65270
|
+
{ type: "uint128", name: "baseRate" }
|
|
65271
|
+
]
|
|
65272
|
+
}
|
|
65273
|
+
]
|
|
65274
|
+
},
|
|
65275
|
+
{
|
|
65276
|
+
name: "waitingPeriod",
|
|
65277
|
+
type: "function",
|
|
65278
|
+
stateMutability: "view",
|
|
65279
|
+
inputs: [],
|
|
65280
|
+
outputs: [{ type: "uint32" }]
|
|
65281
|
+
}
|
|
65282
|
+
];
|
|
65283
|
+
|
|
65284
|
+
// src/vaults/lst/withdrawals/readers/treehouse.ts
|
|
65285
|
+
var readerTreehouseRedemption = {
|
|
65286
|
+
fetch: async (user, multicallRetry, chainId, entry) => {
|
|
65287
|
+
if (!entry.withdrawalContract) return [];
|
|
65288
|
+
const res = await multicallRetry({
|
|
65289
|
+
chain: chainId,
|
|
65290
|
+
calls: [
|
|
65291
|
+
{
|
|
65292
|
+
address: entry.withdrawalContract,
|
|
65293
|
+
name: "getPendingRedeems",
|
|
65294
|
+
params: [user]
|
|
65295
|
+
},
|
|
65296
|
+
{
|
|
65297
|
+
address: entry.withdrawalContract,
|
|
65298
|
+
name: "waitingPeriod",
|
|
65299
|
+
params: []
|
|
65300
|
+
}
|
|
65301
|
+
],
|
|
65302
|
+
abi: [
|
|
65303
|
+
TreehouseRedemptionQueueAbi,
|
|
65304
|
+
TreehouseRedemptionQueueAbi
|
|
65305
|
+
]
|
|
65306
|
+
});
|
|
65307
|
+
const reqs = res[0];
|
|
65308
|
+
const waitingPeriod = toNumber(res[1]);
|
|
65309
|
+
if (!Array.isArray(reqs) || waitingPeriod === void 0) return [];
|
|
65310
|
+
const out = [];
|
|
65311
|
+
for (let i = 0; i < reqs.length; i++) {
|
|
65312
|
+
const r = reqs[i];
|
|
65313
|
+
const startTime = toNumber(r.startTime);
|
|
65314
|
+
const assets = toBigInt14(r.assets);
|
|
65315
|
+
const shares = toBigInt14(r.shares);
|
|
65316
|
+
if (startTime === void 0 || assets === void 0) continue;
|
|
65317
|
+
const readyAt = startTime + waitingPeriod;
|
|
65318
|
+
out.push({
|
|
65319
|
+
lst: entry.lst,
|
|
65320
|
+
brand: entry.brand,
|
|
65321
|
+
symbol: entry.symbol,
|
|
65322
|
+
// Positional — see note 1 above.
|
|
65323
|
+
requestId: String(i),
|
|
65324
|
+
amountUnderlying: assets.toString(),
|
|
65325
|
+
shares: shares?.toString(),
|
|
65326
|
+
status: computeStatus(readyAt),
|
|
65327
|
+
readyAt
|
|
65328
|
+
});
|
|
65329
|
+
}
|
|
65330
|
+
return out;
|
|
65331
|
+
}
|
|
65332
|
+
};
|
|
65333
|
+
|
|
64621
65334
|
// src/vaults/lst/withdrawals/abis/trufin.ts
|
|
64622
65335
|
var TruFinVaultAbi = [
|
|
64623
65336
|
{
|
|
@@ -64682,15 +65395,15 @@ var readerTruFin = {
|
|
|
64682
65395
|
if (typeof recipient === "string" && recipient.toLowerCase() !== lcUser) {
|
|
64683
65396
|
continue;
|
|
64684
65397
|
}
|
|
64685
|
-
const
|
|
64686
|
-
if (
|
|
65398
|
+
const amount4 = Array.isArray(w) ? toBigInt14(w[1]) : toBigInt14(w.amount);
|
|
65399
|
+
if (amount4 === void 0 || amount4 === 0n) continue;
|
|
64687
65400
|
out.push({
|
|
64688
65401
|
lst: entry.lst,
|
|
64689
65402
|
brand: entry.brand,
|
|
64690
65403
|
symbol: entry.symbol,
|
|
64691
65404
|
// Composite id — same shape as the input.
|
|
64692
65405
|
requestId: `${pairs[i].validator}:${pairs[i].nonce.toString()}`,
|
|
64693
|
-
amountUnderlying:
|
|
65406
|
+
amountUnderlying: amount4.toString(),
|
|
64694
65407
|
status: claimable ? "claimable" : "pending"
|
|
64695
65408
|
});
|
|
64696
65409
|
}
|
|
@@ -64797,17 +65510,17 @@ var readerYieldNest = {
|
|
|
64797
65510
|
const id = ids[i];
|
|
64798
65511
|
const r = stage3[i];
|
|
64799
65512
|
if (!r) continue;
|
|
64800
|
-
const
|
|
65513
|
+
const amount4 = toBigInt14(r.amount);
|
|
64801
65514
|
const created = toNumber(r.creationTimestamp);
|
|
64802
65515
|
const processed = Boolean(r.processed);
|
|
64803
|
-
if (
|
|
65516
|
+
if (amount4 === void 0 || created === void 0) continue;
|
|
64804
65517
|
const readyAt = created + finalizationSeconds;
|
|
64805
65518
|
out.push({
|
|
64806
65519
|
lst: entry.lst,
|
|
64807
65520
|
brand: entry.brand,
|
|
64808
65521
|
symbol: entry.symbol,
|
|
64809
65522
|
requestId: id.toString(),
|
|
64810
|
-
amountUnderlying:
|
|
65523
|
+
amountUnderlying: amount4.toString(),
|
|
64811
65524
|
status: processed ? "claimed" : computeStatus(readyAt),
|
|
64812
65525
|
readyAt: processed ? void 0 : readyAt
|
|
64813
65526
|
});
|
|
@@ -64876,6 +65589,8 @@ var buildWithdrawalReader = (entry) => {
|
|
|
64876
65589
|
return readerPrimeStaking;
|
|
64877
65590
|
case "berapawRedeemQueue":
|
|
64878
65591
|
return readerBeraPaw;
|
|
65592
|
+
case "treehouseRedemptionQueue":
|
|
65593
|
+
return readerTreehouseRedemption;
|
|
64879
65594
|
case "eventsOnly":
|
|
64880
65595
|
case "noQueue":
|
|
64881
65596
|
case "unverified":
|
|
@@ -64886,6 +65601,18 @@ var buildWithdrawalReader = (entry) => {
|
|
|
64886
65601
|
// src/vaults/lst/withdrawals/registry.ts
|
|
64887
65602
|
var LST_WITHDRAWAL_REGISTRY = {
|
|
64888
65603
|
"1": [
|
|
65604
|
+
{
|
|
65605
|
+
// Treehouse tETH — `TreehouseRedemptionV2`, the queued (5 bps / 7 d)
|
|
65606
|
+
// exit. The instant Fastlane leg settles in the same transaction and
|
|
65607
|
+
// so never produces a pending request. Undocumented address,
|
|
65608
|
+
// recovered from `Vault.redemption()` →
|
|
65609
|
+
// `RedemptionController.getRedemptionContracts()`.
|
|
65610
|
+
lst: "0xd11c452fc99cf405034ee446803b6f6c1f6d5ed8",
|
|
65611
|
+
brand: "Treehouse",
|
|
65612
|
+
symbol: "tETH",
|
|
65613
|
+
reader: "treehouseRedemptionQueue",
|
|
65614
|
+
withdrawalContract: "0xcd63a29faff07130d3af89bb4f40778938aabb85"
|
|
65615
|
+
},
|
|
64889
65616
|
{
|
|
64890
65617
|
// wBETH — Binance's UnwrapTokenV1 queue, the SAME contract address
|
|
64891
65618
|
// on Ethereum and BNB. Entered via `wBETH.requestWithdrawEth`;
|
|
@@ -65349,6 +66076,14 @@ var LST_WITHDRAWAL_REGISTRY = {
|
|
|
65349
66076
|
}
|
|
65350
66077
|
],
|
|
65351
66078
|
"43114": [
|
|
66079
|
+
{
|
|
66080
|
+
// Treehouse tAVAX — same stack as tETH; 17-day wait here.
|
|
66081
|
+
lst: "0x14a84f1a61ccd7d1be596a6cc11fe33a36bc1646",
|
|
66082
|
+
brand: "Treehouse",
|
|
66083
|
+
symbol: "tAVAX",
|
|
66084
|
+
reader: "treehouseRedemptionQueue",
|
|
66085
|
+
withdrawalContract: "0x765f6dc8496ca7ef1e4a391be10185229aacf04b"
|
|
66086
|
+
},
|
|
65352
66087
|
// Ankr ankrAVAX — Ankr unstake queue; reader not yet implemented.
|
|
65353
66088
|
{
|
|
65354
66089
|
lst: "0xc3344870d52688874b06d844e0c36cc39fc727f6",
|
|
@@ -65419,6 +66154,14 @@ var LST_WITHDRAWAL_REGISTRY = {
|
|
|
65419
66154
|
}
|
|
65420
66155
|
],
|
|
65421
66156
|
"999": [
|
|
66157
|
+
{
|
|
66158
|
+
// Treehouse tHYPE — same stack as tETH; 10-day wait here.
|
|
66159
|
+
lst: "0xb83d27f0f4133a7b0377a88089583131a903fdc7",
|
|
66160
|
+
brand: "Treehouse",
|
|
66161
|
+
symbol: "tHYPE",
|
|
66162
|
+
reader: "treehouseRedemptionQueue",
|
|
66163
|
+
withdrawalContract: "0xcebbb011c2f29b0ed25895c54662bd1ccad30280"
|
|
66164
|
+
},
|
|
65422
66165
|
{
|
|
65423
66166
|
// Hyperbeat hbHYPE Ultra — ERC-7540 async-redeem.
|
|
65424
66167
|
lst: "0x96c6cbb6251ee1c257b2162ca0f39aa5fa44b1fb",
|
|
@@ -65658,6 +66401,15 @@ var Erc4626ReadAbi2 = [
|
|
|
65658
66401
|
outputs: [{ type: "uint256", name: "assets" }]
|
|
65659
66402
|
}
|
|
65660
66403
|
];
|
|
66404
|
+
var LockupPeriodAbi = [
|
|
66405
|
+
{
|
|
66406
|
+
name: "lockupPeriod",
|
|
66407
|
+
type: "function",
|
|
66408
|
+
stateMutability: "view",
|
|
66409
|
+
inputs: [],
|
|
66410
|
+
outputs: [{ type: "uint256" }]
|
|
66411
|
+
}
|
|
66412
|
+
];
|
|
65661
66413
|
var CooldownDurationAbi = [
|
|
65662
66414
|
{
|
|
65663
66415
|
name: "cooldownDuration",
|
|
@@ -65758,14 +66510,16 @@ var readerErc46262 = (entry) => {
|
|
|
65758
66510
|
var readerErc4626Cooldown = (entry) => {
|
|
65759
66511
|
const shareUnit = 10n ** BigInt(entry.decimals);
|
|
65760
66512
|
const underlyingUnit = 10n ** BigInt(entry.underlyingDecimals ?? entry.decimals);
|
|
66513
|
+
const cooldownGetter = entry.cooldownGetter ?? "cooldownDuration";
|
|
66514
|
+
const cooldownAbi = cooldownGetter === "lockupPeriod" ? LockupPeriodAbi : CooldownDurationAbi;
|
|
65761
66515
|
return {
|
|
65762
66516
|
calls: [
|
|
65763
66517
|
{ address: entry.address, name: "totalAssets", params: [] },
|
|
65764
66518
|
{ address: entry.address, name: "totalSupply", params: [] },
|
|
65765
66519
|
{ address: entry.address, name: "convertToAssets", params: [shareUnit] },
|
|
65766
|
-
{ address: entry.address, name:
|
|
66520
|
+
{ address: entry.address, name: cooldownGetter, params: [] }
|
|
65767
66521
|
],
|
|
65768
|
-
abis: [Erc4626ReadAbi2, TotalSupplyAbi2, Erc4626ReadAbi2,
|
|
66522
|
+
abis: [Erc4626ReadAbi2, TotalSupplyAbi2, Erc4626ReadAbi2, cooldownAbi],
|
|
65769
66523
|
parse: ([assets, supply, rate, cooldown]) => {
|
|
65770
66524
|
const totalAssets = toBigInt15(assets);
|
|
65771
66525
|
const totalSupply = toBigInt15(supply);
|
|
@@ -66243,6 +66997,8 @@ var readerHyperbeatVault = (entry) => {
|
|
|
66243
66997
|
var readerNavOracle = (entry) => {
|
|
66244
66998
|
const shareUnit = 10n ** BigInt(entry.decimals);
|
|
66245
66999
|
const underlyingUnit = 10n ** BigInt(entry.underlyingDecimals ?? entry.decimals);
|
|
67000
|
+
const oracleDecimals = entry.priceOracleDecimals ?? 18;
|
|
67001
|
+
const oracleScale = 10n ** BigInt(oracleDecimals);
|
|
66246
67002
|
return {
|
|
66247
67003
|
calls: [
|
|
66248
67004
|
{ address: entry.address, name: "totalSupply", params: [] },
|
|
@@ -66257,8 +67013,9 @@ var readerNavOracle = (entry) => {
|
|
|
66257
67013
|
const totalSupply = toBigInt15(supply);
|
|
66258
67014
|
if (totalSupply === void 0) return void 0;
|
|
66259
67015
|
const raw = Array.isArray(round) ? round[1] : round?.answer;
|
|
66260
|
-
const
|
|
66261
|
-
if (
|
|
67016
|
+
const answer = toBigInt15(raw);
|
|
67017
|
+
if (answer === void 0 || answer <= 0n) return void 0;
|
|
67018
|
+
const exchangeRate = answer * ONE_E1813 / oracleScale;
|
|
66262
67019
|
return {
|
|
66263
67020
|
totalAssets: totalSupply * exchangeRate * underlyingUnit / (ONE_E1813 * shareUnit),
|
|
66264
67021
|
totalSupply,
|
|
@@ -66558,6 +67315,19 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
|
|
|
66558
67315
|
instantRedeemEnabled: state.instantRedeemEnabled,
|
|
66559
67316
|
inventoryContract: entry.inventoryContract?.toLowerCase(),
|
|
66560
67317
|
withdrawQueue: state.withdrawQueue ?? entry.withdrawQueue?.toLowerCase(),
|
|
67318
|
+
// Both legs of a two-legged exit, spelled out — see `VaultExitRoute`.
|
|
67319
|
+
// Derived from the flat fields the readers already establish, so every
|
|
67320
|
+
// savings row gets it without a per-provider change; the queued leg's
|
|
67321
|
+
// fee is left ABSENT rather than 0 because "not published" and "free"
|
|
67322
|
+
// are different claims and only some protocols make the second.
|
|
67323
|
+
exitRoutes: deriveExitRoutes({
|
|
67324
|
+
withdrawalMode: entry.withdrawalMode,
|
|
67325
|
+
withdrawFeeBps: state.withdrawFeeBps,
|
|
67326
|
+
withdrawalCooldownSeconds: state.withdrawalCooldownSeconds ?? entry.withdrawalCooldownSeconds,
|
|
67327
|
+
liquidity: liquidityRaw,
|
|
67328
|
+
liquidityFormatted,
|
|
67329
|
+
liquidityUsd
|
|
67330
|
+
}),
|
|
66561
67331
|
depositCapacity,
|
|
66562
67332
|
depositCapacityFormatted,
|
|
66563
67333
|
depositCapacityUsd,
|
|
@@ -67174,6 +67944,34 @@ var fetchUpshiftVaults = async (chainId, prices = {}, tokenList = {}) => {
|
|
|
67174
67944
|
return out;
|
|
67175
67945
|
};
|
|
67176
67946
|
|
|
67947
|
+
// src/vaults/rateSanity.ts
|
|
67948
|
+
var NOISE_DEVIATION_BPS = 10;
|
|
67949
|
+
var IMPLAUSIBLE_APR_PERCENT2 = 1e3;
|
|
67950
|
+
var DUST_TVL_USD = 1e3;
|
|
67951
|
+
var impliedDeviationBps = (c) => {
|
|
67952
|
+
const secs = c.expiry - c.nowSecs;
|
|
67953
|
+
if (!(secs > 0)) return 0;
|
|
67954
|
+
const years = secs / 31536e3;
|
|
67955
|
+
return (Math.pow(1 + c.aprPercent / 100, years) - 1) * 1e4;
|
|
67956
|
+
};
|
|
67957
|
+
var isAnnualizationNoise = (c) => {
|
|
67958
|
+
if (!Number.isFinite(c.aprPercent)) return false;
|
|
67959
|
+
if (!(c.expiry > c.nowSecs)) return false;
|
|
67960
|
+
return Math.abs(impliedDeviationBps(c)) < NOISE_DEVIATION_BPS;
|
|
67961
|
+
};
|
|
67962
|
+
var isImplausibleMagnitude = (aprPercent, totalAssetsUsd) => {
|
|
67963
|
+
if (!Number.isFinite(aprPercent)) return false;
|
|
67964
|
+
if (Math.abs(aprPercent) <= IMPLAUSIBLE_APR_PERCENT2) return false;
|
|
67965
|
+
return (totalAssetsUsd ?? 0) < DUST_TVL_USD;
|
|
67966
|
+
};
|
|
67967
|
+
var isUnearnableRate = (args) => {
|
|
67968
|
+
const { aprPercent, totalAssetsUsd, expiry } = args;
|
|
67969
|
+
if (isImplausibleMagnitude(aprPercent, totalAssetsUsd)) return true;
|
|
67970
|
+
if (expiry === void 0) return false;
|
|
67971
|
+
const nowSecs = args.nowSecs ?? Math.floor(Date.now() / 1e3);
|
|
67972
|
+
return (totalAssetsUsd ?? 0) < DUST_TVL_USD && isAnnualizationNoise({ aprPercent, expiry, nowSecs });
|
|
67973
|
+
};
|
|
67974
|
+
|
|
67177
67975
|
// src/vaults/yearn/fetchPublic.ts
|
|
67178
67976
|
var BRAND3 = "Yearn";
|
|
67179
67977
|
var ZERO_ADDR = "0x0000000000000000000000000000000000000000";
|
|
@@ -67363,7 +68161,14 @@ var fetchYearnVaults = async (chainId, multicallRetry, prices = {}, tokenList =
|
|
|
67363
68161
|
const out = {};
|
|
67364
68162
|
for (const item of items) {
|
|
67365
68163
|
const parsed = parseVault9(item, chainId, prices, tokenList);
|
|
67366
|
-
if (parsed)
|
|
68164
|
+
if (!parsed) continue;
|
|
68165
|
+
if (isUnearnableRate({
|
|
68166
|
+
aprPercent: parsed.supplyRate,
|
|
68167
|
+
totalAssetsUsd: parsed.totalAssetsUsd
|
|
68168
|
+
})) {
|
|
68169
|
+
continue;
|
|
68170
|
+
}
|
|
68171
|
+
out[parsed.address] = parsed;
|
|
67367
68172
|
}
|
|
67368
68173
|
try {
|
|
67369
68174
|
await attachYearnLiquidity(chainId, multicallRetry, out);
|
|
@@ -69125,7 +69930,16 @@ var fetchPendlePtMarkets = async (chainId, multicallRetry, prices = {}, tokenLis
|
|
|
69125
69930
|
decimalsOnChain,
|
|
69126
69931
|
nowSecs
|
|
69127
69932
|
);
|
|
69128
|
-
if (parsed)
|
|
69933
|
+
if (!parsed) continue;
|
|
69934
|
+
if (isUnearnableRate({
|
|
69935
|
+
aprPercent: parsed.supplyRate,
|
|
69936
|
+
totalAssetsUsd: parsed.totalAssetsUsd,
|
|
69937
|
+
expiry: parsed.expiry,
|
|
69938
|
+
nowSecs
|
|
69939
|
+
})) {
|
|
69940
|
+
continue;
|
|
69941
|
+
}
|
|
69942
|
+
out[parsed.address] = parsed;
|
|
69129
69943
|
}
|
|
69130
69944
|
return out;
|
|
69131
69945
|
};
|
|
@@ -69374,7 +70188,16 @@ var fetchSpectraPtMarkets = async (chainId, multicallRetry, prices = {}, tokenLi
|
|
|
69374
70188
|
decimalsOnChain,
|
|
69375
70189
|
nowSecs
|
|
69376
70190
|
);
|
|
69377
|
-
if (parsed)
|
|
70191
|
+
if (!parsed) continue;
|
|
70192
|
+
if (isUnearnableRate({
|
|
70193
|
+
aprPercent: parsed.supplyRate,
|
|
70194
|
+
totalAssetsUsd: parsed.totalAssetsUsd,
|
|
70195
|
+
expiry: parsed.expiry,
|
|
70196
|
+
nowSecs
|
|
70197
|
+
})) {
|
|
70198
|
+
continue;
|
|
70199
|
+
}
|
|
70200
|
+
out[parsed.address] = parsed;
|
|
69378
70201
|
}
|
|
69379
70202
|
return out;
|
|
69380
70203
|
};
|
|
@@ -69702,24 +70525,24 @@ function shortDate(unixSecs) {
|
|
|
69702
70525
|
}
|
|
69703
70526
|
function feePhrase(fee) {
|
|
69704
70527
|
const magnitude = Math.abs(fee.value);
|
|
69705
|
-
let
|
|
70528
|
+
let amount4;
|
|
69706
70529
|
switch (fee.unit) {
|
|
69707
70530
|
case "bps":
|
|
69708
|
-
|
|
70531
|
+
amount4 = `${magnitude} bps`;
|
|
69709
70532
|
break;
|
|
69710
70533
|
case "apr-percent":
|
|
69711
|
-
|
|
70534
|
+
amount4 = `${pct(magnitude)}/yr`;
|
|
69712
70535
|
break;
|
|
69713
70536
|
case "percent":
|
|
69714
|
-
|
|
70537
|
+
amount4 = pct(magnitude);
|
|
69715
70538
|
break;
|
|
69716
70539
|
default:
|
|
69717
|
-
|
|
70540
|
+
amount4 = String(magnitude);
|
|
69718
70541
|
}
|
|
69719
70542
|
const rebate = fee.value < 0 ? " rebate" : "";
|
|
69720
70543
|
const qualifier = fee.indicative ? " (estimated, resolved at execution)" : "";
|
|
69721
70544
|
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" : "";
|
|
69722
|
-
return `${fee.label}: ${
|
|
70545
|
+
return `${fee.label}: ${amount4}${rebate}${bound}${qualifier}`;
|
|
69723
70546
|
}
|
|
69724
70547
|
function maturityPhrase(m) {
|
|
69725
70548
|
if (m.kind === "fixed-date" && m.maturity)
|
|
@@ -69805,12 +70628,40 @@ function provenance(rate) {
|
|
|
69805
70628
|
}
|
|
69806
70629
|
return ` (incl. ${pct(intrinsic)} from the asset)`;
|
|
69807
70630
|
}
|
|
69808
|
-
function
|
|
70631
|
+
function routePhrase(r, symbol) {
|
|
70632
|
+
const when = r.kind === "instant" ? "instantly" : r.waitSeconds ? `after ${duration(r.waitSeconds)}` : r.kind === "market" ? "by selling it" : "after a wait";
|
|
70633
|
+
const cost = r.feeBps === 0 ? " free" : r.feeBps != null ? ` for ${(r.feeBps / 100).toFixed(2)} %` : r.feeUnknown ? " for a fee" : "";
|
|
70634
|
+
const floor = r.minAmountFormatted != null && r.minAmountFormatted > 0 ? ` (min ${amount(r.minAmountFormatted)}${symbol ? ` ${symbol}` : ""})` : "";
|
|
70635
|
+
const cap = r.kind !== "instant" || r.capacityFormatted == null ? "" : r.capacityFormatted <= 0 ? ", though nothing is available right now" : `, up to ${amount(r.capacityFormatted)}${symbol ? ` ${symbol}` : ""} right now`;
|
|
70636
|
+
return `${when}${cost}${floor}${cap}`;
|
|
70637
|
+
}
|
|
70638
|
+
function routesSentence(routes2, symbol) {
|
|
70639
|
+
const legs = routes2.map((r) => routePhrase(r, symbol));
|
|
70640
|
+
const body = legs.length === 1 ? legs[0] : `${legs.slice(0, -1).join(", ")}, or ${legs[legs.length - 1]}`;
|
|
70641
|
+
return `You can leave ${body}.`;
|
|
70642
|
+
}
|
|
70643
|
+
function amount(v) {
|
|
70644
|
+
if (v >= 1e3) return v.toLocaleString("en-US", { maximumFractionDigits: 0 });
|
|
70645
|
+
if (v >= 1) return v.toFixed(2).replace(/\.?0+$/, "");
|
|
70646
|
+
return v.toPrecision(3);
|
|
70647
|
+
}
|
|
70648
|
+
function headlineExitFromRoutes(routes2, symbol) {
|
|
70649
|
+
if (!routes2 || routes2.length < 2) return void 0;
|
|
70650
|
+
const fast = routes2.find((r) => r.kind === "instant");
|
|
70651
|
+
const slow = routes2.find((r) => r.kind === "queued");
|
|
70652
|
+
if (!fast || !slow) return void 0;
|
|
70653
|
+
const fastPart = fast.feeBps == null ? "instant exit" : fast.feeBps === 0 ? "free instant exit" : `instant exit for ${(fast.feeBps / 100).toFixed(2)} %`;
|
|
70654
|
+
const slowCost = slow.feeBps === 0 ? "free" : slow.feeBps != null ? `${(slow.feeBps / 100).toFixed(2)} %` : void 0;
|
|
70655
|
+
const floor = slow.minAmountFormatted != null && slow.minAmountFormatted > 0 ? ` above ${amount(slow.minAmountFormatted)}${symbol ? ` ${symbol}` : ""}` : "";
|
|
70656
|
+
const slowPart = slowCost ? `queue${floor} for ${slowCost}` : `queue${floor}`;
|
|
70657
|
+
return `${fastPart}, or ${slowPart}`;
|
|
70658
|
+
}
|
|
70659
|
+
function supplyHeadline(s, sheet = {}) {
|
|
69809
70660
|
if (s.role === "collateral") {
|
|
69810
70661
|
return `Collateral only \xB7 ${maturityPhrase(s.maturity)}`;
|
|
69811
70662
|
}
|
|
69812
70663
|
const rate = `${rateLabel(s)} ${pct(s.rate.aprTotal)}${windowNote(s.rate)}${provenance(s.rate)}`;
|
|
69813
|
-
const exit = exitPhrase[String(s.exit.mode)] ?? (s.exit.settlement === "sync" ? "withdraw any time" : "delayed withdrawal");
|
|
70664
|
+
const exit = headlineExitFromRoutes(s.exit.routes, sheet.asset?.symbol) ?? exitPhrase[String(s.exit.mode)] ?? (s.exit.settlement === "sync" ? "withdraw any time" : "delayed withdrawal");
|
|
69814
70665
|
const cooldown = s.exit.cooldownSecs ? ` (${duration(s.exit.cooldownSecs)})` : "";
|
|
69815
70666
|
const mat = s.maturity.kind === "perpetual" ? "" : ` ${maturityPhrase(s.maturity)}`;
|
|
69816
70667
|
const warmup = s.rate.warmupSecs ? ` \xB7 earns after ${duration(s.rate.warmupSecs)}` : "";
|
|
@@ -69846,7 +70697,9 @@ function supplyDescription(s, sheet = {}) {
|
|
|
69846
70697
|
`You earn ${pct(s.rate.aprTotal)} (${comp.join(" + ")}), ${rateBehaviour(s.rate)}.`
|
|
69847
70698
|
);
|
|
69848
70699
|
}
|
|
69849
|
-
if (s.exit.
|
|
70700
|
+
if (s.exit.routes && s.exit.routes.length > 1) {
|
|
70701
|
+
parts.push(routesSentence(s.exit.routes, sheet.asset?.symbol));
|
|
70702
|
+
} else if (s.exit.mode === "instant") {
|
|
69850
70703
|
const util = sheet.utilization?.utilization;
|
|
69851
70704
|
parts.push(
|
|
69852
70705
|
util != null && util >= 0.95 ? `Withdrawals are instant in principle, but utilization is ${pct(util * 100)} \u2014 there may be little or no liquidity to withdraw right now.` : "Withdrawals are instant, up to the liquidity available in the market."
|
|
@@ -69931,6 +70784,12 @@ function borrowDescription(b) {
|
|
|
69931
70784
|
parts.push(
|
|
69932
70785
|
"Liquidation is a public auction rather than a loan-to-value threshold" + (win ? `, open for ${duration(win)} once started` : "") + (pen != null ? `, and the liquidator is paid ${pct(pen * 100)}` : "") + "."
|
|
69933
70786
|
);
|
|
70787
|
+
} else if (b.liquidation.model === "repay-to-target-hf") {
|
|
70788
|
+
const l = b.liquidation;
|
|
70789
|
+
const start = l.liquidationLtv != null && l.liquidationLtv > 0 ? `Liquidation starts at ${pct(l.liquidationLtv * 100)} LTV and` : "A liquidation";
|
|
70790
|
+
const sized = l.targetHealthFactor != null ? ` repays as much of your debt as it takes to restore a health factor of ${l.targetHealthFactor.toFixed(2)}` : " repays as much of your debt as it takes to restore the spoke\u2019s target health factor";
|
|
70791
|
+
const bonus = l.penalty != null && l.penalty > 0 ? ` \u2014 the liquidator\u2019s bonus scales up to ${pct(l.penalty * 100)}` + (l.healthFactorForMaxBonus != null ? ` at a health factor of ${l.healthFactorForMaxBonus.toFixed(2)}` : "") + "." : ".";
|
|
70792
|
+
parts.push(`${start}${sized} rather than a fixed share of it${bonus}`);
|
|
69934
70793
|
} else if (b.liquidation.liquidationLtv != null && b.liquidation.liquidationLtv > 0) {
|
|
69935
70794
|
const pen = b.liquidation.penalty;
|
|
69936
70795
|
parts.push(
|
|
@@ -69964,6 +70823,27 @@ var TERM_PROFILES = [
|
|
|
69964
70823
|
]
|
|
69965
70824
|
}
|
|
69966
70825
|
}),
|
|
70826
|
+
P({
|
|
70827
|
+
id: "aave-v4.spoke@v1",
|
|
70828
|
+
name: "Aave V4 spoke (liquidated to a target health factor)",
|
|
70829
|
+
family: "pool",
|
|
70830
|
+
supply: {
|
|
70831
|
+
description: "A shared liquidity pool on an Aave V4 spoke. Deposits earn interest paid by borrowers of the hub asset, at a rate that moves with utilization. Withdrawals are instant up to the cash left in the pool.",
|
|
70832
|
+
implications: [
|
|
70833
|
+
"Your yield is not fixed \u2014 it rises and falls with borrowing demand.",
|
|
70834
|
+
"If utilization reaches 100 %, withdrawals are blocked until borrowers repay or new deposits arrive.",
|
|
70835
|
+
"Each spoke is its own market: the same asset on another spoke is a separate position with its own risk parameters."
|
|
70836
|
+
]
|
|
70837
|
+
},
|
|
70838
|
+
borrow: {
|
|
70839
|
+
description: "Borrow against collateral at a rate that moves with utilization. Liquidation here is sized to a target health factor rather than capped at a fixed share of your debt: a liquidator repays whatever it takes to bring the position back up to the target, and their bonus grows the further under water it is.",
|
|
70840
|
+
implications: [
|
|
70841
|
+
"There is no 50 % close-factor protection \u2014 how much of your debt is taken depends on how far the position fell, and a deep enough drop takes all of it.",
|
|
70842
|
+
"The published liquidation penalty is the MAXIMUM bonus, charged only once the position is far enough under water; a shallow liquidation costs less.",
|
|
70843
|
+
"V4 uses ONE loan-to-value per asset for both borrowing and liquidation \u2014 there is no buffer between the LTV you can borrow to and the one that gets you liquidated."
|
|
70844
|
+
]
|
|
70845
|
+
}
|
|
70846
|
+
}),
|
|
69967
70847
|
// ── Fixed-term families ──────────────────────────────────────────────────
|
|
69968
70848
|
P({
|
|
69969
70849
|
id: "exactly.fixed@v1",
|
|
@@ -70952,7 +71832,7 @@ function finalizeInfo(sheet) {
|
|
|
70952
71832
|
sheet.borrow.info = { headline: "", description: "", tags: [] };
|
|
70953
71833
|
if (sheet.supply) {
|
|
70954
71834
|
sheet.supply.info = {
|
|
70955
|
-
headline: sheet.supply.info.headline || supplyHeadline(sheet.supply),
|
|
71835
|
+
headline: sheet.supply.info.headline || supplyHeadline(sheet.supply, sheet),
|
|
70956
71836
|
description: sheet.supply.info.description || supplyDescription(sheet.supply, sheet),
|
|
70957
71837
|
implications: sheet.supply.info.implications,
|
|
70958
71838
|
tags: deriveSupplyTags(sheet.supply, market)
|
|
@@ -71456,6 +72336,10 @@ function resolveExitMode(input, t) {
|
|
|
71456
72336
|
if (totalAssets <= 0) return "instant";
|
|
71457
72337
|
return liquidity >= totalAssets ? "instant" : "instant-capped";
|
|
71458
72338
|
}
|
|
72339
|
+
var TWO_LEGGED_MODES = /* @__PURE__ */ new Set([
|
|
72340
|
+
"fee-or-queued",
|
|
72341
|
+
"instant-or-queued"
|
|
72342
|
+
]);
|
|
71459
72343
|
var ASYNC_MODES = /* @__PURE__ */ new Set([
|
|
71460
72344
|
"fixed-cooldown",
|
|
71461
72345
|
"queued",
|
|
@@ -71469,12 +72353,29 @@ function settlementFor(mode, priceRisk) {
|
|
|
71469
72353
|
return "market";
|
|
71470
72354
|
return ASYNC_MODES.has(mode) ? "async" : "sync";
|
|
71471
72355
|
}
|
|
72356
|
+
function derivedRoutes(input, mode) {
|
|
72357
|
+
const routes2 = deriveExitRoutes({
|
|
72358
|
+
withdrawalMode: mode,
|
|
72359
|
+
withdrawFeeBps: input.withdrawFeeBps,
|
|
72360
|
+
withdrawalCooldownSeconds: input.withdrawalCooldownSeconds,
|
|
72361
|
+
liquidity: isNum2(input.liquidity) ? String(input.liquidity) : void 0,
|
|
72362
|
+
liquidityFormatted: input.liquidity,
|
|
72363
|
+
liquidityUsd: input.liquidityUsd
|
|
72364
|
+
});
|
|
72365
|
+
return routes2.length > 0 ? routes2 : void 0;
|
|
72366
|
+
}
|
|
71472
72367
|
function buildExit(input, t, fees) {
|
|
71473
72368
|
const mode = resolveExitMode(input, t);
|
|
71474
72369
|
const priceRisk = resolvePriceRisk(input, t);
|
|
71475
72370
|
const ratio = input.instantLiquidityRatio ?? (isNum2(input.liquidity) && isNum2(input.totalAssets) && input.totalAssets > 0 ? clamp014(input.liquidity / input.totalAssets) : void 0);
|
|
71476
72371
|
return {
|
|
71477
72372
|
mode,
|
|
72373
|
+
// The row's own list wins — providers that read their protocol's exit
|
|
72374
|
+
// modules attach live per-leg fees and minimums. Otherwise derive the
|
|
72375
|
+
// same split from the flat fields, because the alternative is a sheet
|
|
72376
|
+
// that states one wait and one fee belonging to DIFFERENT legs. Only a
|
|
72377
|
+
// row whose mode we cannot map at all ends up with no routes.
|
|
72378
|
+
routes: input.exitRoutes ?? derivedRoutes(input, mode),
|
|
71478
72379
|
settlement: settlementFor(mode, priceRisk),
|
|
71479
72380
|
cooldownSecs: input.withdrawalCooldownSeconds,
|
|
71480
72381
|
liquidity: isNum2(input.liquidity) || isNum2(input.liquidityUsd) ? {
|
|
@@ -71681,6 +72582,10 @@ function buildCoverage2(sheet, input, t) {
|
|
|
71681
72582
|
else pending.counterparty = "solvency-not-curated-default-assumed";
|
|
71682
72583
|
if (sheet.supply?.exit.liquidity) present.push("exitLiquidity");
|
|
71683
72584
|
else pending.exitLiquidity = "provider-does-not-publish-liquidity";
|
|
72585
|
+
if (sheet.supply?.exit.routes?.length) present.push("exitRoutes");
|
|
72586
|
+
else if (TWO_LEGGED_MODES.has(String(sheet.supply?.exit.mode)))
|
|
72587
|
+
pending.exitRoutes = "provider-does-not-publish-per-leg-terms";
|
|
72588
|
+
else notApplicable.exitRoutes = "single-exit-route";
|
|
71684
72589
|
return {
|
|
71685
72590
|
present,
|
|
71686
72591
|
notApplicable: Object.keys(notApplicable).length ? notApplicable : void 0,
|
|
@@ -72409,13 +73314,13 @@ function earnMarketFromVault(row, chainId, opts = {}) {
|
|
|
72409
73314
|
// The vault origin reports RAW base units + a pre-formatted convenience
|
|
72410
73315
|
// field. Carry both; fall back to formatting the raw amount ourselves so
|
|
72411
73316
|
// `formatted` — the field consumers sort on — is never silently absent.
|
|
72412
|
-
tvl:
|
|
73317
|
+
tvl: amount2(
|
|
72413
73318
|
tvl.totalAssets,
|
|
72414
73319
|
tvl.totalAssetsFormatted,
|
|
72415
73320
|
tvl.totalAssetsUsd,
|
|
72416
73321
|
assetDecimals
|
|
72417
73322
|
),
|
|
72418
|
-
liquidity: liq.liquidity != null || liq.liquidityUsd != null ?
|
|
73323
|
+
liquidity: liq.liquidity != null || liq.liquidityUsd != null ? amount2(
|
|
72419
73324
|
liq.liquidity,
|
|
72420
73325
|
liq.liquidityFormatted,
|
|
72421
73326
|
liq.liquidityUsd,
|
|
@@ -72427,7 +73332,10 @@ function earnMarketFromVault(row, chainId, opts = {}) {
|
|
|
72427
73332
|
mode: exitMode,
|
|
72428
73333
|
settlement: str6(meta.redemptionType),
|
|
72429
73334
|
cooldownSecs: num13(meta.withdrawalCooldownSeconds),
|
|
72430
|
-
feeBps: num13(meta.withdrawFeeBps)
|
|
73335
|
+
feeBps: num13(meta.withdrawFeeBps),
|
|
73336
|
+
// Passed through, never re-derived: the earn row and the vault row must
|
|
73337
|
+
// not disagree about what the legs out are.
|
|
73338
|
+
routes: Array.isArray(meta.exitRoutes) ? meta.exitRoutes : void 0
|
|
72431
73339
|
},
|
|
72432
73340
|
availability,
|
|
72433
73341
|
risk: {
|
|
@@ -72528,7 +73436,7 @@ function isMatured(maturity) {
|
|
|
72528
73436
|
if (!maturity?.maturity) return false;
|
|
72529
73437
|
return maturity.maturity <= Math.floor(Date.now() / 1e3);
|
|
72530
73438
|
}
|
|
72531
|
-
function
|
|
73439
|
+
function amount2(raw, formatted, usd, decimals) {
|
|
72532
73440
|
const rawStr = raw != null ? String(raw) : void 0;
|
|
72533
73441
|
return {
|
|
72534
73442
|
raw: rawStr,
|
|
@@ -72556,6 +73464,13 @@ var num14 = (v) => {
|
|
|
72556
73464
|
};
|
|
72557
73465
|
var str7 = (v) => typeof v === "string" && v.trim() !== "" ? v : void 0;
|
|
72558
73466
|
var bool2 = (v) => typeof v === "boolean" ? v : void 0;
|
|
73467
|
+
var routes = (v) => {
|
|
73468
|
+
if (!Array.isArray(v)) return void 0;
|
|
73469
|
+
const out = v.filter(
|
|
73470
|
+
(r) => !!r && typeof r === "object" && typeof r.id === "string" && typeof r.kind === "string"
|
|
73471
|
+
);
|
|
73472
|
+
return out.length > 0 ? out : void 0;
|
|
73473
|
+
};
|
|
72559
73474
|
var strArray = (v) => {
|
|
72560
73475
|
if (!Array.isArray(v)) return void 0;
|
|
72561
73476
|
const out = v.filter((x) => typeof x === "string" && x !== "");
|
|
@@ -72626,6 +73541,7 @@ function toVaultTermInput(vault, provider, chainId) {
|
|
|
72626
73541
|
withdrawalMode: str7(row.withdrawalMode),
|
|
72627
73542
|
withdrawalCooldownSeconds: num14(row.withdrawalCooldownSeconds),
|
|
72628
73543
|
withdrawFeeBps: num14(row.withdrawFeeBps),
|
|
73544
|
+
exitRoutes: routes(row.exitRoutes),
|
|
72629
73545
|
fee: num14(row.fee),
|
|
72630
73546
|
managementFee: num14(row.managementFee),
|
|
72631
73547
|
swapFeeRate: num14(row.feeRate),
|
|
@@ -72692,6 +73608,7 @@ function vaultTermInputFromEarnMarket(m) {
|
|
|
72692
73608
|
withdrawalMode: m.exit.mode,
|
|
72693
73609
|
withdrawalCooldownSeconds: m.exit.cooldownSecs,
|
|
72694
73610
|
withdrawFeeBps: m.exit.feeBps,
|
|
73611
|
+
exitRoutes: routes(m.exit.routes),
|
|
72695
73612
|
fee: m.rate.fee,
|
|
72696
73613
|
managementFee: num14(meta.managementFee),
|
|
72697
73614
|
swapFeeRate: num14(meta.feeRate),
|
|
@@ -72774,6 +73691,7 @@ function vaultTermInputFromSourceRow(row, chainId) {
|
|
|
72774
73691
|
withdrawalMode: str7(meta.withdrawalMode),
|
|
72775
73692
|
withdrawalCooldownSeconds: num14(meta.withdrawalCooldownSeconds),
|
|
72776
73693
|
withdrawFeeBps: num14(meta.withdrawFeeBps),
|
|
73694
|
+
exitRoutes: routes(meta.exitRoutes),
|
|
72777
73695
|
fee: num14(rates.fee),
|
|
72778
73696
|
managementFee: num14(meta.managementFee),
|
|
72779
73697
|
swapFeeRate: num14(meta.feeRate),
|
|
@@ -73740,8 +74658,18 @@ function toTermSheetInput(row, ctx = {}) {
|
|
|
73740
74658
|
"flags.variableBorrowDisabled"
|
|
73741
74659
|
),
|
|
73742
74660
|
config,
|
|
73743
|
-
|
|
73744
|
-
|
|
74661
|
+
// `caps.` is NOT optional here. `/pools/latest` serializes both of these as
|
|
74662
|
+
// TOP-LEVEL row fields, while `/lending/latest` — the endpoint the lending
|
|
74663
|
+
// term sheets are actually stamped on — nests them under `caps` alongside
|
|
74664
|
+
// the supply/borrow caps (yield-tracer `utils/lending.ts`). Reading only
|
|
74665
|
+
// the flat key made every sheet on that endpoint fall through to the
|
|
74666
|
+
// builder's `?? 1`, so Aave and Compound V2 published "the whole debt can
|
|
74667
|
+
// be repaid in one liquidation" against a real close factor of 0.5, and
|
|
74668
|
+
// Aave V4's `targetHealthFactor` vanished entirely.
|
|
74669
|
+
closeFactor: num15(pick2(row, "closeFactor", "caps.closeFactor")),
|
|
74670
|
+
targetHealthFactor: num15(
|
|
74671
|
+
pick2(row, "targetHealthFactor", "caps.targetHealthFactor")
|
|
74672
|
+
),
|
|
73745
74673
|
fixedTerm: pick2(row, "fixedTerm") ?? ctx.fixedTerm,
|
|
73746
74674
|
terms: pick2(row, "terms"),
|
|
73747
74675
|
market: resolveMarketDescriptors(row, ctx.market)
|
|
@@ -73773,6 +74701,11 @@ var ROW_DESCRIPTOR_KEYS = [
|
|
|
73773
74701
|
// Fluid: distinguishes a SMART (T2/T3/T4) vault, whose collateral and/or
|
|
73774
74702
|
// debt is a two-token DEX LP position, from an ordinary T1 pool row.
|
|
73775
74703
|
"fluid",
|
|
74704
|
+
// Aave V4: the liquidation BONUS CURVE (`healthFactorForMaxBonus`,
|
|
74705
|
+
// `liquidationBonusFactor`). The sizing knob `targetHealthFactor` is a
|
|
74706
|
+
// market-level column and arrives without this; the curve is what turns the
|
|
74707
|
+
// published max bonus from a flat penalty into a bound.
|
|
74708
|
+
"aaveV4",
|
|
73776
74709
|
"broker",
|
|
73777
74710
|
"collateralProvider",
|
|
73778
74711
|
"loanProvider",
|
|
@@ -75347,6 +76280,32 @@ var morphoBlueAdapter = {
|
|
|
75347
76280
|
};
|
|
75348
76281
|
}
|
|
75349
76282
|
};
|
|
76283
|
+
var aaveV4Adapter = {
|
|
76284
|
+
id: "aave-v4",
|
|
76285
|
+
matches: isAaveV4Type,
|
|
76286
|
+
profileId: () => "aave-v4.spoke@v1",
|
|
76287
|
+
build: (input) => {
|
|
76288
|
+
const target = input.targetHealthFactor;
|
|
76289
|
+
const desc = input.market?.aaveV4 ?? {};
|
|
76290
|
+
const maxBonusHf = num17(desc.healthFactorForMaxBonus);
|
|
76291
|
+
return {
|
|
76292
|
+
borrow: {
|
|
76293
|
+
liquidation: {
|
|
76294
|
+
model: "repay-to-target-hf",
|
|
76295
|
+
// NOT a close factor — the ceiling. See the header.
|
|
76296
|
+
closeFactor: 1,
|
|
76297
|
+
targetHealthFactor: target,
|
|
76298
|
+
healthFactorForMaxBonus: maxBonusHf
|
|
76299
|
+
}
|
|
76300
|
+
}
|
|
76301
|
+
};
|
|
76302
|
+
}
|
|
76303
|
+
};
|
|
76304
|
+
function num17(v) {
|
|
76305
|
+
if (v == null) return void 0;
|
|
76306
|
+
const n = typeof v === "string" ? Number(v) : v;
|
|
76307
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
76308
|
+
}
|
|
75350
76309
|
|
|
75351
76310
|
// src/terms/adapters/index.ts
|
|
75352
76311
|
var TERM_ADAPTERS = [
|
|
@@ -75370,7 +76329,8 @@ var TERM_ADAPTERS = [
|
|
|
75370
76329
|
curvanceAdapter,
|
|
75371
76330
|
twyneAdapter,
|
|
75372
76331
|
fraxlendAdapter,
|
|
75373
|
-
morphoBlueAdapter
|
|
76332
|
+
morphoBlueAdapter,
|
|
76333
|
+
aaveV4Adapter
|
|
75374
76334
|
];
|
|
75375
76335
|
function resolveAdapter(lender) {
|
|
75376
76336
|
return TERM_ADAPTERS.find((a) => a.matches(lender));
|
|
@@ -75982,11 +76942,11 @@ function earnMarketFromPool(row, fallbackChainId, venueCollaterals) {
|
|
|
75982
76942
|
// so `formatted` is populated and `raw` is genuinely absent. Do NOT
|
|
75983
76943
|
// back-fill `raw` by re-scaling — the round-trip loses precision and would
|
|
75984
76944
|
// fabricate base units the origin never sent.
|
|
75985
|
-
tvl:
|
|
76945
|
+
tvl: amount3(
|
|
75986
76946
|
row.totalDeposits,
|
|
75987
76947
|
row.totalDepositsUSD ?? row.totalDepositsUsd
|
|
75988
76948
|
),
|
|
75989
|
-
liquidity:
|
|
76949
|
+
liquidity: amount3(
|
|
75990
76950
|
row.totalLiquidity,
|
|
75991
76951
|
row.totalLiquidityUSD ?? row.totalLiquidityUsd
|
|
75992
76952
|
),
|
|
@@ -76086,7 +77046,7 @@ function sumRewardAprs(rewards) {
|
|
|
76086
77046
|
}
|
|
76087
77047
|
return seen ? total : void 0;
|
|
76088
77048
|
}
|
|
76089
|
-
function
|
|
77049
|
+
function amount3(formatted, usd) {
|
|
76090
77050
|
return { formatted: num13(formatted), usd: num13(usd) };
|
|
76091
77051
|
}
|
|
76092
77052
|
function sum2(...parts) {
|
|
@@ -76336,7 +77296,7 @@ function legEarnUid(marketUid) {
|
|
|
76336
77296
|
if (isVaultVenue(parts[0])) return void 0;
|
|
76337
77297
|
return marketUid;
|
|
76338
77298
|
}
|
|
76339
|
-
function
|
|
77299
|
+
function num18(v) {
|
|
76340
77300
|
const n = typeof v === "number" ? v : Number(v);
|
|
76341
77301
|
return Number.isFinite(n) ? n : 0;
|
|
76342
77302
|
}
|
|
@@ -76358,10 +77318,10 @@ function legAsset(pos) {
|
|
|
76358
77318
|
};
|
|
76359
77319
|
}
|
|
76360
77320
|
function toLeg(pos) {
|
|
76361
|
-
const depositsUsd =
|
|
76362
|
-
const debtUsd =
|
|
76363
|
-
const hasSupply = depositsUsd !== 0 ||
|
|
76364
|
-
const hasDebt = debtUsd !== 0 ||
|
|
77321
|
+
const depositsUsd = num18(pos.depositsUSD);
|
|
77322
|
+
const debtUsd = num18(pos.debtUSD) + num18(pos.debtStableUSD);
|
|
77323
|
+
const hasSupply = depositsUsd !== 0 || num18(pos.deposits) !== 0;
|
|
77324
|
+
const hasDebt = debtUsd !== 0 || num18(pos.debt) !== 0 || num18(pos.debtStable) !== 0;
|
|
76365
77325
|
return {
|
|
76366
77326
|
earnUid: legEarnUid(pos.marketUid),
|
|
76367
77327
|
marketUid: pos.marketUid,
|
|
@@ -76401,12 +77361,12 @@ function earnPositionFromLenderEntry(entry) {
|
|
|
76401
77361
|
(s) => s.legs.some((l) => l.side !== "none") || s.netUsd !== 0
|
|
76402
77362
|
);
|
|
76403
77363
|
const crossMargin = active.length <= 1;
|
|
76404
|
-
const suppliedUsd =
|
|
76405
|
-
const borrowedUsd =
|
|
77364
|
+
const suppliedUsd = num18(entry.balanceData?.deposits);
|
|
77365
|
+
const borrowedUsd = num18(entry.balanceData?.debt);
|
|
76406
77366
|
const aprBreakdown = {
|
|
76407
|
-
market:
|
|
76408
|
-
rewards:
|
|
76409
|
-
intrinsic:
|
|
77367
|
+
market: num18(entry.aprData?.apr),
|
|
77368
|
+
rewards: num18(entry.aprData?.rewardApr),
|
|
77369
|
+
intrinsic: num18(entry.aprData?.intrinsicApr)
|
|
76410
77370
|
};
|
|
76411
77371
|
return {
|
|
76412
77372
|
positionUid: buildLendingPositionUid(entry.lender, entry.chainId),
|
|
@@ -76420,15 +77380,15 @@ function earnPositionFromLenderEntry(entry) {
|
|
|
76420
77380
|
...entry.lenderInfo?.logoUri ? { logoURI: entry.lenderInfo.logoUri } : {},
|
|
76421
77381
|
suppliedUsd,
|
|
76422
77382
|
borrowedUsd,
|
|
76423
|
-
netUsd:
|
|
77383
|
+
netUsd: num18(entry.balanceData?.nav),
|
|
76424
77384
|
apr: aprBreakdown.market + aprBreakdown.rewards + aprBreakdown.intrinsic,
|
|
76425
77385
|
aprBreakdown,
|
|
76426
|
-
depositApr:
|
|
76427
|
-
borrowApr:
|
|
77386
|
+
depositApr: num18(entry.aprData?.depositApr),
|
|
77387
|
+
borrowApr: num18(entry.aprData?.borrowApr),
|
|
76428
77388
|
// Only a cross-margin account HAS one health factor. Publishing the first
|
|
76429
77389
|
// sub-account's as the row's would be a number about a different position.
|
|
76430
77390
|
health: crossMargin ? active[0]?.health ?? null : null,
|
|
76431
|
-
leverage:
|
|
77391
|
+
leverage: num18(entry.leverage),
|
|
76432
77392
|
crossMargin,
|
|
76433
77393
|
legs: subAccounts.flatMap((s) => s.legs),
|
|
76434
77394
|
subAccounts: active,
|