@1delta/margin-fetcher 5.0.109 → 5.0.110
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 +49 -2
- package/dist/index.js +326 -33
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -8316,7 +8316,9 @@ type SupplyExitMode = Open<'instant' | 'instant-capped' | 'instant-or-queued' |
|
|
|
8316
8316
|
/** Sell the instrument on a book (Term, TermMax, Midnight). */
|
|
8317
8317
|
| 'market-sale'
|
|
8318
8318
|
/** No early exit at all. */
|
|
8319
|
-
| 'at-maturity'
|
|
8319
|
+
| 'at-maturity'
|
|
8320
|
+
/** A dated bond: par at maturity, or earlier at a price (Usual bUSD0). */
|
|
8321
|
+
| 'fee-or-maturity' | 'off-chain' | 'dex-only'>;
|
|
8320
8322
|
/**
|
|
8321
8323
|
* One concrete way out, as published by the vault row. Re-exported from the
|
|
8322
8324
|
* vault layer so a term sheet and the `/v1/data/vaults` row cannot disagree
|
|
@@ -9108,7 +9110,14 @@ type DeepPartial<T> = {
|
|
|
9108
9110
|
* kept separate so the two providers can evolve independently without
|
|
9109
9111
|
* one provider's withdrawal taxonomy creep affecting the other.
|
|
9110
9112
|
*/
|
|
9111
|
-
type SavingsWithdrawalMode = 'instant' | 'instant-capped' | 'fixed-cooldown' | 'queued' | 'request-based' | 'fee-or-queued'
|
|
9113
|
+
type SavingsWithdrawalMode = 'instant' | 'instant-capped' | 'fixed-cooldown' | 'queued' | 'request-based' | 'fee-or-queued'
|
|
9114
|
+
/**
|
|
9115
|
+
* A fixed-maturity BOND: redeemable at par on a date, or earlier for a
|
|
9116
|
+
* price — Usual's bUSD0 (floor-price unlock, a par unlock paid in USUAL, or
|
|
9117
|
+
* par with the redemption token). There is no request and no queue; the
|
|
9118
|
+
* "wait" is the bond's own end, in `expiry`.
|
|
9119
|
+
*/
|
|
9120
|
+
| 'fee-or-maturity';
|
|
9112
9121
|
/**
|
|
9113
9122
|
* Parsed savings-vault entry.
|
|
9114
9123
|
*
|
|
@@ -9354,6 +9363,44 @@ interface SavingsVault extends VaultClassificationFields {
|
|
|
9354
9363
|
* only per-share number there is.
|
|
9355
9364
|
*/
|
|
9356
9365
|
redemptionDiscountBps?: number;
|
|
9366
|
+
/**
|
|
9367
|
+
* Unix seconds at which the position MATURES and redeems at par. The term
|
|
9368
|
+
* sheet reads it as a `fixed-date` maturity (`termSheet.supply.maturity`),
|
|
9369
|
+
* which also closes entry once it passes. Same field name and units as
|
|
9370
|
+
* `PendlePt.expiry`.
|
|
9371
|
+
*/
|
|
9372
|
+
expiry?: number;
|
|
9373
|
+
/**
|
|
9374
|
+
* 1e18-scaled underlying paid per share by the guaranteed EARLY exit
|
|
9375
|
+
* (bUSD0's `getFloorPrice()`, 0.92 at integration). `withdrawFeeBps` carries
|
|
9376
|
+
* the same fact as a haircut on that leg. Absent ⇒ not read; `'0'` ⇒ the
|
|
9377
|
+
* floor exit is switched off.
|
|
9378
|
+
*/
|
|
9379
|
+
floorPrice?: string;
|
|
9380
|
+
/**
|
|
9381
|
+
* Signed basis-point gap between the share's MARKET price and what it
|
|
9382
|
+
* redeems for (`exchangeRate` × underlying price): negative ⇒ it trades
|
|
9383
|
+
* below par. Only computed for `fee-or-maturity` rows, and only when the
|
|
9384
|
+
* caller's price map carries the share token itself — bUSD0 traded at ~0.971
|
|
9385
|
+
* against USD0 at integration, i.e. ≈ −290 bps, which is the yield a buyer
|
|
9386
|
+
* locks in by holding to `expiry`.
|
|
9387
|
+
*/
|
|
9388
|
+
marketDiscountBps?: number;
|
|
9389
|
+
/** `true` when the protocol's user paths are paused. Absent ⇒ not read. */
|
|
9390
|
+
isPaused?: boolean;
|
|
9391
|
+
/** The rest of a bond's terms — see `SavingsOnChainState.bond`. */
|
|
9392
|
+
bond?: {
|
|
9393
|
+
/** Unix seconds the bond period began. */
|
|
9394
|
+
startTime?: number;
|
|
9395
|
+
/** Token a par exit before maturity burns one-for-one (rt-bUSD0). */
|
|
9396
|
+
redemptionToken?: string;
|
|
9397
|
+
/** Its supply, raw — the most that can EVER exit early at par. */
|
|
9398
|
+
redemptionTokenSupply?: string;
|
|
9399
|
+
/** Token the par early unlock is paid in (USUAL). */
|
|
9400
|
+
parUnlockToken?: string;
|
|
9401
|
+
/** Raw `parUnlockToken` pulled per ONE share by that unlock. */
|
|
9402
|
+
parUnlockCostPerShare?: string;
|
|
9403
|
+
};
|
|
9357
9404
|
/**
|
|
9358
9405
|
* Curated loss-waterfall / backing classification, straight from the
|
|
9359
9406
|
* registry entry. Absent ⇒ not assessed (NOT "safe").
|
package/dist/index.js
CHANGED
|
@@ -49133,6 +49133,33 @@ var sthusdFetcher = {
|
|
|
49133
49133
|
};
|
|
49134
49134
|
}
|
|
49135
49135
|
};
|
|
49136
|
+
|
|
49137
|
+
// src/yields/intrinsic/fetchers/usual.ts
|
|
49138
|
+
var USDZEROPLUS_URL = "https://app.usual.money/api/rewards/rates/USD0++";
|
|
49139
|
+
var ETHZERO_URL = "https://app.usual.money/api/rewards/rates/ETH0";
|
|
49140
|
+
var BUSD0_KEY = "Staked USD0::USD0++";
|
|
49141
|
+
var usdZeroPlus = BUSD0_KEY;
|
|
49142
|
+
var ethZero = "ETH0::ETH0";
|
|
49143
|
+
var usdZeroPlusFetcher = {
|
|
49144
|
+
label: "USDZEROPLUS",
|
|
49145
|
+
fetch: async () => {
|
|
49146
|
+
const res = await fetch(USDZEROPLUS_URL, {
|
|
49147
|
+
method: "GET",
|
|
49148
|
+
headers: { Accept: "application/json" }
|
|
49149
|
+
}).then((r) => r.json());
|
|
49150
|
+
return { [usdZeroPlus]: Number(res?.rewards[0]?.apr ?? 0) * 100 };
|
|
49151
|
+
}
|
|
49152
|
+
};
|
|
49153
|
+
var ethZeroFetcher = {
|
|
49154
|
+
label: "ETHZERO",
|
|
49155
|
+
fetch: async () => {
|
|
49156
|
+
const res = await fetch(ETHZERO_URL, {
|
|
49157
|
+
method: "GET",
|
|
49158
|
+
headers: { Accept: "application/json" }
|
|
49159
|
+
}).then((r) => r.json());
|
|
49160
|
+
return { [ethZero]: Number(res?.rewards[0]?.apr ?? 0) * 100 };
|
|
49161
|
+
}
|
|
49162
|
+
};
|
|
49136
49163
|
var CHAIN_ID14 = Chain.ETHEREUM_MAINNET;
|
|
49137
49164
|
var HUMA_PST_FEED = "0x4be50be32db1510240d542f77c5b36ca0d0965e6";
|
|
49138
49165
|
var HUMA_PST_KEY = "HUMA::PST";
|
|
@@ -52479,6 +52506,50 @@ var SINGLE_CHAIN_ENTRIES = {
|
|
|
52479
52506
|
yieldFetcher: saturnFetcher,
|
|
52480
52507
|
yieldKey: SUSDAT_KEY
|
|
52481
52508
|
},
|
|
52509
|
+
// ---- Usual (usual.money) — bUSD0, Bond USD0 (ex-USD0++) ------------
|
|
52510
|
+
//
|
|
52511
|
+
// A fixed-maturity BOND over USD0, not a staked stablecoin: one bUSD0 is
|
|
52512
|
+
// one USD0 at `getEndTime()` = 1844335800 (2028-06-11 11:30 UTC; the bond
|
|
52513
|
+
// started 2024-06-11 and runs `totalBondTimes()` = 4 years). Not ERC-4626
|
|
52514
|
+
// in any part, hence the `usual-bond` reader. Fully backed 1:1 — the
|
|
52515
|
+
// contract held exactly its supply in USD0 (518,288,230.80 each) on
|
|
52516
|
+
// 2026-10-07 — but the backing is admin-sweepable (`emergencyWithdraw`),
|
|
52517
|
+
// so `solvency` stays unasserted and the reader clamps the rate to it.
|
|
52518
|
+
//
|
|
52519
|
+
// The rate is par and NEVER drifts: the yield is a USUAL reward stream
|
|
52520
|
+
// (Usual's `rewards/rates/USD0++` API, 5.69 % at integration). The
|
|
52521
|
+
// interesting numbers are the early exits — `unlockUsd0ppFloorPrice` at
|
|
52522
|
+
// `getFloorPrice()` (0.92 → `withdrawFeeBps` 800), `unlockUSD0ppWithUsual`
|
|
52523
|
+
// at par for `calculateRequiredUsual` (2.147 USUAL per bUSD0 ≈ 2.6 % at
|
|
52524
|
+
// $0.0122), and `reconstruct` at par for an equal rt-bUSD0 burn, which only
|
|
52525
|
+
// V3 mints receive (~337.9k rt against ~518M bUSD0). The market sat at
|
|
52526
|
+
// ~0.971, so the floor is NOT the cheapest exit — the market and the USUAL
|
|
52527
|
+
// unlock both beat it. Every user path is `whenNotPaused`, and transfers
|
|
52528
|
+
// revert for USD0-blacklisted addresses.
|
|
52529
|
+
{
|
|
52530
|
+
reader: "usual-bond",
|
|
52531
|
+
address: "0x35d8949372d46b7a3d5a56006ae77b215fc69bc0",
|
|
52532
|
+
underlying: "0x73a15fed60bf67631dc6cd7bc5b6e8da8190acf5",
|
|
52533
|
+
// USD0
|
|
52534
|
+
symbol: "bUSD0",
|
|
52535
|
+
brand: "Usual",
|
|
52536
|
+
description: "Usual's four-year bond on its USD0 stablecoin: each bUSD0 is backed by one USD0 held in the contract and redeems for it at par on 11 June 2028. The yield is paid separately in USUAL tokens, not added to the bond. Leaving before maturity costs something \u2014 the guaranteed floor price (currently 0.92), a fee paid in USUAL for par, or a sale on the market below par \u2014 unless you still hold the redemption token from minting.",
|
|
52537
|
+
decimals: 18,
|
|
52538
|
+
isRebasing: false,
|
|
52539
|
+
isMintable: true,
|
|
52540
|
+
withdrawalMode: "fee-or-maturity",
|
|
52541
|
+
expiry: 1844335800,
|
|
52542
|
+
// getEndTime() — 2028-06-11 11:30 UTC
|
|
52543
|
+
usualBond: {
|
|
52544
|
+
redemptionToken: "0x82dca22b48b14de38ccf83b03330120c4b8acfe9",
|
|
52545
|
+
// rt-bUSD0
|
|
52546
|
+
parUnlockToken: "0xc4441c2be5d8fa8126822b9929ca0b81ea0de38e",
|
|
52547
|
+
// USUAL
|
|
52548
|
+
parUnlockTokenSymbol: "USUAL"
|
|
52549
|
+
},
|
|
52550
|
+
yieldFetcher: usdZeroPlusFetcher,
|
|
52551
|
+
yieldKey: BUSD0_KEY
|
|
52552
|
+
},
|
|
52482
52553
|
// ---- Strata (docs.strata.markets) — senior/junior risk tranches ----
|
|
52483
52554
|
//
|
|
52484
52555
|
// Six CDO markets, twelve ERC-4626 tranche tokens, all Ethereum.
|
|
@@ -55558,32 +55629,6 @@ var csusdlFetcher = {
|
|
|
55558
55629
|
}
|
|
55559
55630
|
};
|
|
55560
55631
|
|
|
55561
|
-
// src/yields/intrinsic/fetchers/usual.ts
|
|
55562
|
-
var USDZEROPLUS_URL = "https://app.usual.money/api/rewards/rates/USD0++";
|
|
55563
|
-
var ETHZERO_URL = "https://app.usual.money/api/rewards/rates/ETH0";
|
|
55564
|
-
var usdZeroPlus = "Staked USD0::USD0++";
|
|
55565
|
-
var ethZero = "ETH0::ETH0";
|
|
55566
|
-
var usdZeroPlusFetcher = {
|
|
55567
|
-
label: "USDZEROPLUS",
|
|
55568
|
-
fetch: async () => {
|
|
55569
|
-
const res = await fetch(USDZEROPLUS_URL, {
|
|
55570
|
-
method: "GET",
|
|
55571
|
-
headers: { Accept: "application/json" }
|
|
55572
|
-
}).then((r) => r.json());
|
|
55573
|
-
return { [usdZeroPlus]: Number(res?.rewards[0]?.apr ?? 0) * 100 };
|
|
55574
|
-
}
|
|
55575
|
-
};
|
|
55576
|
-
var ethZeroFetcher = {
|
|
55577
|
-
label: "ETHZERO",
|
|
55578
|
-
fetch: async () => {
|
|
55579
|
-
const res = await fetch(ETHZERO_URL, {
|
|
55580
|
-
method: "GET",
|
|
55581
|
-
headers: { Accept: "application/json" }
|
|
55582
|
-
}).then((r) => r.json());
|
|
55583
|
-
return { [ethZero]: Number(res?.rewards[0]?.apr ?? 0) * 100 };
|
|
55584
|
-
}
|
|
55585
|
-
};
|
|
55586
|
-
|
|
55587
55632
|
// src/yields/intrinsic/fetchers/jito.ts
|
|
55588
55633
|
var JITOSOL_URL = "https://www.jito.network/api/getJitoPoolStats/";
|
|
55589
55634
|
var jitoSol = "Jito Staked SOL::JitoSOL";
|
|
@@ -67581,6 +67626,87 @@ var marketRoute = () => ({
|
|
|
67581
67626
|
settlement: "market",
|
|
67582
67627
|
description: "The protocol's own mint and redeem are permissioned, so for a holder without that permission this is the route: sell the share token at whatever the book bids, with price impact that grows with size. It fills at the MARKET price, which is not the row's `exchangeRate` \u2014 that stays the NAV \u2014 so the leg must be built with a slippage bound."
|
|
67583
67628
|
});
|
|
67629
|
+
var capped = (a, b) => {
|
|
67630
|
+
if (a === void 0) return b;
|
|
67631
|
+
if (b === void 0) return a;
|
|
67632
|
+
return BigInt(a) < BigInt(b) ? a : b;
|
|
67633
|
+
};
|
|
67634
|
+
var bondExitRoutes = (i) => {
|
|
67635
|
+
const routes2 = [];
|
|
67636
|
+
const now = i.now ?? Math.floor(Date.now() / 1e3);
|
|
67637
|
+
const matured = i.expiry !== void 0 && now >= i.expiry;
|
|
67638
|
+
const capacity = {
|
|
67639
|
+
capacity: i.liquidity,
|
|
67640
|
+
capacityFormatted: i.liquidityFormatted,
|
|
67641
|
+
capacityUsd: i.liquidityUsd
|
|
67642
|
+
};
|
|
67643
|
+
if (i.withdrawFeeBps != null)
|
|
67644
|
+
routes2.push({
|
|
67645
|
+
id: "floor",
|
|
67646
|
+
kind: "instant",
|
|
67647
|
+
label: "Early exit at the floor price",
|
|
67648
|
+
settlement: "sync",
|
|
67649
|
+
feeBps: i.withdrawFeeBps,
|
|
67650
|
+
waitSeconds: 0,
|
|
67651
|
+
...capacity,
|
|
67652
|
+
selfOnly: true,
|
|
67653
|
+
description: "Burns the bond now for the protocol's floor price; the difference to par goes to the protocol's treasury, not to you. Pays the sender only."
|
|
67654
|
+
});
|
|
67655
|
+
if (i.parUnlockAvailable) {
|
|
67656
|
+
const token = i.parUnlockTokenSymbol ?? "the protocol token";
|
|
67657
|
+
routes2.push({
|
|
67658
|
+
id: "usual-unlock",
|
|
67659
|
+
kind: "instant",
|
|
67660
|
+
label: `Early exit at par (pays ${token})`,
|
|
67661
|
+
settlement: "sync",
|
|
67662
|
+
feeBps: i.parUnlockFeeBps,
|
|
67663
|
+
...i.parUnlockFeeBps == null ? { feeUnknown: true } : {},
|
|
67664
|
+
waitSeconds: 0,
|
|
67665
|
+
...capacity,
|
|
67666
|
+
selfOnly: true,
|
|
67667
|
+
description: `Pays par in the underlying, but you must also pay ${token} \u2014 a fixed amount per bond, so its cost in dollars moves with ${token}'s price. Pays the sender only.`
|
|
67668
|
+
});
|
|
67669
|
+
}
|
|
67670
|
+
if (i.redemptionTokenCapacity !== void 0)
|
|
67671
|
+
routes2.push({
|
|
67672
|
+
id: "reconstruct",
|
|
67673
|
+
kind: "instant",
|
|
67674
|
+
label: "Par with the redemption token",
|
|
67675
|
+
settlement: "sync",
|
|
67676
|
+
feeBps: 0,
|
|
67677
|
+
waitSeconds: 0,
|
|
67678
|
+
capacity: capped(i.liquidity, i.redemptionTokenCapacity),
|
|
67679
|
+
capacityFormatted: i.liquidityFormatted !== void 0 && i.redemptionTokenCapacityFormatted !== void 0 ? Math.min(i.liquidityFormatted, i.redemptionTokenCapacityFormatted) : i.redemptionTokenCapacityFormatted ?? i.liquidityFormatted,
|
|
67680
|
+
description: "Free and at par any time, but it burns an equal amount of the redemption token, which only fresh mints receive \u2014 a holder who bought the bond, or minted it before the token existed, cannot take this route. Capacity is the token supply across everyone."
|
|
67681
|
+
});
|
|
67682
|
+
routes2.push(
|
|
67683
|
+
matured ? {
|
|
67684
|
+
id: "maturity",
|
|
67685
|
+
kind: "instant",
|
|
67686
|
+
label: "Par at maturity",
|
|
67687
|
+
settlement: "sync",
|
|
67688
|
+
feeBps: 0,
|
|
67689
|
+
waitSeconds: 0,
|
|
67690
|
+
description: "The bond has matured: redeem at par. Burns your WHOLE balance in one call."
|
|
67691
|
+
} : {
|
|
67692
|
+
id: "maturity",
|
|
67693
|
+
kind: "queued",
|
|
67694
|
+
label: i.expiry !== void 0 ? `Par at maturity (${new Date(i.expiry * 1e3).toISOString().slice(0, 10)})` : "Par at maturity",
|
|
67695
|
+
settlement: "async",
|
|
67696
|
+
feeBps: 0,
|
|
67697
|
+
waitSeconds: i.expiry !== void 0 ? Math.max(0, i.expiry - now) : void 0,
|
|
67698
|
+
description: "Hold to the maturity date and redeem at par \u2014 nothing to request in the meantime. The redemption burns your WHOLE balance in one call."
|
|
67699
|
+
}
|
|
67700
|
+
);
|
|
67701
|
+
routes2.push({
|
|
67702
|
+
id: "market",
|
|
67703
|
+
kind: "market",
|
|
67704
|
+
label: "Sell on the market",
|
|
67705
|
+
settlement: "market",
|
|
67706
|
+
description: "Sell the bond to somebody else. It fills at the market price \u2014 usually a discount to par that closes toward maturity \u2014 not at the row's `exchangeRate`, with price impact that grows with size, so the leg must be built with a slippage bound."
|
|
67707
|
+
});
|
|
67708
|
+
return routes2;
|
|
67709
|
+
};
|
|
67584
67710
|
var deriveExitRoutes = (i) => {
|
|
67585
67711
|
const routes2 = deriveProtocolExitRoutes(i);
|
|
67586
67712
|
return i.secondaryMarketOnly ? [...routes2, marketRoute()] : routes2;
|
|
@@ -67607,6 +67733,8 @@ var deriveProtocolExitRoutes = (i) => {
|
|
|
67607
67733
|
// inventory instead.
|
|
67608
67734
|
case "instant-or-queued":
|
|
67609
67735
|
return [instantRoute(i, i.withdrawFeeBps ?? 0), queuedRoute(i)];
|
|
67736
|
+
case "fee-or-maturity":
|
|
67737
|
+
return bondExitRoutes(i);
|
|
67610
67738
|
case "instant":
|
|
67611
67739
|
return [
|
|
67612
67740
|
{
|
|
@@ -72236,6 +72364,30 @@ var NEST_FEE_INSTANT_REDEMPTION = 0;
|
|
|
72236
72364
|
var NEST_FEE_DEPOSIT = 1;
|
|
72237
72365
|
var NEST_FEE_REDEMPTION = 2;
|
|
72238
72366
|
|
|
72367
|
+
// src/vaults/savings/abis/usual.ts
|
|
72368
|
+
var view = (name, inputs = []) => ({
|
|
72369
|
+
name,
|
|
72370
|
+
type: "function",
|
|
72371
|
+
stateMutability: "view",
|
|
72372
|
+
inputs,
|
|
72373
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
72374
|
+
});
|
|
72375
|
+
var UsualBondFloorPriceAbi = [view("getFloorPrice")];
|
|
72376
|
+
var UsualBondStartTimeAbi = [view("getStartTime")];
|
|
72377
|
+
var UsualBondEndTimeAbi = [view("getEndTime")];
|
|
72378
|
+
var UsualBondRequiredUsualAbi = [
|
|
72379
|
+
view("calculateRequiredUsual", [{ name: "usd0ppAmount", type: "uint256" }])
|
|
72380
|
+
];
|
|
72381
|
+
var UsualBondPausedAbi = [
|
|
72382
|
+
{
|
|
72383
|
+
name: "paused",
|
|
72384
|
+
type: "function",
|
|
72385
|
+
stateMutability: "view",
|
|
72386
|
+
inputs: [],
|
|
72387
|
+
outputs: [{ name: "", type: "bool" }]
|
|
72388
|
+
}
|
|
72389
|
+
];
|
|
72390
|
+
|
|
72239
72391
|
// src/vaults/savings/readers/erc4626Idle.ts
|
|
72240
72392
|
var readerErc4626Idle = (entry) => {
|
|
72241
72393
|
const shareUnit = 10n ** BigInt(entry.decimals);
|
|
@@ -72801,6 +72953,88 @@ var readerSaturnVault = (entry) => {
|
|
|
72801
72953
|
};
|
|
72802
72954
|
};
|
|
72803
72955
|
|
|
72956
|
+
// src/vaults/savings/readers/usualBond.ts
|
|
72957
|
+
var readerUsualBond = (entry) => {
|
|
72958
|
+
const cfg = entry.usualBond;
|
|
72959
|
+
const shareUnit = 10n ** BigInt(entry.decimals);
|
|
72960
|
+
return {
|
|
72961
|
+
calls: [
|
|
72962
|
+
{ address: entry.address, name: "totalSupply", params: [] },
|
|
72963
|
+
{ address: entry.underlying, name: "balanceOf", params: [entry.address] },
|
|
72964
|
+
{ address: entry.address, name: "getFloorPrice", params: [] },
|
|
72965
|
+
{ address: entry.address, name: "getStartTime", params: [] },
|
|
72966
|
+
{ address: entry.address, name: "getEndTime", params: [] },
|
|
72967
|
+
{ address: entry.address, name: "paused", params: [] },
|
|
72968
|
+
// No pinned rt token ⇒ read the bond's own supply in its place and
|
|
72969
|
+
// discard it, keeping the slice width fixed.
|
|
72970
|
+
{
|
|
72971
|
+
address: cfg?.redemptionToken ?? entry.address,
|
|
72972
|
+
name: "totalSupply",
|
|
72973
|
+
params: []
|
|
72974
|
+
},
|
|
72975
|
+
{
|
|
72976
|
+
address: entry.address,
|
|
72977
|
+
name: "calculateRequiredUsual",
|
|
72978
|
+
params: [shareUnit]
|
|
72979
|
+
}
|
|
72980
|
+
],
|
|
72981
|
+
abis: [
|
|
72982
|
+
TotalSupplyAbi2,
|
|
72983
|
+
BalanceOfAbi,
|
|
72984
|
+
UsualBondFloorPriceAbi,
|
|
72985
|
+
UsualBondStartTimeAbi,
|
|
72986
|
+
UsualBondEndTimeAbi,
|
|
72987
|
+
UsualBondPausedAbi,
|
|
72988
|
+
TotalSupplyAbi2,
|
|
72989
|
+
UsualBondRequiredUsualAbi
|
|
72990
|
+
],
|
|
72991
|
+
parse: ([
|
|
72992
|
+
supply,
|
|
72993
|
+
backingRaw,
|
|
72994
|
+
floor,
|
|
72995
|
+
start,
|
|
72996
|
+
end,
|
|
72997
|
+
paused,
|
|
72998
|
+
rtSupply,
|
|
72999
|
+
usual
|
|
73000
|
+
]) => {
|
|
73001
|
+
const totalSupply = toBigInt16(supply);
|
|
73002
|
+
const backing = toBigInt16(backingRaw);
|
|
73003
|
+
const endTime = toBigInt16(end);
|
|
73004
|
+
if (totalSupply === void 0 || backing === void 0 || endTime === void 0 || endTime <= 0n)
|
|
73005
|
+
return void 0;
|
|
73006
|
+
const exchangeRate = totalSupply > 0n && backing < totalSupply ? backing * ONE_E1815 / totalSupply : ONE_E1815;
|
|
73007
|
+
const floorPrice = toBigInt16(floor);
|
|
73008
|
+
const startTime = toBigInt16(start);
|
|
73009
|
+
const isPaused = typeof paused === "boolean" ? paused : void 0;
|
|
73010
|
+
const parUnlockCostPerShare = toBigInt16(usual);
|
|
73011
|
+
return {
|
|
73012
|
+
totalAssets: backing,
|
|
73013
|
+
totalSupply,
|
|
73014
|
+
exchangeRate,
|
|
73015
|
+
expiry: Number(endTime),
|
|
73016
|
+
paused: isPaused,
|
|
73017
|
+
// The floor exit's haircut, in the field every reader uses for "what
|
|
73018
|
+
// the immediate exit costs". Rounded UP: 0.92 → 800 bps exactly, and a
|
|
73019
|
+
// floor that is not a whole bps never reads cheaper than it is.
|
|
73020
|
+
withdrawFeeBps: floorPrice !== void 0 && floorPrice > 0n && floorPrice <= ONE_E1815 ? Number((ONE_E1815 - floorPrice + 10n ** 14n - 1n) / 10n ** 14n) : void 0,
|
|
73021
|
+
// Unread ⇒ assume open (the immediate exits are the norm); a READ pause
|
|
73022
|
+
// closes every leg, maturity included.
|
|
73023
|
+
instantRedeemEnabled: isPaused !== true,
|
|
73024
|
+
// Every immediate exit pays out of the bond's own USD0 — at most the
|
|
73025
|
+
// whole backing, never more.
|
|
73026
|
+
instantRedeemCapacity: isPaused === true ? 0n : backing,
|
|
73027
|
+
bond: {
|
|
73028
|
+
floorPrice,
|
|
73029
|
+
startTime: startTime !== void 0 ? Number(startTime) : void 0,
|
|
73030
|
+
redemptionTokenSupply: cfg?.redemptionToken ? toBigInt16(rtSupply) : void 0,
|
|
73031
|
+
parUnlockCostPerShare
|
|
73032
|
+
}
|
|
73033
|
+
};
|
|
73034
|
+
}
|
|
73035
|
+
};
|
|
73036
|
+
};
|
|
73037
|
+
|
|
72804
73038
|
// src/vaults/savings/readers/venusHub.ts
|
|
72805
73039
|
var NEUTRAL_PROBE2 = "0x000000000000000000000000000000000000dead";
|
|
72806
73040
|
var BPS_TO_PCT = 100;
|
|
@@ -73092,6 +73326,8 @@ var buildReader2 = (entry) => {
|
|
|
73092
73326
|
return readerSaturnVault(entry);
|
|
73093
73327
|
case "nest-vault":
|
|
73094
73328
|
return readerNestVault(entry);
|
|
73329
|
+
case "usual-bond":
|
|
73330
|
+
return readerUsualBond(entry);
|
|
73095
73331
|
case "erc4626-cooldown":
|
|
73096
73332
|
return readerErc4626Cooldown(entry);
|
|
73097
73333
|
case "erc4626-idle":
|
|
@@ -73203,6 +73439,18 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
|
|
|
73203
73439
|
const redemptionDiscountBps = state.fundamentalExchangeRate !== void 0 && state.fundamentalExchangeRate > 0n ? Number(
|
|
73204
73440
|
state.exchangeRate * 100000000n / state.fundamentalExchangeRate - 100000000n
|
|
73205
73441
|
) / 1e4 : void 0;
|
|
73442
|
+
const bond = state.bond;
|
|
73443
|
+
const isBond = entry.withdrawalMode === "fee-or-maturity";
|
|
73444
|
+
const sharePriceUsd = prices[addressLc];
|
|
73445
|
+
const redeemableUsd = priceUsd !== void 0 ? Number(state.exchangeRate) / 1e18 * priceUsd : 0;
|
|
73446
|
+
const marketDiscountBps = isBond && sharePriceUsd !== void 0 && redeemableUsd > 0 ? Math.round((sharePriceUsd / redeemableUsd - 1) * 1e5) / 10 : void 0;
|
|
73447
|
+
const parToken = entry.usualBond?.parUnlockToken.toLowerCase();
|
|
73448
|
+
const parTokenPrice = parToken !== void 0 ? prices[parToken] : void 0;
|
|
73449
|
+
const parTokenDec = parToken !== void 0 ? tokenList[parToken]?.decimals ?? 18 : 18;
|
|
73450
|
+
const parUnlockFeeBps = bond?.parUnlockCostPerShare !== void 0 && parTokenPrice !== void 0 && redeemableUsd > 0 ? Math.round(
|
|
73451
|
+
Number(bond.parUnlockCostPerShare) / 10 ** parTokenDec * parTokenPrice * 1e4 / redeemableUsd
|
|
73452
|
+
) : void 0;
|
|
73453
|
+
const rtSupply = bond?.redemptionTokenSupply;
|
|
73206
73454
|
const productName = entry.label ?? entry.symbol;
|
|
73207
73455
|
const displayName = entry.label ? `${entry.brand} ${entry.label}` : composeVaultDisplayName(
|
|
73208
73456
|
entry.brand,
|
|
@@ -73264,6 +73512,18 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
|
|
|
73264
73512
|
withdrawalCooldownSeconds: state.withdrawalCooldownSeconds ?? entry.withdrawalCooldownSeconds,
|
|
73265
73513
|
withdrawFeeBps: state.withdrawFeeBps,
|
|
73266
73514
|
depositFeeBps: state.depositFeeBps,
|
|
73515
|
+
// Bond terms — absent on every perpetual vault. See the type.
|
|
73516
|
+
expiry: state.expiry ?? entry.expiry,
|
|
73517
|
+
isPaused: state.paused,
|
|
73518
|
+
floorPrice: bond?.floorPrice?.toString(),
|
|
73519
|
+
marketDiscountBps,
|
|
73520
|
+
bond: bond ? {
|
|
73521
|
+
startTime: bond.startTime,
|
|
73522
|
+
redemptionToken: entry.usualBond?.redemptionToken.toLowerCase(),
|
|
73523
|
+
redemptionTokenSupply: rtSupply?.toString(),
|
|
73524
|
+
parUnlockToken: parToken,
|
|
73525
|
+
parUnlockCostPerShare: bond.parUnlockCostPerShare?.toString()
|
|
73526
|
+
} : void 0,
|
|
73267
73527
|
// Term-sheet inputs that no reader can derive — see the registry's
|
|
73268
73528
|
// docstrings. Passed through verbatim so the sheet can stop hardcoding
|
|
73269
73529
|
// "compounds per second" and "needs an approval" for every vault.
|
|
@@ -73298,7 +73558,14 @@ var fetchSavingsVaults = async (chainId, multicallRetry, prices = {}, tokenList
|
|
|
73298
73558
|
exitMinAmountFormatted: state.exitMinAmount !== void 0 ? Number(state.exitMinAmount) / 10 ** underlyingDec : void 0,
|
|
73299
73559
|
// Adds the `market` leg — the only route a holder without the
|
|
73300
73560
|
// protocol's mint/redeem permission actually has.
|
|
73301
|
-
secondaryMarketOnly: entry.secondaryMarketOnly
|
|
73561
|
+
secondaryMarketOnly: entry.secondaryMarketOnly,
|
|
73562
|
+
// Bond legs (`fee-or-maturity` only; ignored by every other mode).
|
|
73563
|
+
expiry: state.expiry ?? entry.expiry,
|
|
73564
|
+
redemptionTokenCapacity: rtSupply?.toString(),
|
|
73565
|
+
redemptionTokenCapacityFormatted: rtSupply !== void 0 ? Number(rtSupply) / 10 ** underlyingDec : void 0,
|
|
73566
|
+
parUnlockAvailable: bond?.parUnlockCostPerShare !== void 0 && bond.parUnlockCostPerShare > 0n,
|
|
73567
|
+
parUnlockFeeBps,
|
|
73568
|
+
parUnlockTokenSymbol: entry.usualBond?.parUnlockTokenSymbol
|
|
73302
73569
|
}),
|
|
73303
73570
|
resolveSelfOnly(chainId, entry.address)
|
|
73304
73571
|
),
|
|
@@ -74333,6 +74600,7 @@ var classifyRedemption = (provider, v) => {
|
|
|
74333
74600
|
if (SYNC_REDEMPTION_PROVIDERS.has(provider)) return "sync";
|
|
74334
74601
|
if (provider === "lst") return "async";
|
|
74335
74602
|
if (provider === "savings") {
|
|
74603
|
+
if (v.withdrawalMode === "fee-or-maturity") return void 0;
|
|
74336
74604
|
return v.withdrawalMode === "instant" && !v.withdrawalCooldownSeconds ? "sync" : "async";
|
|
74337
74605
|
}
|
|
74338
74606
|
return "sync";
|
|
@@ -76676,6 +76944,7 @@ var exitPhrase = {
|
|
|
76676
76944
|
"request-based": "withdrawals need a request",
|
|
76677
76945
|
"market-sale": "exit by selling on the market",
|
|
76678
76946
|
"at-maturity": "locked until maturity",
|
|
76947
|
+
"fee-or-maturity": "exit early at a discount, or at par at maturity",
|
|
76679
76948
|
"off-chain": "exit off-chain",
|
|
76680
76949
|
"dex-only": "exit only via a DEX"
|
|
76681
76950
|
};
|
|
@@ -76715,6 +76984,7 @@ function headlineExitFromRoutes(routes2, symbol) {
|
|
|
76715
76984
|
const fastPart = fast.feeBps == null ? "instant exit" : fast.feeBps === 0 ? "free instant exit" : `instant exit for ${(fast.feeBps / 100).toFixed(2)} %`;
|
|
76716
76985
|
const slowCost = slow.feeBps === 0 ? "free" : slow.feeBps != null ? `${(slow.feeBps / 100).toFixed(2)} %` : void 0;
|
|
76717
76986
|
const floor = slow.minAmountFormatted != null && slow.minAmountFormatted > 0 ? ` above ${amount(slow.minAmountFormatted)}${symbol ? ` ${symbol}` : ""}` : "";
|
|
76987
|
+
if (slow.id === "maturity") return `${fastPart}, or par at maturity`;
|
|
76718
76988
|
const slowPart = slowCost ? `queue${floor} for ${slowCost}` : `queue${floor}`;
|
|
76719
76989
|
return `${fastPart}, or ${slowPart}`;
|
|
76720
76990
|
}
|
|
@@ -79067,6 +79337,7 @@ var EXIT_MODE_LABELS = {
|
|
|
79067
79337
|
"request-based": "Request",
|
|
79068
79338
|
"market-sale": "Market sale",
|
|
79069
79339
|
"at-maturity": "At maturity",
|
|
79340
|
+
"fee-or-maturity": "Fee or maturity",
|
|
79070
79341
|
"off-chain": "Off-chain",
|
|
79071
79342
|
"dex-only": "DEX only"
|
|
79072
79343
|
};
|
|
@@ -79080,6 +79351,7 @@ var EXIT_MODE_DESCRIPTIONS = {
|
|
|
79080
79351
|
"request-based": "Withdrawals need a request and a later claim.",
|
|
79081
79352
|
"market-sale": "Exit by selling the position on a market.",
|
|
79082
79353
|
"at-maturity": "Locked until maturity.",
|
|
79354
|
+
"fee-or-maturity": "Exit early at a discount, or at par at maturity.",
|
|
79083
79355
|
"off-chain": "Exit is settled off-chain.",
|
|
79084
79356
|
"dex-only": "Exit only by selling on a DEX."
|
|
79085
79357
|
};
|
|
@@ -79386,7 +79658,10 @@ var UNCAPPED_EXIT_MODES = /* @__PURE__ */ new Set([
|
|
|
79386
79658
|
"instant-or-queued",
|
|
79387
79659
|
"request-based",
|
|
79388
79660
|
"off-chain",
|
|
79389
|
-
"at-maturity"
|
|
79661
|
+
"at-maturity",
|
|
79662
|
+
// A bond's par leg is the maturity, uncapped like `at-maturity`; the early
|
|
79663
|
+
// legs are bounded by the backing, which `liquidity` already reports.
|
|
79664
|
+
"fee-or-maturity"
|
|
79390
79665
|
]);
|
|
79391
79666
|
function meetsLiquidityFloor(input, minUsd) {
|
|
79392
79667
|
if (input.canWithdraw === false) return false;
|
|
@@ -79947,7 +80222,10 @@ function savingsCuration(provider, chainId, address) {
|
|
|
79947
80222
|
solvency: e.solvency,
|
|
79948
80223
|
accrual: e.accrual,
|
|
79949
80224
|
yieldWarmupSeconds: e.yieldWarmupSeconds,
|
|
79950
|
-
needsDepositApproval: e.needsDepositApproval
|
|
80225
|
+
needsDepositApproval: e.needsDepositApproval,
|
|
80226
|
+
// A dated bond's maturity (Usual bUSD0) — static, and the one fact that
|
|
80227
|
+
// keeps a proxied bond row from rendering as perpetual.
|
|
80228
|
+
expiry: e.expiry
|
|
79951
80229
|
};
|
|
79952
80230
|
}
|
|
79953
80231
|
function vaultTermInputFromEarnMarket(m) {
|
|
@@ -80007,7 +80285,7 @@ function vaultTermInputFromEarnMarket(m) {
|
|
|
80007
80285
|
withdrawalsPaused: m.availability.canWithdraw ? void 0 : true,
|
|
80008
80286
|
isClosed: bool2(meta.isClosed),
|
|
80009
80287
|
whitelisted: bool2(meta.whitelisted),
|
|
80010
|
-
expiry: m.maturity?.maturity,
|
|
80288
|
+
expiry: m.maturity?.maturity ?? curated.expiry,
|
|
80011
80289
|
timelock: num14(meta.timelock),
|
|
80012
80290
|
allocators: strArray(meta.allocators),
|
|
80013
80291
|
owner: str7(meta.owner),
|
|
@@ -80089,7 +80367,7 @@ function vaultTermInputFromSourceRow(row, chainId) {
|
|
|
80089
80367
|
withdrawalsPaused: bool2(meta.isWithdrawalPaused),
|
|
80090
80368
|
isClosed: bool2(meta.isClosed),
|
|
80091
80369
|
whitelisted: bool2(meta.whitelisted),
|
|
80092
|
-
expiry: num14(meta.expiry) ?? num14(meta.maturity),
|
|
80370
|
+
expiry: num14(meta.expiry) ?? num14(meta.maturity) ?? curated.expiry,
|
|
80093
80371
|
timelock: num14(meta.timelock),
|
|
80094
80372
|
allocators: strArray(meta.allocators),
|
|
80095
80373
|
owner: str7(meta.owner),
|
|
@@ -82893,6 +83171,11 @@ var isNum4 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
|
82893
83171
|
function build2(input) {
|
|
82894
83172
|
const vault = jupiterLendVaultFromKey(input.lender);
|
|
82895
83173
|
const address = input.asset?.address ?? input.underlying;
|
|
83174
|
+
const smart = input.market?.fluid ?? {};
|
|
83175
|
+
const isSmartCol = !!smart.isSmartCol;
|
|
83176
|
+
const isSmartDebt = !!smart.isSmartDebt;
|
|
83177
|
+
const isSmart = isSmartCol || isSmartDebt;
|
|
83178
|
+
const pair = (p) => Array.isArray(p) ? p.join(" + ") : void 0;
|
|
82896
83179
|
const pending = {
|
|
82897
83180
|
"borrow.liquidation.liquidationMaxLimit": "the max liquidation limit (the LTV past which a position is liquidated ENTIRELY) is not served",
|
|
82898
83181
|
"borrow.availability.cap": "the layer's EXPANDING borrow limit (current, hard max, expand percent and duration) is not served \u2014 it is not a cap, so the row carries none",
|
|
@@ -82953,12 +83236,22 @@ function build2(input) {
|
|
|
82953
83236
|
constraints: {
|
|
82954
83237
|
crossMargin: false,
|
|
82955
83238
|
positionModel: "nft",
|
|
82956
|
-
positionIdMeaning: "The vault position NFT id (per vault; one collateral / debt pair each). positionId 0 MINTS a new position \u2014 only an opening deposit may pass 0; any other action sent with 0 acts on a fresh empty position and reports success."
|
|
83239
|
+
positionIdMeaning: "The vault position NFT id (per vault; one collateral / debt pair each). positionId 0 MINTS a new position \u2014 only an opening deposit may pass 0; any other action sent with 0 acts on a fresh empty position and reports success.",
|
|
83240
|
+
...isSmart ? {
|
|
83241
|
+
// the fluid adapter's notes: a smart side is a DEX share, not a token
|
|
83242
|
+
notes: [
|
|
83243
|
+
isSmartCol ? `Collateral is a Jupiter Lend DEX position (shares) over ${pair(smart.collateralPair) ?? "two tokens"}; this row is one leg of it.` : void 0,
|
|
83244
|
+
isSmartDebt ? `Debt is a Jupiter Lend DEX position (shares) over ${pair(smart.debtPair) ?? "two tokens"}; this row is one leg of it.` : void 0,
|
|
83245
|
+
isSmartDebt ? "The borrow rate is NET of the trading yield the debt LP earns, so it can be negative." : void 0,
|
|
83246
|
+
isSmartCol ? "The supply rate INCLUDES the DEX trading yield (trailing 7 days, after the protocol revenue cut) on top of the liquidity-layer rate." : void 0,
|
|
83247
|
+
"Both legs of a side move together \u2014 a leg cannot be supplied, borrowed or withdrawn on its own; the pool rebalances the split."
|
|
83248
|
+
].filter(Boolean)
|
|
83249
|
+
} : {}
|
|
82957
83250
|
},
|
|
82958
83251
|
ext: {
|
|
82959
83252
|
jupiterLend: {
|
|
82960
83253
|
...vault ? { market: vault.market, vaultId: vault.vaultId } : {},
|
|
82961
|
-
fluidVaultType: FLUID_VAULT_TYPE_T1,
|
|
83254
|
+
fluidVaultType: isNum4(smart.vaultType) ? smart.vaultType : FLUID_VAULT_TYPE_T1,
|
|
82962
83255
|
...vault?.market === "main" ? { programs: JL_MAIN_PROGRAMS } : {},
|
|
82963
83256
|
/** The marketUid ref is the leg's MINT. */
|
|
82964
83257
|
marketUidRef: "mint"
|