@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 +124 -5
- package/dist/index.js +150 -24
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
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)
|
|
2291
|
-
*
|
|
2292
|
-
*
|
|
2293
|
-
*
|
|
2294
|
-
* clearing APR; the levels
|
|
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)
|
|
21508
|
-
*
|
|
21509
|
-
*
|
|
21510
|
-
*
|
|
21511
|
-
* clearing APR; the levels
|
|
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, {
|
|
21679
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
21811
|
-
depositsEnabled:
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 = [];
|