@1delta/margin-fetcher 0.0.403 → 0.0.404

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
@@ -329,6 +329,76 @@ interface FixedTermProvider {
329
329
  /** The single counterparty/venue contract, when there is one (Lista broker, Term servicer). */
330
330
  address?: string;
331
331
  }
332
+ /**
333
+ * Origination window for a fixed-term market whose terms are only obtainable
334
+ * during a bounded round rather than continuously (`provider.kind: 'auction'`
335
+ * — Term Finance).
336
+ *
337
+ * This is the difference between "the rate card is empty right now" and "this
338
+ * market is dead": between rounds a Term repo still has a maturity, collateral
339
+ * params and a last-cleared rate, but nothing can be borrowed until the next
340
+ * round is listed. Without it every closed repo renders as an ordinary
341
+ * borrowable market whose action silently cannot be built.
342
+ *
343
+ * `status` is a snapshot at fetch time; the timestamps are raw so a consumer
344
+ * can re-derive it live (and drive a countdown) against a cached response.
345
+ */
346
+ interface FixedTermAuction {
347
+ /**
348
+ * Round lifecycle at fetch time:
349
+ * - `upcoming` — listed but not yet accepting submissions (`now < startTime`)
350
+ * - `open` — accepting sealed bids/offers (`startTime ≤ now < revealTime`)
351
+ * - `revealing` — submissions closed, prices revealing / clearing pending
352
+ * (`revealTime ≤ now < endTime`)
353
+ * - `closed` — no round is currently listed for this market. Borrowing is
354
+ * unavailable until the next one; lending may still be
355
+ * possible on the secondary repo-token book.
356
+ */
357
+ status: 'upcoming' | 'open' | 'revealing' | 'closed';
358
+ /**
359
+ * Can a NEW borrow be opened right now? True only inside an open round —
360
+ * Term borrow origination is a sealed bid, so there is no other entry point.
361
+ *
362
+ * Consume this rather than re-deriving from `status`: it is the single flag
363
+ * a borrow CTA should gate on, and it stays correct if more statuses appear.
364
+ * It is NOT the same as `canLend` — see below.
365
+ */
366
+ canBorrow: boolean;
367
+ /**
368
+ * Can a NEW lend position be opened right now? Deliberately decoupled from
369
+ * `canBorrow`: the primary auction is only one of two lend surfaces, and
370
+ * buying repo tokens on the secondary book works between rounds. So a closed
371
+ * round leaves the market lend-only rather than fully inert, and a UI that
372
+ * greys out the whole market would be wrong.
373
+ */
374
+ canLend: boolean;
375
+ /**
376
+ * Seconds until submissions close (`revealTime − now`), or undefined when no
377
+ * round is open. A snapshot — for a live countdown, derive from `revealTime`.
378
+ */
379
+ secondsUntilClose?: number;
380
+ /**
381
+ * Ready-to-display consequences of this market's origination model, most
382
+ * important first. Mirrors `params.market.teller.implications`: auction
383
+ * mechanics are unusual enough that a UI showing only a rate misleads.
384
+ */
385
+ implications?: string[];
386
+ /** Round id. Absent when `status: 'closed'`. */
387
+ id?: string;
388
+ /** Submissions open (unix seconds). Absent when `status: 'closed'`. */
389
+ startTime?: number;
390
+ /** Submissions CLOSE / reveal begins (unix seconds). Absent when closed. */
391
+ revealTime?: number;
392
+ /** Round clears (unix seconds). Absent when closed. */
393
+ endTime?: number;
394
+ /**
395
+ * Minimum submission size in loan-token base units (raw). Term rounds carry a
396
+ * real floor (e.g. 1000 USDC) — an amount below it cannot be submitted at all,
397
+ * so it belongs next to the terms rather than surfacing as a failed action.
398
+ */
399
+ minBorrowAmount?: string;
400
+ minLendAmount?: string;
401
+ }
332
402
  /**
333
403
  * Canonical fixed-term market descriptor, emitted on `params.market.fixedTerm`
334
404
  * for EVERY fixed-rate / fixed-maturity market (Lista brokered + Morpho
@@ -367,6 +437,12 @@ interface FixedTermInfo {
367
437
  earlyRepay: FixedTermEarlyRepay;
368
438
  /** Who offers the term (Lista broker vs Midnight order book). */
369
439
  provider?: FixedTermProvider;
440
+ /**
441
+ * Origination window, for `provider.kind: 'auction'` markets only (Term
442
+ * Finance). Absent for lenders whose terms are continuously available — a
443
+ * missing `auction` means "no window applies", NOT "closed".
444
+ */
445
+ auction?: FixedTermAuction;
370
446
  }
371
447
  /** A Lista loan, attached to its own entry in the positions array. */
372
448
  interface ListaTermLoan {
@@ -2234,14 +2310,48 @@ interface TermBookSource {
2234
2310
  getTopAndBook?(config: TermMarketConfig, maxLevels?: number): Promise<{
2235
2311
  top: TermBookTop;
2236
2312
  book: TermBook;
2313
+ /** Live/upcoming auction round; null when none is listed. */
2314
+ auction: TermAuctionWindow | null;
2237
2315
  } | null>;
2238
2316
  }
2317
+ /**
2318
+ * The repo's CURRENT primary auction round, when one is listed.
2319
+ *
2320
+ * Term borrow origination is a periodic sealed-bid auction, not a continuous
2321
+ * book: outside the submission window there is nothing to bid on, so a repo
2322
+ * whose auction has cleared is lend-only (buy repo tokens on the secondary
2323
+ * book) until the next round is listed. Timestamps are raw so consumers can
2324
+ * derive a live countdown; `status` is a snapshot at fetch time.
2325
+ */
2326
+ interface TermAuctionWindow {
2327
+ /** Auction round id (the TermAuction entity id). */
2328
+ id: string;
2329
+ /** Submissions open (unix seconds). */
2330
+ startTime: number;
2331
+ /** Submissions CLOSE and the sealed prices start revealing (unix seconds). */
2332
+ revealTime: number;
2333
+ /** Auction clears (unix seconds). Equal to `revealTime` on current deployments. */
2334
+ endTime: number;
2335
+ /** Minimum bid (borrow) size, loan-token base units (raw string; '0' when unset). */
2336
+ minBidAmount: string;
2337
+ /** Minimum offer (lend) size, loan-token base units (raw string; '0' when unset). */
2338
+ minOfferAmount: string;
2339
+ /** Highest accepted bid rate, WAD (raw string; '0' when unset). */
2340
+ maxBidPriceWad: string;
2341
+ /** Highest accepted offer rate, WAD (raw string; '0' when unset). */
2342
+ maxOfferPriceWad: string;
2343
+ }
2239
2344
  /** A Term repo paired with its current top-of-book (null when the fetch failed). */
2240
2345
  interface TermMarketRaw {
2241
2346
  config: TermMarketConfig;
2242
2347
  top: TermBookTop | null;
2243
2348
  /** Bounded book slice (top-N levels/side); null/absent when unavailable. */
2244
2349
  book?: TermBook | null;
2350
+ /**
2351
+ * The live/upcoming auction round, or null when no round is currently listed
2352
+ * (the common case between auctions — the repo is then lend-only).
2353
+ */
2354
+ auction?: TermAuctionWindow | null;
2245
2355
  }
2246
2356
 
2247
2357
  /**
@@ -2287,15 +2397,24 @@ declare class TermSubgraphSource implements TermBookSource {
2287
2397
  getBookTop(config: TermMarketConfig): Promise<TermBookTop | null>;
2288
2398
  /**
2289
2399
  * ONE query → the aggregate top (best APR + FULL depth) PLUS a bounded book
2290
- * slice (top `maxLevels` open orders per side). `asks` = orders selling repo
2291
- * tokens (the secondary LEND book); `bids` = the rest (borrow side, usually
2292
- * empty Term borrow is sealed-bid auction, not a continuous book). Term
2293
- * secondary orders carry no per-order rate, so every level shares the market's
2294
- * clearing APR; the levels expose per-order SIZE for filtering.
2400
+ * slice (top `maxLevels` open orders per side) PLUS the repo's current
2401
+ * auction round. `asks` = orders selling repo tokens (the secondary LEND
2402
+ * book); `bids` = the rest (borrow side, usually empty Term borrow is
2403
+ * sealed-bid auction, not a continuous book). Term secondary orders carry no
2404
+ * per-order rate, so every level shares the market's clearing APR; the levels
2405
+ * expose per-order SIZE for filtering.
2406
+ *
2407
+ * Two auction reads, deliberately distinct:
2408
+ * - `cleared` — the latest COMPLETE round, whose clearing price IS the
2409
+ * market's fixed APR (and stays the reference rate between auctions).
2410
+ * - `pending` — rounds not yet complete/cancelled. Only one of these is a
2411
+ * real, actionable round; the rest are abandoned listings the subgraph
2412
+ * never marked complete, filtered out below.
2295
2413
  */
2296
2414
  getTopAndBook(config: TermMarketConfig, maxLevels?: number): Promise<{
2297
2415
  top: TermBookTop;
2298
2416
  book: TermBook;
2417
+ auction: TermAuctionWindow | null;
2299
2418
  } | null>;
2300
2419
  getListings(config: TermMarketConfig): Promise<TermListing[] | null>;
2301
2420
  /**
package/dist/index.js CHANGED
@@ -21470,6 +21470,20 @@ var toBig3 = (v) => {
21470
21470
  return 0n;
21471
21471
  }
21472
21472
  };
21473
+ function pickAuction(rows, nowSec7 = Math.floor(Date.now() / 1e3)) {
21474
+ if (!Array.isArray(rows) || rows.length === 0) return null;
21475
+ const live = rows.filter((a) => a && !a.delisted && !a.nonViableAuction).map((a) => ({
21476
+ id: String(a.id ?? ""),
21477
+ startTime: toNum(a.auctionStartTime),
21478
+ revealTime: toNum(a.revealTime),
21479
+ endTime: toNum(a.auctionEndTime),
21480
+ minBidAmount: String(a.auctionMinBidAmount ?? "0"),
21481
+ minOfferAmount: String(a.auctionMinOfferAmount ?? "0"),
21482
+ maxBidPriceWad: String(a.auctionMaxBidPrice ?? "0"),
21483
+ maxOfferPriceWad: String(a.auctionMaxOfferPrice ?? "0")
21484
+ })).filter((a) => a.endTime > nowSec7).sort((a, b) => a.endTime - b.endTime);
21485
+ return live[0] ?? null;
21486
+ }
21473
21487
  var TermSubgraphSource = class {
21474
21488
  url;
21475
21489
  fetchImpl;
@@ -21504,29 +21518,54 @@ var TermSubgraphSource = class {
21504
21518
  }
21505
21519
  /**
21506
21520
  * ONE query → the aggregate top (best APR + FULL depth) PLUS a bounded book
21507
- * slice (top `maxLevels` open orders per side). `asks` = orders selling repo
21508
- * tokens (the secondary LEND book); `bids` = the rest (borrow side, usually
21509
- * empty Term borrow is sealed-bid auction, not a continuous book). Term
21510
- * secondary orders carry no per-order rate, so every level shares the market's
21511
- * clearing APR; the levels expose per-order SIZE for filtering.
21521
+ * slice (top `maxLevels` open orders per side) PLUS the repo's current
21522
+ * auction round. `asks` = orders selling repo tokens (the secondary LEND
21523
+ * book); `bids` = the rest (borrow side, usually empty Term borrow is
21524
+ * sealed-bid auction, not a continuous book). Term secondary orders carry no
21525
+ * per-order rate, so every level shares the market's clearing APR; the levels
21526
+ * expose per-order SIZE for filtering.
21527
+ *
21528
+ * Two auction reads, deliberately distinct:
21529
+ * - `cleared` — the latest COMPLETE round, whose clearing price IS the
21530
+ * market's fixed APR (and stays the reference rate between auctions).
21531
+ * - `pending` — rounds not yet complete/cancelled. Only one of these is a
21532
+ * real, actionable round; the rest are abandoned listings the subgraph
21533
+ * never marked complete, filtered out below.
21512
21534
  */
21513
21535
  async getTopAndBook(config, maxLevels = 20) {
21514
21536
  const id = config.termRepoId.toLowerCase();
21515
21537
  const repoToken = config.repoToken.toLowerCase();
21516
21538
  const data = await this.gql(
21517
- `query Top($id: ID!, $repoId: Bytes!) {
21539
+ `query Top($id: ID!, $termId: String!, $repoId: Bytes!) {
21518
21540
  termRepo(id: $id) { termRepoTokenRedemptionRatio }
21519
21541
  termAuctions(where: { term: $id, auctionComplete: true }, orderBy: auctionEndTime, orderDirection: desc, first: 1) {
21520
21542
  auctionClearingPrice
21521
21543
  dayCountFractionMantissa
21522
21544
  }
21545
+ pending: termAuctions(
21546
+ where: { term: $termId, auctionComplete: false, auctionCancelled: false }
21547
+ orderBy: auctionEndTime
21548
+ orderDirection: desc
21549
+ first: 5
21550
+ ) {
21551
+ id
21552
+ auctionStartTime
21553
+ revealTime
21554
+ auctionEndTime
21555
+ delisted
21556
+ nonViableAuction
21557
+ auctionMinBidAmount
21558
+ auctionMinOfferAmount
21559
+ auctionMaxBidPrice
21560
+ auctionMaxOfferPrice
21561
+ }
21523
21562
  termOrders(where: { termRepoId: $repoId, orderCancelled: false }, first: 500) {
21524
21563
  makerToken
21525
21564
  originalOrderAmount
21526
21565
  filledAmount
21527
21566
  }
21528
21567
  }`,
21529
- { id, repoId: id }
21568
+ { id, termId: id, repoId: id }
21530
21569
  );
21531
21570
  if (!data) return null;
21532
21571
  const redemptionRatio = toBig3(data.termRepo?.termRepoTokenRedemptionRatio) || BigInt(WAD3);
@@ -21563,7 +21602,7 @@ var TermSubgraphSource = class {
21563
21602
  supplyLiquidity: toLoan(supplyUnits),
21564
21603
  borrowLiquidity: toLoan(borrowUnits)
21565
21604
  };
21566
- return { top, book: { bids, asks } };
21605
+ return { top, book: { bids, asks }, auction: pickAuction(data.pending) };
21567
21606
  }
21568
21607
  async getListings(config) {
21569
21608
  const id = config.termRepoId.toLowerCase();
@@ -21672,17 +21711,23 @@ async function fetchTopAndBookWithFallback2(source, chainId, config, nowSec7) {
21672
21711
  fresh = await source.getTopAndBook(config, TERM_BOOK_LEVELS).catch(() => null);
21673
21712
  } else {
21674
21713
  const top = await source.getBookTop(config).catch(() => null);
21675
- if (top) fresh = { top, book: { bids: [], asks: [] } };
21714
+ if (top) fresh = { top, book: { bids: [], asks: [] }, auction: null };
21676
21715
  }
21677
21716
  if (fresh) {
21678
- lastGood2.set(key, { top: fresh.top, book: fresh.book, at: nowSec7 });
21679
- return { top: fresh.top, book: fresh.book };
21717
+ lastGood2.set(key, {
21718
+ top: fresh.top,
21719
+ book: fresh.book,
21720
+ auction: fresh.auction ?? null,
21721
+ at: nowSec7
21722
+ });
21723
+ return { top: fresh.top, book: fresh.book, auction: fresh.auction ?? null };
21680
21724
  }
21681
21725
  const cached = lastGood2.get(key);
21682
21726
  if (cached && nowSec7 - cached.at <= LKG_TTL_SEC2) {
21683
- return { top: cached.top, book: cached.book };
21727
+ const stillOpen = cached.auction && cached.auction.endTime > nowSec7 ? cached.auction : null;
21728
+ return { top: cached.top, book: cached.book, auction: stillOpen };
21684
21729
  }
21685
- return { top: null, book: null };
21730
+ return { top: null, book: null, auction: null };
21686
21731
  }
21687
21732
  async function fetchTermMarkets(chainId, source = createTermBookSource(chainId)) {
21688
21733
  const markets = termMarketsByChain(chainId);
@@ -21691,15 +21736,15 @@ async function fetchTermMarkets(chainId, source = createTermBookSource(chainId))
21691
21736
  return Promise.all(
21692
21737
  markets.map(async (config) => {
21693
21738
  if (Number(config.maturity) <= nowSec7) {
21694
- return { config, top: null, book: null };
21739
+ return { config, top: null, book: null, auction: null };
21695
21740
  }
21696
- const { top, book } = await fetchTopAndBookWithFallback2(
21741
+ const { top, book, auction } = await fetchTopAndBookWithFallback2(
21697
21742
  source,
21698
21743
  chainId,
21699
21744
  config,
21700
21745
  nowSec7
21701
21746
  );
21702
- return { config, top, book };
21747
+ return { config, top, book, auction };
21703
21748
  })
21704
21749
  );
21705
21750
  }
@@ -21733,6 +21778,76 @@ function termLenderKey(termRepoId) {
21733
21778
  const body = termRepoId.startsWith("0x") ? termRepoId.slice(2) : termRepoId;
21734
21779
  return "TERM_FINANCE_" + body.toUpperCase();
21735
21780
  }
21781
+ function fmtDuration(secs) {
21782
+ if (secs >= 2 * 86400) return `${Math.round(secs / 86400)} days`;
21783
+ if (secs >= 2 * 3600) return `${Math.round(secs / 3600)} hours`;
21784
+ return `${Math.max(1, Math.round(secs / 60))} minutes`;
21785
+ }
21786
+ function auctionImplications(status, matured, secondsUntilClose) {
21787
+ const out = [];
21788
+ if (matured) {
21789
+ out.push(
21790
+ "This term has MATURED \u2014 it can no longer be borrowed or lent. Existing positions settle through the repurchase/redemption window."
21791
+ );
21792
+ return out;
21793
+ }
21794
+ if (status === "open") {
21795
+ out.push(
21796
+ `\u26A0 Borrowing is a SEALED BID into an auction, not an instant loan. Submissions close in ${secondsUntilClose != null ? fmtDuration(secondsUntilClose) : "a limited window"}; after that nothing can be borrowed until the next round is listed.`
21797
+ );
21798
+ out.push(
21799
+ "Your rate is NOT the rate shown \u2014 the shown figure is the last round\u2019s clearing rate. Your actual rate is set when this round clears, and a bid above the clearing rate may not be filled at all."
21800
+ );
21801
+ } else if (status === "revealing") {
21802
+ out.push(
21803
+ "\u26A0 Bidding has CLOSED for this round \u2014 sealed prices are being revealed and the auction is clearing. No new borrows until the next round is listed."
21804
+ );
21805
+ } else if (status === "upcoming") {
21806
+ out.push(
21807
+ "An auction round is scheduled but not yet accepting bids. Borrowing becomes possible when it opens."
21808
+ );
21809
+ } else {
21810
+ out.push(
21811
+ "\u26A0 NO auction is open, so this market CANNOT be borrowed right now. Term originates loans only during scheduled sealed-bid auctions."
21812
+ );
21813
+ out.push(
21814
+ "Any borrow rate shown is the last round\u2019s clearing rate \u2014 historical, not obtainable."
21815
+ );
21816
+ }
21817
+ out.push(
21818
+ "Lending is still possible between rounds by buying repo tokens on the secondary market; only borrowing depends on the auction window."
21819
+ );
21820
+ out.push(
21821
+ "Fixed maturity: the debt is a static face value with no interest accrual, repayable up to the end of the repurchase window."
21822
+ );
21823
+ return out;
21824
+ }
21825
+ function toFixedTermAuction(auction, now, matured = false) {
21826
+ const base = { canBorrow: false, canLend: !matured };
21827
+ if (!auction || auction.endTime <= now) {
21828
+ return {
21829
+ status: "closed",
21830
+ ...base,
21831
+ implications: auctionImplications("closed", matured)
21832
+ };
21833
+ }
21834
+ const status = now < auction.startTime ? "upcoming" : now < auction.revealTime ? "open" : "revealing";
21835
+ const secondsUntilClose = status === "open" ? Math.max(0, auction.revealTime - now) : void 0;
21836
+ return {
21837
+ status,
21838
+ ...base,
21839
+ // A matured repo is never borrowable, whatever the round says.
21840
+ canBorrow: status === "open" && !matured,
21841
+ secondsUntilClose,
21842
+ implications: auctionImplications(status, matured, secondsUntilClose),
21843
+ id: auction.id,
21844
+ startTime: auction.startTime,
21845
+ revealTime: auction.revealTime,
21846
+ endTime: auction.endTime,
21847
+ minBorrowAmount: auction.minBidAmount,
21848
+ minLendAmount: auction.minOfferAmount
21849
+ };
21850
+ }
21736
21851
  function currencyFor2(address, decimals, tokens) {
21737
21852
  const lower = address.toLowerCase();
21738
21853
  return tokens[lower] ?? { address: lower, symbol: "", name: "", decimals };
@@ -21744,7 +21859,7 @@ function convertTermMarketsToResponse(raw, chainId, prices = {}, _additionalYiel
21744
21859
  }, tokens = {}) {
21745
21860
  const out = {};
21746
21861
  const now = nowSec2();
21747
- for (const { config, top, book } of raw) {
21862
+ for (const { config, top, book, auction } of raw) {
21748
21863
  if (!config?.termRepoId || !config.purchaseToken) continue;
21749
21864
  const m = termLenderKey(config.termRepoId);
21750
21865
  const maturity = Number(config.maturity);
@@ -21752,7 +21867,9 @@ function convertTermMarketsToResponse(raw, chainId, prices = {}, _additionalYiel
21752
21867
  const matured = ttm <= 0;
21753
21868
  const supplyAprPct = !matured ? top?.supplyAprPct ?? 0 : 0;
21754
21869
  const borrowAprPct = !matured ? top?.borrowAprPct ?? 0 : 0;
21755
- const terms = borrowAprPct > 0 && !matured ? [
21870
+ const auctionInfo = toFixedTermAuction(auction, now, matured);
21871
+ const auctionOpen = auctionInfo.canBorrow;
21872
+ const terms = borrowAprPct > 0 && auctionOpen ? [
21756
21873
  {
21757
21874
  termId: 0,
21758
21875
  durationSecs: Math.max(0, ttm),
@@ -21807,10 +21924,15 @@ function convertTermMarketsToResponse(raw, chainId, prices = {}, _additionalYiel
21807
21924
  },
21808
21925
  closeFactor: 1,
21809
21926
  collateralActive: false,
21810
- borrowingEnabled: !matured,
21811
- depositsEnabled: !matured,
21927
+ // Borrow needs a LIVE auction round, not just an unmatured repo.
21928
+ // `depositsEnabled` stays on the maturity alone: lending is also possible
21929
+ // between rounds by buying repo tokens on the secondary book.
21930
+ borrowingEnabled: auctionOpen,
21931
+ depositsEnabled: auctionInfo.canLend,
21812
21932
  hasStable: false,
21813
- variableBorrowDisabled: false,
21933
+ // Term has no variable rate at all; between auctions there is no
21934
+ // borrowable rate either, so flag it rather than let a 0 read as free.
21935
+ variableBorrowDisabled: true,
21814
21936
  isActive: true,
21815
21937
  isFrozen: false
21816
21938
  };
@@ -21893,7 +22015,11 @@ function convertTermMarketsToResponse(raw, chainId, prices = {}, _additionalYiel
21893
22015
  earlyRepay: { kind: "none" },
21894
22016
  // Fixed rate is discovered by the periodic sealed-bid auction; the
21895
22017
  // per-repo servicer is the market-level venue reference.
21896
- provider: { kind: "auction", address: config.servicer }
22018
+ provider: { kind: "auction", address: config.servicer },
22019
+ // The origination window. `closed` (the common state between rounds)
22020
+ // is what tells a consumer that this market is display-only right
22021
+ // now, rather than an ordinary market with an empty rate card.
22022
+ auction: auctionInfo
21897
22023
  },
21898
22024
  collateralParams: config.collateralParams,
21899
22025
  // Bounded book slice (top-N open orders/side) for later filtering. Term
@@ -22883,7 +23009,7 @@ function currencyFor6(address, decimals, symbol, tokens) {
22883
23009
  const lower = address.toLowerCase();
22884
23010
  return tokens[lower] ?? { address: lower, symbol, name: symbol, decimals };
22885
23011
  }
22886
- function fmtDuration(sec) {
23012
+ function fmtDuration2(sec) {
22887
23013
  if (sec == null || sec <= 0) return "a short window";
22888
23014
  if (sec < 3600) return `${Math.round(sec / 60)} minute${sec < 120 ? "" : "s"}`;
22889
23015
  if (sec < 86400) return `${Math.round(sec / 3600)} hour${sec < 7200 ? "" : "s"}`;
@@ -23049,7 +23175,7 @@ function convertTellerMarketsToResponse(raw, chainId, prices = {}, _additionalYi
23049
23175
  const originationFeeBps = marketFeeBps + protocolFeeBps;
23050
23176
  const originationFeePercent = originationFeeBps / 100;
23051
23177
  const graceSec = p.paymentDefaultDuration;
23052
- const graceHuman = fmtDuration(graceSec);
23178
+ const graceHuman = fmtDuration2(graceSec);
23053
23179
  const ltvPct = ltv > 0 ? Math.round(ltv * 100) : void 0;
23054
23180
  const lossX = ltv > 0 ? (1 / ltv).toFixed(1) : void 0;
23055
23181
  const implications = [];