@1delta/margin-fetcher 5.0.9 → 5.0.10
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 +82 -22
- package/dist/index.js +229 -13
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,50 @@ interface RewardEntry$1 extends BaseYields$1 {
|
|
|
33
33
|
asset: string;
|
|
34
34
|
}
|
|
35
35
|
type RewardsList$1 = RewardEntry$1[];
|
|
36
|
+
/**
|
|
37
|
+
* The knob the BORROWER turns at open, when this config's numbers depend on one.
|
|
38
|
+
*
|
|
39
|
+
* Absent on every protocol whose factors are constants (Aave, Morpho, Compound…).
|
|
40
|
+
* Present where a per-loan choice moves them — LlamaLend's band count `N` moves
|
|
41
|
+
* the collateral factor; Liquity's chosen interest rate moves the cost.
|
|
42
|
+
*
|
|
43
|
+
* This describes the DOMAIN only. The value a given position actually chose is
|
|
44
|
+
* per-position and lives in the user-data `modes[posId]` slot — it cannot live
|
|
45
|
+
* here, because a lender with sub-accounts (Liquity troves, TermMax GTs) has
|
|
46
|
+
* several live values in one market at once.
|
|
47
|
+
*
|
|
48
|
+
* `kind` is what tells a consumer how to READ that number: without it a UI
|
|
49
|
+
* renders a band count of 15 as "e-mode 15", since `modes` historically only
|
|
50
|
+
* ever carried e-mode categories.
|
|
51
|
+
*
|
|
52
|
+
* See POSITION_PARAMETERS_PLAN.md.
|
|
53
|
+
*/
|
|
54
|
+
interface OpenParameter {
|
|
55
|
+
/** Discriminator — how to interpret the matching `modes[posId]` value. */
|
|
56
|
+
kind: 'llamalend-bands' | 'interest-rate';
|
|
57
|
+
/** Which of this config's numbers moves with the parameter. */
|
|
58
|
+
dimension: 'collateralFactor' | 'rate';
|
|
59
|
+
/** Allowed values: a continuous range, or a discrete set. */
|
|
60
|
+
domain: {
|
|
61
|
+
min: number;
|
|
62
|
+
max: number;
|
|
63
|
+
} | {
|
|
64
|
+
values: number[];
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* The value THIS config's numbers were computed at. A consumer that quotes a
|
|
68
|
+
* different value must recompute — it must not reuse `collateralFactor`.
|
|
69
|
+
*/
|
|
70
|
+
default: number;
|
|
71
|
+
/**
|
|
72
|
+
* `true` ⇒ fixed for the life of the loan; changing it means close & reopen
|
|
73
|
+
* (LlamaLend — `_add_collateral_borrow` reuses the tick width).
|
|
74
|
+
* `false` ⇒ adjustable in place (Liquity), subject to the friction below.
|
|
75
|
+
*/
|
|
76
|
+
immutableAfterOpen: boolean;
|
|
77
|
+
/** Adjustment cooldown, when mutable (Liquity `interestRateAdjCooldownSeconds`). */
|
|
78
|
+
adjustCooldownSeconds?: number;
|
|
79
|
+
}
|
|
36
80
|
interface ConfigEntry {
|
|
37
81
|
category: number;
|
|
38
82
|
borrowCollateralFactor: number;
|
|
@@ -63,6 +107,8 @@ interface ConfigEntry {
|
|
|
63
107
|
targetHealthFactor?: number;
|
|
64
108
|
collateralDisabled?: boolean;
|
|
65
109
|
debtDisabled?: boolean;
|
|
110
|
+
/** Borrower-chosen open-time parameter this config's numbers depend on. */
|
|
111
|
+
openParameter?: OpenParameter;
|
|
66
112
|
}
|
|
67
113
|
interface PoolConfig {
|
|
68
114
|
[category: string]: ConfigEntry;
|
|
@@ -630,6 +676,12 @@ interface LenderConfigData {
|
|
|
630
676
|
targetHealthFactor?: number;
|
|
631
677
|
collateralDisabled?: boolean;
|
|
632
678
|
debtDisabled?: boolean;
|
|
679
|
+
/**
|
|
680
|
+
* Borrower-chosen open-time parameter this config's numbers depend on.
|
|
681
|
+
* Mirrors the API-side `ConfigEntry.openParameter`; see
|
|
682
|
+
* POSITION_PARAMETERS_PLAN.md.
|
|
683
|
+
*/
|
|
684
|
+
openParameter?: OpenParameter;
|
|
633
685
|
}
|
|
634
686
|
interface ModeBase {
|
|
635
687
|
category: number;
|
|
@@ -3304,11 +3356,41 @@ interface ResupplyPairRaw {
|
|
|
3304
3356
|
collateralPrice: bigint | null;
|
|
3305
3357
|
/** Cached `1e36 / collateralPrice` from the pair (stale between writes). */
|
|
3306
3358
|
exchangeRate: bigint | null;
|
|
3359
|
+
/** Convex pool id the collateral is staked into. 0 = not staked, no rewards. */
|
|
3360
|
+
convexPid: bigint | null;
|
|
3361
|
+
/** This pair's WEIGHT in the RSUP emission stream (not a token balance). */
|
|
3362
|
+
rsupWeight: bigint | null;
|
|
3363
|
+
/** Convex reward streams on the staked collateral: reward wei per second per
|
|
3364
|
+
* 1e18 of staked SHARES, aggregated by token (a pool can list the same
|
|
3365
|
+
* token twice). */
|
|
3366
|
+
collateralRewards: {
|
|
3367
|
+
token: string;
|
|
3368
|
+
ratePerSecPerShare: bigint;
|
|
3369
|
+
}[];
|
|
3370
|
+
}
|
|
3371
|
+
/**
|
|
3372
|
+
* Chain-level RSUP emission state — one read for the whole roster.
|
|
3373
|
+
*
|
|
3374
|
+
* `pairEmissions` stakes governance WEIGHT, not tokens: `totalWeight` is the
|
|
3375
|
+
* sum over all pairs and each pair's slice is its `rsupWeight`. A pair's RSUP
|
|
3376
|
+
* per second is `rewardRate x rsupWeight / totalWeight`.
|
|
3377
|
+
*/
|
|
3378
|
+
interface ResupplyRsupEmissions {
|
|
3379
|
+
/** The RSUP token. */
|
|
3380
|
+
govToken: string;
|
|
3381
|
+
/** RSUP wei per second across ALL pairs. */
|
|
3382
|
+
rewardRate: bigint;
|
|
3383
|
+
/** Sum of every pair's weight. */
|
|
3384
|
+
totalWeight: bigint;
|
|
3385
|
+
/** Emissions stop here; past it the stream pays nothing. */
|
|
3386
|
+
periodFinish: bigint;
|
|
3307
3387
|
}
|
|
3308
3388
|
interface ResupplyMarketsRaw {
|
|
3309
3389
|
lender: string;
|
|
3310
3390
|
config?: ResupplyConfigChain;
|
|
3311
3391
|
pairs: ResupplyPairRaw[];
|
|
3392
|
+
/** Absent when the stream has ended or could not be read. */
|
|
3393
|
+
rsup?: ResupplyRsupEmissions;
|
|
3312
3394
|
}
|
|
3313
3395
|
|
|
3314
3396
|
/**
|
|
@@ -3556,28 +3638,6 @@ declare function llamaLendKeyParts(key: string): {
|
|
|
3556
3638
|
lender: string;
|
|
3557
3639
|
controller: string;
|
|
3558
3640
|
} | undefined;
|
|
3559
|
-
/**
|
|
3560
|
-
* Map the LlamaLend batch into the shared `MorphoGeneralPublicResponse` shape,
|
|
3561
|
-
* keyed by `LLAMALEND_<CONTROLLER_ADDR>` — one key per market.
|
|
3562
|
-
*
|
|
3563
|
-
* Per market, two entries in the isolated-pair layout:
|
|
3564
|
-
*
|
|
3565
|
-
* - COLLATERAL entry — deposit-only. `collateralFactor` is the LTV AT THE
|
|
3566
|
-
* MARKET'S DEFAULT BAND COUNT, because LlamaLend has no market-constant
|
|
3567
|
-
* LTV: it is a function of `N` and moves 0.886..0.991 on a single market.
|
|
3568
|
-
* The whole curve rides along in `params.market.llamalend.bandLtv` so the
|
|
3569
|
-
* UI can show the trade-off and the leverage sizer can use the real number
|
|
3570
|
-
* for the `N` the user actually picks.
|
|
3571
|
-
* - LOAN entry — the borrowed token. Supply side is the ERC-4626 vault, so
|
|
3572
|
-
* unlike Inverse this one HAS `totalDeposits`.
|
|
3573
|
-
*
|
|
3574
|
-
* SOFT LIQUIDATION is the thing this shape cannot express natively, so it is
|
|
3575
|
-
* carried explicitly in the descriptor. `liquidationPenalty` here is the HARD
|
|
3576
|
-
* liquidation bonus only — it applies below the entire band range. Inside the
|
|
3577
|
-
* range a position is converted gradually through the market's own AMM with no
|
|
3578
|
-
* penalty at all, and a consumer that renders `liquidationPenalty` as "what
|
|
3579
|
-
* you lose when the price hits X" is describing the wrong event.
|
|
3580
|
-
*/
|
|
3581
3641
|
declare function convertLlamaLendMarketsToResponse(raw: LlamaLendMarketsRaw, chainId: string, prices?: {
|
|
3582
3642
|
[asset: string]: number;
|
|
3583
3643
|
}, additionalYields?: AdditionalYields, tokens?: GenericTokenList): {
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { fetchTokenLists, fetchTokenList, aavePools, compoundV3Pools, initConfig
|
|
|
7
7
|
import lodash from 'lodash';
|
|
8
8
|
import { Chain } from '@1delta/chain-registry';
|
|
9
9
|
import { multicallRetryUniversal, getEvmClient, getEvmChain, getEvmClientUniversal } from '@1delta/providers';
|
|
10
|
-
import { LiquityTroveManagerAbi, LiquityActivePoolAbi, LiquityStabilityPoolAbi, LiquityPriceFeedAbi, LiquitySortedTrovesAbi, RiverTroveManagerAbi, RiverStabilityPoolAbi, TellerMarketRegistryAbi, TellerV2Abi, InverseMarketAbi, InverseOracleAbi, InverseDbrAbi, Erc20Abi, LlamaLendControllerAbi, LlamaLendControllerV1Abi, LlamaLendControllerV2Abi, LlamaLendVaultAbi, LlamaLendAmmAbi, MetaMorphoAbi, ExactlyPreviewerAbi, ExactlyAuditorAbi, LenderCommitmentGroupAbi, ResupplyRegistryAbi, ResupplyPairAbi, UsddVatAbi, UsddJugAbi, UsddSpotAbi, FrankencoinPositionAbi, FluidLendingResolverAbi, FluidVaultResolverAbi, FluidLiquidityResolverAbi, MoolahVaultAbi,
|
|
10
|
+
import { LiquityTroveManagerAbi, LiquityActivePoolAbi, LiquityStabilityPoolAbi, LiquityPriceFeedAbi, LiquitySortedTrovesAbi, RiverTroveManagerAbi, RiverStabilityPoolAbi, TellerMarketRegistryAbi, TellerV2Abi, InverseMarketAbi, InverseOracleAbi, InverseDbrAbi, Erc20Abi, LlamaLendControllerAbi, LlamaLendControllerV1Abi, LlamaLendControllerV2Abi, LlamaLendVaultAbi, LlamaLendAmmAbi, MetaMorphoAbi, ExactlyPreviewerAbi, ExactlyAuditorAbi, LenderCommitmentGroupAbi, ResupplyRegistryAbi, ResupplyPairAbi, ResupplyUtilitiesAbi, ResupplyRewardHandlerAbi, ResupplyPairEmissionsAbi, ConvexPoolUtilAbi, UsddVatAbi, UsddJugAbi, UsddSpotAbi, FrankencoinPositionAbi, FluidLendingResolverAbi, FluidVaultResolverAbi, FluidLiquidityResolverAbi, MoolahVaultAbi, MorphoLensAbi, AaveV4SpokeAbi, AaveV4OracleAbi, AaveV4HubAbi, DolomiteMarginAbi, GearboxMarketCompressorV310Abi, MorphoBlueAbi, MidnightAbi, TermRepoTokenAbi, TermRepoServicerAbi, TermRepoCollateralManagerAbi, LiquityTroveNFTAbi, LiquityCollSurplusPoolAbi, TellerCollateralManagerAbi, TermMaxViewerAbi, InverseEscrowAbi, CurvanceMarketManagerAbi, CurvanceCTokenAbi, GearboxCreditAccountCompressorV310Abi, UsddCdpManagerAbi, UsddProxyRegistryAbi, CurvanceProtocolReaderAbi, CurvanceCentralRegistryAbi, TermPriceConsumerAbi, CurvanceOracleManagerAbi, TermMaxOracleAggregatorV2Abi } from '@1delta/abis';
|
|
11
11
|
export { MorphoLensAbi } from '@1delta/abis';
|
|
12
12
|
import { prepareDebitDataMulticall, prepareLenderDebitMulticall, parseDebitDataResult, parseLenderDebitResult, getPermit2ContractAddress, getCompoundV3CometAddress as getCompoundV3CometAddress$1, getMorphoAddress, getAaveCollateralTokenAddress, getSiloHalfForUnderlying, InitMarginAddresses, getLstAcceptedInputs } from '@1delta/calldata-sdk';
|
|
13
13
|
import { proxyNativeFetch } from '@1delta/proxy-fetch';
|
|
@@ -21401,6 +21401,19 @@ function convertLiquityMarketsToResponse(raw, chainId, prices = {}, _additionalY
|
|
|
21401
21401
|
borrowLiquidity = Math.min(borrowLiquidity, Math.max(0, cap - entireDebt));
|
|
21402
21402
|
}
|
|
21403
21403
|
if (shutdown) borrowLiquidity = 0;
|
|
21404
|
+
const rateParameter = {
|
|
21405
|
+
kind: "interest-rate",
|
|
21406
|
+
dimension: "rate",
|
|
21407
|
+
domain: {
|
|
21408
|
+
min: Number(cfg.minAnnualInterestRate ?? 0) / 1e18,
|
|
21409
|
+
max: Number(cfg.maxAnnualInterestRate ?? 0) / 1e18
|
|
21410
|
+
},
|
|
21411
|
+
// No protocol default — the borrower must choose. The low end is the
|
|
21412
|
+
// cheapest but the first to be redeemed against.
|
|
21413
|
+
default: Number(cfg.minAnnualInterestRate ?? 0) / 1e18,
|
|
21414
|
+
immutableAfterOpen: false,
|
|
21415
|
+
adjustCooldownSeconds: cfg.interestRateAdjCooldownSeconds ? Number(cfg.interestRateAdjCooldownSeconds) : void 0
|
|
21416
|
+
};
|
|
21404
21417
|
const entry = { data: {} };
|
|
21405
21418
|
const collUid = createMarketUid(chainId, lenderKey, collAddr);
|
|
21406
21419
|
entry.data[collUid] = {
|
|
@@ -21435,7 +21448,18 @@ function convertLiquityMarketsToResponse(raw, chainId, prices = {}, _additionalY
|
|
|
21435
21448
|
liquidationPenalty: liqPenalty,
|
|
21436
21449
|
closeFactor: 1,
|
|
21437
21450
|
collateralDisabled: false,
|
|
21438
|
-
debtDisabled: true
|
|
21451
|
+
debtDisabled: true,
|
|
21452
|
+
/**
|
|
21453
|
+
* Liquity's borrower picks their own interest rate at open, and it
|
|
21454
|
+
* sets redemption priority as well as cost — so it is a real
|
|
21455
|
+
* parameter, not a quoted rate.
|
|
21456
|
+
*
|
|
21457
|
+
* The MUTABLE case: adjustable in place, but rate-limited by
|
|
21458
|
+
* `interestRateAdjCooldownSeconds` and fee-charged if adjusted
|
|
21459
|
+
* early. The per-trove value lives in `modes[troveId]`, because one
|
|
21460
|
+
* address can hold several troves at different rates at once.
|
|
21461
|
+
*/
|
|
21462
|
+
openParameter: rateParameter
|
|
21439
21463
|
}
|
|
21440
21464
|
},
|
|
21441
21465
|
closeFactor: 1,
|
|
@@ -23205,7 +23229,7 @@ var VAULT_PRICE_ABI = [
|
|
|
23205
23229
|
}
|
|
23206
23230
|
];
|
|
23207
23231
|
var IDENTITY_READS = 3;
|
|
23208
|
-
var STATE_READS =
|
|
23232
|
+
var STATE_READS = 14;
|
|
23209
23233
|
var ONE = 10n ** 18n;
|
|
23210
23234
|
var identityCache = /* @__PURE__ */ new Map();
|
|
23211
23235
|
var identityKey = (chainId, pair) => `${chainId}:${pair.toLowerCase()}`;
|
|
@@ -23312,6 +23336,11 @@ async function fetchResupplyMarkets(lender, chainId) {
|
|
|
23312
23336
|
}
|
|
23313
23337
|
const identities = discovered.map((p) => identityCache.get(identityKey(chainId, p))).filter((x) => !!x);
|
|
23314
23338
|
if (identities.length === 0) return { lender, config, pairs: [] };
|
|
23339
|
+
const { rsup, pairEmissions, convexPoolUtil } = await readRewardContext(
|
|
23340
|
+
chainId,
|
|
23341
|
+
config.registry,
|
|
23342
|
+
config.utilities
|
|
23343
|
+
);
|
|
23315
23344
|
const utilities = config.utilities;
|
|
23316
23345
|
const calls = [];
|
|
23317
23346
|
const abis = [];
|
|
@@ -23328,7 +23357,16 @@ async function fetchResupplyMarkets(lender, chainId) {
|
|
|
23328
23357
|
// The collateral vault's own share price — the exact input Resupply's
|
|
23329
23358
|
// `BasicVaultOracle` uses. Read LIVE rather than inverting the pair's
|
|
23330
23359
|
// cached `exchangeRate`, which only moves when someone writes.
|
|
23331
|
-
{ address: id.collateral, name: "convertToAssets", params: [ONE] }
|
|
23360
|
+
{ address: id.collateral, name: "convertToAssets", params: [ONE] },
|
|
23361
|
+
// Rewards. `convexPid == 0` means the collateral is not staked, so there
|
|
23362
|
+
// is nothing to report; the weight is this pair's slice of the RSUP
|
|
23363
|
+
// stream. Both are governance-mutable, so neither is cached.
|
|
23364
|
+
{ address: id.pair, name: "convexPid", params: [] },
|
|
23365
|
+
{
|
|
23366
|
+
address: pairEmissions ?? id.pair,
|
|
23367
|
+
name: pairEmissions ? "balanceOf" : "convexPid",
|
|
23368
|
+
params: pairEmissions ? [id.pair] : []
|
|
23369
|
+
}
|
|
23332
23370
|
);
|
|
23333
23371
|
abis.push(
|
|
23334
23372
|
ResupplyPairAbi,
|
|
@@ -23339,7 +23377,9 @@ async function fetchResupplyMarkets(lender, chainId) {
|
|
|
23339
23377
|
ResupplyPairAbi,
|
|
23340
23378
|
ResupplyPairAbi,
|
|
23341
23379
|
ResupplyPairAbi,
|
|
23342
|
-
VAULT_PRICE_ABI
|
|
23380
|
+
VAULT_PRICE_ABI,
|
|
23381
|
+
ResupplyPairAbi,
|
|
23382
|
+
pairEmissions ? ResupplyPairEmissionsAbi : ResupplyPairAbi
|
|
23343
23383
|
);
|
|
23344
23384
|
if (utilities) {
|
|
23345
23385
|
calls.push(
|
|
@@ -23397,11 +23437,118 @@ async function fetchResupplyMarkets(lender, chainId) {
|
|
|
23397
23437
|
ratePerSec: tuple(rateInfo, 1),
|
|
23398
23438
|
exchangeRate: tuple(exchangeInfo, 2),
|
|
23399
23439
|
collateralPrice: big(results[base + 8]),
|
|
23400
|
-
|
|
23401
|
-
|
|
23440
|
+
// Indices follow the PUSH ORDER above exactly: the two reward reads sit
|
|
23441
|
+
// at +9/+10, BEFORE the lens block, so the lens reads are +11/+12.
|
|
23442
|
+
// (Getting this wrong is silent — it produced a 3-billion-percent APR
|
|
23443
|
+
// before the numbers were checked against a hand computation.)
|
|
23444
|
+
convexPid: big(results[base + 9]),
|
|
23445
|
+
rsupWeight: pairEmissions ? big(results[base + 10]) : null,
|
|
23446
|
+
liveRatePerSec: utilities ? big(results[base + 11]) : null,
|
|
23447
|
+
underlyingSupplyRatePerSec: utilities ? big(results[base + 12]) : null,
|
|
23448
|
+
collateralRewards: []
|
|
23402
23449
|
};
|
|
23403
23450
|
});
|
|
23404
|
-
|
|
23451
|
+
await attachCollateralRewards(chainId, convexPoolUtil, pairs);
|
|
23452
|
+
return { lender, config, pairs, rsup };
|
|
23453
|
+
}
|
|
23454
|
+
async function readRewardContext(chainId, registry, utilities) {
|
|
23455
|
+
const addr2 = (v) => typeof v === "string" && v.startsWith("0x") && !/^0x0+$/.test(v) ? v : void 0;
|
|
23456
|
+
try {
|
|
23457
|
+
const first = await multicallRetryUniversal({
|
|
23458
|
+
chain: chainId,
|
|
23459
|
+
calls: [
|
|
23460
|
+
{ address: registry, name: "rewardHandler", params: [] },
|
|
23461
|
+
{ address: registry, name: "govToken", params: [] },
|
|
23462
|
+
...utilities ? [{ address: utilities, name: "convexPoolUtil", params: [] }] : []
|
|
23463
|
+
],
|
|
23464
|
+
abi: [
|
|
23465
|
+
ResupplyRegistryAbi,
|
|
23466
|
+
ResupplyRegistryAbi,
|
|
23467
|
+
...utilities ? [ResupplyUtilitiesAbi] : []
|
|
23468
|
+
],
|
|
23469
|
+
allowFailure: true
|
|
23470
|
+
});
|
|
23471
|
+
const rewardHandler = addr2(first[0]);
|
|
23472
|
+
const govToken = addr2(first[1]);
|
|
23473
|
+
const convexPoolUtil = utilities ? addr2(first[2]) : void 0;
|
|
23474
|
+
if (!rewardHandler || !govToken) return { convexPoolUtil };
|
|
23475
|
+
const [emissions] = await multicallRetryUniversal({
|
|
23476
|
+
chain: chainId,
|
|
23477
|
+
calls: [{ address: rewardHandler, name: "pairEmissions", params: [] }],
|
|
23478
|
+
abi: ResupplyRewardHandlerAbi,
|
|
23479
|
+
allowFailure: true
|
|
23480
|
+
});
|
|
23481
|
+
const pairEmissions = addr2(emissions);
|
|
23482
|
+
if (!pairEmissions) return { convexPoolUtil };
|
|
23483
|
+
const stream = await multicallRetryUniversal({
|
|
23484
|
+
chain: chainId,
|
|
23485
|
+
calls: [
|
|
23486
|
+
{ address: pairEmissions, name: "periodFinish", params: [] },
|
|
23487
|
+
{ address: pairEmissions, name: "rewardRate", params: [] },
|
|
23488
|
+
{ address: pairEmissions, name: "totalSupply", params: [] }
|
|
23489
|
+
],
|
|
23490
|
+
abi: [
|
|
23491
|
+
ResupplyPairEmissionsAbi,
|
|
23492
|
+
ResupplyPairEmissionsAbi,
|
|
23493
|
+
ResupplyPairEmissionsAbi
|
|
23494
|
+
],
|
|
23495
|
+
allowFailure: true
|
|
23496
|
+
});
|
|
23497
|
+
const periodFinish = big(stream[0]);
|
|
23498
|
+
const rewardRate = big(stream[1]);
|
|
23499
|
+
const totalWeight = big(stream[2]);
|
|
23500
|
+
if (periodFinish === null || rewardRate === null || totalWeight === null || totalWeight === 0n) {
|
|
23501
|
+
return { pairEmissions, convexPoolUtil };
|
|
23502
|
+
}
|
|
23503
|
+
if (periodFinish <= BigInt(Math.floor(Date.now() / 1e3))) {
|
|
23504
|
+
return { pairEmissions, convexPoolUtil };
|
|
23505
|
+
}
|
|
23506
|
+
return {
|
|
23507
|
+
rsup: { govToken, rewardRate, totalWeight, periodFinish },
|
|
23508
|
+
pairEmissions,
|
|
23509
|
+
convexPoolUtil
|
|
23510
|
+
};
|
|
23511
|
+
} catch {
|
|
23512
|
+
return {};
|
|
23513
|
+
}
|
|
23514
|
+
}
|
|
23515
|
+
async function attachCollateralRewards(chainId, convexPoolUtil, pairs) {
|
|
23516
|
+
if (!convexPoolUtil) return;
|
|
23517
|
+
const staked = pairs.filter((p) => (p.convexPid ?? 0n) > 0n);
|
|
23518
|
+
if (staked.length === 0) return;
|
|
23519
|
+
let res = [];
|
|
23520
|
+
try {
|
|
23521
|
+
res = await multicallRetryUniversal({
|
|
23522
|
+
chain: chainId,
|
|
23523
|
+
calls: staked.map((p) => ({
|
|
23524
|
+
address: convexPoolUtil,
|
|
23525
|
+
name: "rewardRates",
|
|
23526
|
+
params: [p.convexPid]
|
|
23527
|
+
})),
|
|
23528
|
+
abi: staked.map(() => ConvexPoolUtilAbi),
|
|
23529
|
+
allowFailure: true
|
|
23530
|
+
});
|
|
23531
|
+
} catch {
|
|
23532
|
+
return;
|
|
23533
|
+
}
|
|
23534
|
+
staked.forEach((p, i) => {
|
|
23535
|
+
const entry = res[i];
|
|
23536
|
+
if (!Array.isArray(entry)) return;
|
|
23537
|
+
const [tokens, rates] = entry;
|
|
23538
|
+
if (!Array.isArray(tokens) || !Array.isArray(rates)) return;
|
|
23539
|
+
const byToken = /* @__PURE__ */ new Map();
|
|
23540
|
+
tokens.forEach((t, j) => {
|
|
23541
|
+
const rate = rates[j];
|
|
23542
|
+
if (typeof t !== "string" || typeof rate !== "bigint" || rate === 0n) {
|
|
23543
|
+
return;
|
|
23544
|
+
}
|
|
23545
|
+
const key2 = t.toLowerCase();
|
|
23546
|
+
byToken.set(key2, (byToken.get(key2) ?? 0n) + rate);
|
|
23547
|
+
});
|
|
23548
|
+
p.collateralRewards = [...byToken.entries()].map(
|
|
23549
|
+
([token, ratePerSecPerShare]) => ({ token, ratePerSecPerShare })
|
|
23550
|
+
);
|
|
23551
|
+
});
|
|
23405
23552
|
}
|
|
23406
23553
|
|
|
23407
23554
|
// src/prices/oracle-prices/fetchers/curvanceRoster.ts
|
|
@@ -23991,6 +24138,8 @@ function currencyFor9(address, decimals, symbol, tokens) {
|
|
|
23991
24138
|
const lower3 = address.toLowerCase();
|
|
23992
24139
|
return tokens[lower3] ?? { address: lower3, symbol, name: symbol, decimals };
|
|
23993
24140
|
}
|
|
24141
|
+
var LLAMALEND_MIN_BANDS = 4;
|
|
24142
|
+
var LLAMALEND_MAX_BANDS = 50;
|
|
23994
24143
|
function convertLlamaLendMarketsToResponse(raw, chainId, prices = {}, additionalYields = {
|
|
23995
24144
|
intrinsicYields: {},
|
|
23996
24145
|
lenderRewards: {},
|
|
@@ -24027,6 +24176,13 @@ function convertLlamaLendMarketsToResponse(raw, chainId, prices = {}, additional
|
|
|
24027
24176
|
const liqPenalty = Number(market.liquidationDiscount) / 1e18 || 0;
|
|
24028
24177
|
const closeFactor = 1;
|
|
24029
24178
|
const depositsEnabled = (m.maxDeposit ?? 0) > 0;
|
|
24179
|
+
const bandParameter = {
|
|
24180
|
+
kind: "llamalend-bands",
|
|
24181
|
+
dimension: "collateralFactor",
|
|
24182
|
+
domain: { min: LLAMALEND_MIN_BANDS, max: LLAMALEND_MAX_BANDS },
|
|
24183
|
+
default: market.defaultBands ?? 10,
|
|
24184
|
+
immutableAfterOpen: true
|
|
24185
|
+
};
|
|
24030
24186
|
const entry = { data: {} };
|
|
24031
24187
|
const collUid = createMarketUid(chainId, lenderKey, collAddr);
|
|
24032
24188
|
entry.data[collUid] = {
|
|
@@ -24064,7 +24220,8 @@ function convertLlamaLendMarketsToResponse(raw, chainId, prices = {}, additional
|
|
|
24064
24220
|
liquidationPenalty: liqPenalty,
|
|
24065
24221
|
closeFactor,
|
|
24066
24222
|
collateralDisabled: false,
|
|
24067
|
-
debtDisabled: true
|
|
24223
|
+
debtDisabled: true,
|
|
24224
|
+
openParameter: bandParameter
|
|
24068
24225
|
}
|
|
24069
24226
|
},
|
|
24070
24227
|
closeFactor,
|
|
@@ -24263,6 +24420,52 @@ function ratePerSecToApr(rate) {
|
|
|
24263
24420
|
if (rate === null) return 0;
|
|
24264
24421
|
return Number(rate) / 1e18 * SECONDS_PER_YEAR9 * 100;
|
|
24265
24422
|
}
|
|
24423
|
+
function buildRewardEntries(p, rsup, chainId, prices, tokens, collateralUsd, debtUsd) {
|
|
24424
|
+
const priceOf = (address) => {
|
|
24425
|
+
const lower3 = address.toLowerCase();
|
|
24426
|
+
const token = tokens[lower3];
|
|
24427
|
+
const key2 = toOracleKey(token?.assetGroup) || toGenericPriceKey(lower3, chainId);
|
|
24428
|
+
return prices[key2] ?? 0;
|
|
24429
|
+
};
|
|
24430
|
+
const collateral = [];
|
|
24431
|
+
if (collateralUsd > 0) {
|
|
24432
|
+
for (const r of p.collateralRewards ?? []) {
|
|
24433
|
+
const price2 = priceOf(r.token);
|
|
24434
|
+
if (price2 <= 0) continue;
|
|
24435
|
+
const decimals = tokens[r.token.toLowerCase()]?.decimals ?? 18;
|
|
24436
|
+
const perSecond = Number(r.ratePerSecPerShare) * Number(p.totalCollateral ?? 0n) / 1e18;
|
|
24437
|
+
const usdPerYear = perSecond / 10 ** decimals * SECONDS_PER_YEAR9 * price2;
|
|
24438
|
+
const apr = usdPerYear / collateralUsd * 100;
|
|
24439
|
+
if (!Number.isFinite(apr) || apr <= 0) continue;
|
|
24440
|
+
collateral.push({
|
|
24441
|
+
asset: r.token,
|
|
24442
|
+
depositRate: apr,
|
|
24443
|
+
variableBorrowRate: 0,
|
|
24444
|
+
stableBorrowRate: 0
|
|
24445
|
+
});
|
|
24446
|
+
}
|
|
24447
|
+
}
|
|
24448
|
+
const borrow = [];
|
|
24449
|
+
if (rsup && debtUsd > 0 && (p.rsupWeight ?? 0n) > 0n) {
|
|
24450
|
+
const price2 = priceOf(rsup.govToken);
|
|
24451
|
+
if (price2 > 0) {
|
|
24452
|
+
const decimals = tokens[rsup.govToken.toLowerCase()]?.decimals ?? 18;
|
|
24453
|
+
const perSecond = Number(rsup.rewardRate) * Number(p.rsupWeight) / Number(rsup.totalWeight);
|
|
24454
|
+
const usdPerYear = perSecond / 10 ** decimals * SECONDS_PER_YEAR9 * price2;
|
|
24455
|
+
const apr = usdPerYear / debtUsd * 100;
|
|
24456
|
+
if (Number.isFinite(apr) && apr > 0) {
|
|
24457
|
+
borrow.push({
|
|
24458
|
+
asset: rsup.govToken,
|
|
24459
|
+
depositRate: 0,
|
|
24460
|
+
// A REBATE on the borrow cost, not a charge.
|
|
24461
|
+
variableBorrowRate: apr,
|
|
24462
|
+
stableBorrowRate: 0
|
|
24463
|
+
});
|
|
24464
|
+
}
|
|
24465
|
+
}
|
|
24466
|
+
}
|
|
24467
|
+
return { collateral, borrow };
|
|
24468
|
+
}
|
|
24266
24469
|
function convertResupplyMarketsToResponse(raw, chainId, prices = {}, _additionalYields = {
|
|
24267
24470
|
intrinsicYields: {},
|
|
24268
24471
|
lenderRewards: {},
|
|
@@ -24298,6 +24501,15 @@ function convertResupplyMarketsToResponse(raw, chainId, prices = {}, _additional
|
|
|
24298
24501
|
const borrowLiquidity = Math.max(borrowLimit - totalDebt, 0);
|
|
24299
24502
|
const halted = (p.borrowLimit ?? 0n) === 0n;
|
|
24300
24503
|
const wrappedMarket = resolveWrappedMarket(chainId, id.collateral, id.name);
|
|
24504
|
+
const rewardEntries = buildRewardEntries(
|
|
24505
|
+
p,
|
|
24506
|
+
raw.rsup,
|
|
24507
|
+
chainId,
|
|
24508
|
+
prices,
|
|
24509
|
+
tokens,
|
|
24510
|
+
totalColl * collPrice,
|
|
24511
|
+
totalDebt * debtPrice
|
|
24512
|
+
);
|
|
24301
24513
|
const maxLtv = p.maxLTV !== null ? Number(p.maxLTV) / LTV_PRECISION : 0;
|
|
24302
24514
|
const liquidationPenalty = p.liquidationFee !== null ? Number(p.liquidationFee) / LTV_PRECISION : 0;
|
|
24303
24515
|
const mintFeePct = p.mintFee !== null ? Number(p.mintFee) / LTV_PRECISION * 100 : 0;
|
|
@@ -24328,7 +24540,9 @@ function convertResupplyMarketsToResponse(raw, chainId, prices = {}, _additional
|
|
|
24328
24540
|
// The wrapped Curve Lend / Fraxlend supply rate — this collateral is a
|
|
24329
24541
|
// lending position and earns while it sits here.
|
|
24330
24542
|
intrinsicYield: collateralIntrinsicApr,
|
|
24331
|
-
|
|
24543
|
+
// CRV/CVX from the Convex position the pair stakes the collateral into.
|
|
24544
|
+
// Empty (not undefined) when the pair does not stake — `convexPid == 0`.
|
|
24545
|
+
rewards: rewardEntries.collateral,
|
|
24332
24546
|
decimals: collDecimals,
|
|
24333
24547
|
config: {
|
|
24334
24548
|
0: {
|
|
@@ -24385,7 +24599,9 @@ function convertResupplyMarketsToResponse(raw, chainId, prices = {}, _additional
|
|
|
24385
24599
|
// but it is governance-settable.
|
|
24386
24600
|
originationFee: mintFeePct,
|
|
24387
24601
|
intrinsicYield: 0,
|
|
24388
|
-
|
|
24602
|
+
// RSUP emissions to BORROWERS — a rebate on `variableBorrowRate`, not a
|
|
24603
|
+
// deposit yield. Empty when the emission stream has expired.
|
|
24604
|
+
rewards: rewardEntries.borrow,
|
|
24389
24605
|
decimals: debtDecimals,
|
|
24390
24606
|
config: {
|
|
24391
24607
|
0: {
|
|
@@ -31141,7 +31357,7 @@ var getLiquityUserDataConverter = (lender, chainId, account, meta) => {
|
|
|
31141
31357
|
troveInfo
|
|
31142
31358
|
}
|
|
31143
31359
|
};
|
|
31144
|
-
modes[t.troveId] =
|
|
31360
|
+
modes[t.troveId] = Number(troveInfo.annualInterestRate) / 1e18;
|
|
31145
31361
|
hist[t.troveId] = {
|
|
31146
31362
|
totalDeposits24h: collNum * collHist,
|
|
31147
31363
|
totalDebt24h: debtNum * loanHist
|
|
@@ -31601,7 +31817,7 @@ var getLlamaLendUserDataConverter = (lender, chainId, account, meta) => {
|
|
|
31601
31817
|
}
|
|
31602
31818
|
}
|
|
31603
31819
|
};
|
|
31604
|
-
const modes = { "0":
|
|
31820
|
+
const modes = { "0": bandCount };
|
|
31605
31821
|
const hist = {
|
|
31606
31822
|
"0": {
|
|
31607
31823
|
totalDeposits24h: collNum * collHist + bandBorrowedNum * loanHist,
|