@1delta/margin-fetcher 5.0.53 → 5.0.54

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 CHANGED
@@ -12179,12 +12179,23 @@ interface EarnExclusions {
12179
12179
  lowTvl: number;
12180
12180
  /** Above the risk ceiling the rest of the API also applies. */
12181
12181
  highRisk: number;
12182
+ /**
12183
+ * Rows whose position is a multi-token LP (`basket`), hidden by default.
12184
+ *
12185
+ * Excluded unasked because the row names ONE token while the position holds
12186
+ * several in a split the pool keeps moving — so a depositor reading it as
12187
+ * "USDC at 10 %" ends up carrying the other leg's price risk. Reported here
12188
+ * so a UI can offer `?lp=include` rather than let the rows vanish silently.
12189
+ */
12190
+ lp: number;
12182
12191
  }
12183
12192
  interface EarnAppliedDefaults {
12184
12193
  minTvlUsd: number;
12185
12194
  maxRiskScore: number;
12186
12195
  excludePassthrough: boolean;
12187
12196
  excludeIlliquid: boolean;
12197
+ /** LP / auto-rebalancing positions are hidden unless `?lp=include`. */
12198
+ excludeLp: boolean;
12188
12199
  }
12189
12200
  /**
12190
12201
  * The filter vocabulary, published rather than hard-coded.
package/dist/index.js CHANGED
@@ -19476,6 +19476,10 @@ function parseVault(vault, chainId, prices, additionalYields, tokenList, liquidi
19476
19476
  }
19477
19477
  return value > 0 ? weighted / value : legs[0]?.rate ?? 0;
19478
19478
  };
19479
+ const smartLegTokens = /* @__PURE__ */ new Set([
19480
+ ...isSmartCol ? colLegs.map((l) => l.token.toLowerCase()) : [],
19481
+ ...isSmartDebt ? debtLegs.map((l) => l.token.toLowerCase()) : []
19482
+ ]);
19479
19483
  const basketSupplyRate = isSmartCol ? basketRate(colLegs) : void 0;
19480
19484
  const basketBorrowRate = isSmartDebt ? basketRate(debtLegs) : void 0;
19481
19485
  const irmTotals = (state, decimals) => state ? {
@@ -19564,7 +19568,7 @@ function parseVault(vault, chainId, prices, additionalYields, tokenList, liquidi
19564
19568
  * NOT the position's rate (use the basket rate); and an exit has to be
19565
19569
  * sized in shares rather than in this token.
19566
19570
  */
19567
- ...isSmartVault ? { autoBalanced: true } : {},
19571
+ ...smartLegTokens.has(leg.token.toLowerCase()) ? { autoBalanced: true } : {},
19568
19572
  fluid: isSmartVault ? {
19569
19573
  vaultType,
19570
19574
  /**
@@ -24647,6 +24651,7 @@ async function fetchTwyneMarkets(lender, chainId) {
24647
24651
  allowFailure: true
24648
24652
  });
24649
24653
  const out = [];
24654
+ const pendingDebtBalances = [];
24650
24655
  markets.forEach((m, i) => {
24651
24656
  const c = i * 8;
24652
24657
  const creditTotalAssets = big3(creditReads[c]);
@@ -24660,6 +24665,7 @@ async function fetchTwyneMarkets(lender, chainId) {
24660
24665
  let externalSupplyRate;
24661
24666
  let externalBorrowRate;
24662
24667
  let externalBorrowLiquidity;
24668
+ let debtAToken;
24663
24669
  if (aaveIdx >= 0) {
24664
24670
  const emode = aaveEmode[aaveIdx];
24665
24671
  const collReserve = aaveReserves6[aaveIdx * 2];
@@ -24669,6 +24675,12 @@ async function fetchTwyneMarkets(lender, chainId) {
24669
24675
  externalSupplyRate = Number(collReserve.currentLiquidityRate) / RAY4;
24670
24676
  if (ok(debtReserve) && debtReserve?.currentVariableBorrowRate !== void 0)
24671
24677
  externalBorrowRate = Number(debtReserve.currentVariableBorrowRate) / RAY4;
24678
+ if (ok(debtReserve)) {
24679
+ const virtual = big3(debtReserve.virtualUnderlyingBalance);
24680
+ if (virtual !== void 0 && virtual > 0n) externalBorrowLiquidity = virtual;
24681
+ else if (typeof debtReserve.aTokenAddress === "string")
24682
+ debtAToken = debtReserve.aTokenAddress;
24683
+ }
24672
24684
  } else if (eulerIdx >= 0) {
24673
24685
  const e = eulerIdx * 7;
24674
24686
  externalLiqLtv = big3(eulerReads[e]);
@@ -24685,7 +24697,10 @@ async function fetchTwyneMarkets(lender, chainId) {
24685
24697
  }
24686
24698
  }
24687
24699
  const s = i * 3;
24688
- if (externalBorrowLiquidity === void 0) externalBorrowLiquidity = big3(scaleReads[s + 2]);
24700
+ if (externalBorrowLiquidity === void 0 && !debtAToken) {
24701
+ externalBorrowLiquidity = big3(scaleReads[s + 2]);
24702
+ }
24703
+ if (debtAToken) pendingDebtBalances.push({ index: out.length, token: m.targetAsset, holder: debtAToken });
24689
24704
  out.push({
24690
24705
  market: m,
24691
24706
  creditTotalAssets,
@@ -24711,6 +24726,22 @@ async function fetchTwyneMarkets(lender, chainId) {
24711
24726
  paused
24712
24727
  });
24713
24728
  });
24729
+ if (pendingDebtBalances.length > 0) {
24730
+ const balances = await multicallRetryUniversal({
24731
+ chain: chainId,
24732
+ calls: pendingDebtBalances.map((p) => ({
24733
+ address: p.token,
24734
+ name: "balanceOf",
24735
+ args: [p.holder]
24736
+ })),
24737
+ abi: ERC20_ABI,
24738
+ allowFailure: true
24739
+ });
24740
+ pendingDebtBalances.forEach((p, i) => {
24741
+ const v = big3(balances[i]);
24742
+ if (v !== void 0 && out[p.index]) out[p.index].externalBorrowLiquidity = v;
24743
+ });
24744
+ }
24714
24745
  if (out.length === 0) return void 0;
24715
24746
  return { lender, chainId, config, markets: out };
24716
24747
  }
@@ -72456,7 +72487,10 @@ var twyneAdapter = {
72456
72487
  description: [
72457
72488
  `Your collateral stays in ${externalName}; Twyne only reserves other lenders\u2019 unused borrowing power so the same collateral supports a larger loan.`,
72458
72489
  bandNote,
72459
- creditApr != null ? `On top of ${externalName}\u2019s borrow rate you pay ${creditApr.toFixed(3)} % a year on the RESERVED CREDIT only \u2014 not on your debt \u2014 and it is charged in the collateral asset.` : void 0
72490
+ creditApr != null ? `On top of ${externalName}\u2019s borrow rate you pay ${creditApr.toFixed(3)} % a year on the RESERVED CREDIT only \u2014 not on your debt \u2014 and it is charged in the collateral asset.` : void 0,
72491
+ // The loan is perpetual; the COLLATERAL is what expires. Said here
72492
+ // rather than in `maturity`, which would mis-type the loan itself.
72493
+ maturity != null && matured ? "This market\u2019s collateral has already matured. Existing positions can still be repaid and closed, but nothing new should be opened against it." : maturity != null ? `Your loan has no end date, but the collateral is a fixed-maturity token that stops accreting on ${new Date(maturity * 1e3).toISOString().slice(0, 10)}, and ${externalName}\u2019s risk parameters move as that date approaches.` : void 0
72460
72494
  ].filter(Boolean).join(" ")
72461
72495
  },
72462
72496
  availability: {
@@ -72490,21 +72524,20 @@ var twyneAdapter = {
72490
72524
  description: `Twyne liquidates first, above your chosen LTV. ${externalName}\u2019s own threshold of ${pct2(externalLiqLtv)} is the backstop, and reaching it is the bad case.`
72491
72525
  } : {}
72492
72526
  },
72493
- // The collateral has a maturity even though the loan does not — a PT
72494
- // stops accreting at expiry and the external threshold ramps out from
72495
- // under it, so this is a date the borrower has to act on.
72496
- ...maturity ? {
72497
- maturity: {
72498
- kind: "fixed-date",
72499
- maturity,
72500
- maturityIso: new Date(maturity * 1e3).toISOString(),
72501
- ...matured ? {
72502
- description: "This market\u2019s collateral has already matured. Existing positions can still be repaid and closed, but no new borrowing should be opened against it."
72503
- } : {
72504
- description: "The collateral is a fixed-maturity token. The loan itself has no end date, but the collateral stops accreting at maturity and the underlying market\u2019s risk parameters move as that date approaches."
72505
- }
72506
- }
72507
- } : {}
72527
+ // THE LOAN IS PERPETUAL. Only the COLLATERAL expires.
72528
+ //
72529
+ // The first version of this adapter put the PT's expiry on
72530
+ // `borrow.maturity` with `kind: 'fixed-date'`, and that is wrong in a
72531
+ // way that shows up immediately in a UI: every consumer reads that field
72532
+ // as "this is a fixed-TERM loan", so the market rendered with a `Fixed`
72533
+ // borrow-rate badge and no APR — a fixed-rate product Twyne does not
72534
+ // offer. A Twyne loan has no end date, no rollover and no settlement;
72535
+ // it accrues at the external market's variable rate until repaid.
72536
+ //
72537
+ // What the collateral's expiry actually means is carried where it
72538
+ // belongs: `twyne.collateralMaturity` / `collateralMatured` on the
72539
+ // market descriptor (computed at read time), and stated in prose here.
72540
+ maturity: { kind: "perpetual" }
72508
72541
  }
72509
72542
  };
72510
72543
  }
@@ -73109,6 +73142,10 @@ function resolveBasket(row) {
73109
73142
  const f = row.fluid;
73110
73143
  if (f && f.isSmartCol !== true) return void 0;
73111
73144
  const legs = (f?.collateralPair ?? []).map((a) => addr3(a)).filter((a) => !!a).map((address) => ({ address }));
73145
+ if (legs.length > 0) {
73146
+ const rowAsset = addr3(row.underlying) ?? addr3(row.asset?.address);
73147
+ if (!rowAsset || !legs.some((l) => l.address === rowAsset)) return void 0;
73148
+ }
73112
73149
  return {
73113
73150
  // Fluid emits one row PER LEG of the pool, so this row is a leg and a
73114
73151
  // consumer that sums the listing without deduping counts the position