@1delta/margin-fetcher 5.0.17 → 5.0.19
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/README.md +164 -116
- package/dist/index.js +470 -32
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -7056,9 +7056,9 @@ var calculateRateForCompoundType2 = (n) => {
|
|
|
7056
7056
|
const rate = Number(formatEther(BigInt(n)));
|
|
7057
7057
|
return (Math.pow(rate * 60 * 60 * 24 / 12 + 1, 365) - 1) * 100;
|
|
7058
7058
|
};
|
|
7059
|
-
var calculateRateForCompoundType = (n, chainId,
|
|
7059
|
+
var calculateRateForCompoundType = (n, chainId, scale3 = 1 /* SECOND */) => {
|
|
7060
7060
|
const rate = Number(formatEther(BigInt(n)));
|
|
7061
|
-
if (
|
|
7061
|
+
if (scale3 === 0 /* BLOCK */)
|
|
7062
7062
|
return (Math.pow(
|
|
7063
7063
|
rate * 60 * 60 * 24 / (BLOCK_TIMES[chainId] ?? "1") + 1,
|
|
7064
7064
|
365
|
|
@@ -20624,8 +20624,8 @@ var TermSubgraphSource = class {
|
|
|
20624
20624
|
const auction = data.termAuctions?.[0];
|
|
20625
20625
|
const clearingRate = toNum(auction?.auctionClearingPrice);
|
|
20626
20626
|
const aprPct = clearingRate > 0 ? clearingRate / WAD3 * 100 : 0;
|
|
20627
|
-
const
|
|
20628
|
-
const toLoan = (repoUnits) => Number(repoUnits * redemptionRatio / BigInt(WAD3)) /
|
|
20627
|
+
const scale3 = Math.pow(10, config.loanDecimals);
|
|
20628
|
+
const toLoan = (repoUnits) => Number(repoUnits * redemptionRatio / BigInt(WAD3)) / scale3;
|
|
20629
20629
|
const orders = (data.termOrders ?? []).map((o) => ({
|
|
20630
20630
|
remaining: toBig3(o.originalOrderAmount) - toBig3(o.filledAmount),
|
|
20631
20631
|
isAsk: String(o.makerToken).toLowerCase() === repoToken
|
|
@@ -20714,7 +20714,7 @@ var TermSubgraphSource = class {
|
|
|
20714
20714
|
{ term, who }
|
|
20715
20715
|
);
|
|
20716
20716
|
if (!data) return null;
|
|
20717
|
-
const
|
|
20717
|
+
const scale3 = Math.pow(10, config.loanDecimals);
|
|
20718
20718
|
const toOrder = (o, side, revealedRaw) => {
|
|
20719
20719
|
const a = o.auction ?? {};
|
|
20720
20720
|
const complete = Boolean(a.auctionComplete);
|
|
@@ -20726,7 +20726,7 @@ var TermSubgraphSource = class {
|
|
|
20726
20726
|
auctionId: String(a.id ?? ""),
|
|
20727
20727
|
account,
|
|
20728
20728
|
amount: String(o.amount ?? "0"),
|
|
20729
|
-
assets: Number(toBig3(o.amount)) /
|
|
20729
|
+
assets: Number(toBig3(o.amount)) / scale3,
|
|
20730
20730
|
assignedAmount: String(o.assignedAmount ?? "0"),
|
|
20731
20731
|
locked: Boolean(o.locked),
|
|
20732
20732
|
revealed,
|
|
@@ -24552,7 +24552,7 @@ function ratePerSecToApr(rate) {
|
|
|
24552
24552
|
return Number(rate) / 1e18 * SECONDS_PER_YEAR9 * 100;
|
|
24553
24553
|
}
|
|
24554
24554
|
function buildRewardEntries(p, rsup, chainId, prices, tokens, collateralUsd, debtUsd) {
|
|
24555
|
-
const
|
|
24555
|
+
const priceOf2 = (address) => {
|
|
24556
24556
|
const lower3 = address.toLowerCase();
|
|
24557
24557
|
const token = tokens[lower3];
|
|
24558
24558
|
const key2 = toOracleKey(token?.assetGroup) || toGenericPriceKey(lower3, chainId);
|
|
@@ -24561,7 +24561,7 @@ function buildRewardEntries(p, rsup, chainId, prices, tokens, collateralUsd, deb
|
|
|
24561
24561
|
const collateral = [];
|
|
24562
24562
|
if (collateralUsd > 0) {
|
|
24563
24563
|
for (const r of p.collateralRewards ?? []) {
|
|
24564
|
-
const price2 =
|
|
24564
|
+
const price2 = priceOf2(r.token);
|
|
24565
24565
|
if (price2 <= 0) continue;
|
|
24566
24566
|
const decimals = tokens[r.token.toLowerCase()]?.decimals ?? 18;
|
|
24567
24567
|
const perSecond = Number(r.ratePerSecPerShare) * Number(p.totalCollateral ?? 0n) / 1e18;
|
|
@@ -24578,7 +24578,7 @@ function buildRewardEntries(p, rsup, chainId, prices, tokens, collateralUsd, deb
|
|
|
24578
24578
|
}
|
|
24579
24579
|
const borrow = [];
|
|
24580
24580
|
if (rsup && debtUsd > 0 && (p.rsupWeight ?? 0n) > 0n) {
|
|
24581
|
-
const price2 =
|
|
24581
|
+
const price2 = priceOf2(rsup.govToken);
|
|
24582
24582
|
if (price2 > 0) {
|
|
24583
24583
|
const decimals = tokens[rsup.govToken.toLowerCase()]?.decimals ?? 18;
|
|
24584
24584
|
const perSecond = Number(rsup.rewardRate) * Number(p.rsupWeight) / Number(rsup.totalWeight);
|
|
@@ -47184,6 +47184,443 @@ var dtrinityRebateRewardFetcher = {
|
|
|
47184
47184
|
return { byLender: merged };
|
|
47185
47185
|
}
|
|
47186
47186
|
};
|
|
47187
|
+
var SECONDS_PER_YEAR12 = 31536e3;
|
|
47188
|
+
var WAD14 = 10n ** 18n;
|
|
47189
|
+
var ZERO2 = "0x0000000000000000000000000000000000000000";
|
|
47190
|
+
var UNBOOSTED_FACTOR = 0.4;
|
|
47191
|
+
var MAX_BOOST = 2.5;
|
|
47192
|
+
var GAUGE_CONTROLLER = "0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB";
|
|
47193
|
+
var L1_CHAINS = /* @__PURE__ */ new Set([Chain.ETHEREUM_MAINNET]);
|
|
47194
|
+
var GAUGE_ABI = [
|
|
47195
|
+
{
|
|
47196
|
+
name: "inflation_rate",
|
|
47197
|
+
type: "function",
|
|
47198
|
+
stateMutability: "view",
|
|
47199
|
+
inputs: [],
|
|
47200
|
+
outputs: [{ type: "uint256" }]
|
|
47201
|
+
},
|
|
47202
|
+
{
|
|
47203
|
+
name: "working_supply",
|
|
47204
|
+
type: "function",
|
|
47205
|
+
stateMutability: "view",
|
|
47206
|
+
inputs: [],
|
|
47207
|
+
outputs: [{ type: "uint256" }]
|
|
47208
|
+
},
|
|
47209
|
+
{
|
|
47210
|
+
name: "totalSupply",
|
|
47211
|
+
type: "function",
|
|
47212
|
+
stateMutability: "view",
|
|
47213
|
+
inputs: [],
|
|
47214
|
+
outputs: [{ type: "uint256" }]
|
|
47215
|
+
},
|
|
47216
|
+
{
|
|
47217
|
+
name: "is_killed",
|
|
47218
|
+
type: "function",
|
|
47219
|
+
stateMutability: "view",
|
|
47220
|
+
inputs: [],
|
|
47221
|
+
outputs: [{ type: "bool" }]
|
|
47222
|
+
},
|
|
47223
|
+
{
|
|
47224
|
+
name: "reward_count",
|
|
47225
|
+
type: "function",
|
|
47226
|
+
stateMutability: "view",
|
|
47227
|
+
inputs: [],
|
|
47228
|
+
outputs: [{ type: "uint256" }]
|
|
47229
|
+
},
|
|
47230
|
+
{
|
|
47231
|
+
name: "reward_tokens",
|
|
47232
|
+
type: "function",
|
|
47233
|
+
stateMutability: "view",
|
|
47234
|
+
inputs: [{ type: "uint256" }],
|
|
47235
|
+
outputs: [{ type: "address" }]
|
|
47236
|
+
},
|
|
47237
|
+
{
|
|
47238
|
+
name: "reward_data",
|
|
47239
|
+
type: "function",
|
|
47240
|
+
stateMutability: "view",
|
|
47241
|
+
inputs: [{ type: "address" }],
|
|
47242
|
+
outputs: [
|
|
47243
|
+
{ name: "distributor", type: "address" },
|
|
47244
|
+
{ name: "period_finish", type: "uint256" },
|
|
47245
|
+
{ name: "rate", type: "uint256" },
|
|
47246
|
+
{ name: "last_update", type: "uint256" },
|
|
47247
|
+
{ name: "integral", type: "uint256" }
|
|
47248
|
+
]
|
|
47249
|
+
},
|
|
47250
|
+
{
|
|
47251
|
+
name: "gauge_relative_weight",
|
|
47252
|
+
type: "function",
|
|
47253
|
+
stateMutability: "view",
|
|
47254
|
+
inputs: [{ type: "address" }],
|
|
47255
|
+
outputs: [{ type: "uint256" }]
|
|
47256
|
+
},
|
|
47257
|
+
{
|
|
47258
|
+
name: "convertToAssets",
|
|
47259
|
+
type: "function",
|
|
47260
|
+
stateMutability: "view",
|
|
47261
|
+
inputs: [{ type: "uint256" }],
|
|
47262
|
+
outputs: [{ type: "uint256" }]
|
|
47263
|
+
},
|
|
47264
|
+
{
|
|
47265
|
+
name: "decimals",
|
|
47266
|
+
type: "function",
|
|
47267
|
+
stateMutability: "view",
|
|
47268
|
+
inputs: [],
|
|
47269
|
+
outputs: [{ type: "uint8" }]
|
|
47270
|
+
},
|
|
47271
|
+
{
|
|
47272
|
+
name: "symbol",
|
|
47273
|
+
type: "function",
|
|
47274
|
+
stateMutability: "view",
|
|
47275
|
+
inputs: [],
|
|
47276
|
+
outputs: [{ type: "string" }]
|
|
47277
|
+
}
|
|
47278
|
+
];
|
|
47279
|
+
var scale2 = (v, decimals) => Number(v) / 10 ** decimals;
|
|
47280
|
+
function crvGaugeApr(params) {
|
|
47281
|
+
const {
|
|
47282
|
+
inflationRate,
|
|
47283
|
+
relativeWeight,
|
|
47284
|
+
workingSupply,
|
|
47285
|
+
pricePerShare,
|
|
47286
|
+
crvPriceUsd,
|
|
47287
|
+
assetPriceUsd,
|
|
47288
|
+
isKilled
|
|
47289
|
+
} = params;
|
|
47290
|
+
if (isKilled) return 0;
|
|
47291
|
+
if (inflationRate <= 0n || relativeWeight <= 0n || workingSupply <= 0n) {
|
|
47292
|
+
return 0;
|
|
47293
|
+
}
|
|
47294
|
+
if (!(crvPriceUsd > 0) || !(assetPriceUsd > 0)) return 0;
|
|
47295
|
+
const crvPerYear = scale2(inflationRate, 18) * scale2(relativeWeight, 18) * SECONDS_PER_YEAR12;
|
|
47296
|
+
const stakedUsd = scale2(workingSupply, 18) * scale2(pricePerShare, 18) * assetPriceUsd;
|
|
47297
|
+
if (!(stakedUsd > 0)) return 0;
|
|
47298
|
+
return crvPerYear * crvPriceUsd / stakedUsd * 100 * UNBOOSTED_FACTOR;
|
|
47299
|
+
}
|
|
47300
|
+
function extraRewardApr(params) {
|
|
47301
|
+
const {
|
|
47302
|
+
rate,
|
|
47303
|
+
periodFinish,
|
|
47304
|
+
rewardDecimals,
|
|
47305
|
+
rewardPriceUsd,
|
|
47306
|
+
totalSupply,
|
|
47307
|
+
pricePerShare,
|
|
47308
|
+
assetPriceUsd,
|
|
47309
|
+
nowSeconds
|
|
47310
|
+
} = params;
|
|
47311
|
+
if (nowSeconds >= Number(periodFinish)) return 0;
|
|
47312
|
+
if (rate <= 0n || totalSupply <= 0n) return 0;
|
|
47313
|
+
if (!(rewardPriceUsd > 0) || !(assetPriceUsd > 0)) return 0;
|
|
47314
|
+
const rewardPerYearUsd = scale2(rate, rewardDecimals) * SECONDS_PER_YEAR12 * rewardPriceUsd;
|
|
47315
|
+
const stakedUsd = scale2(totalSupply, 18) * scale2(pricePerShare, 18) * assetPriceUsd;
|
|
47316
|
+
if (!(stakedUsd > 0)) return 0;
|
|
47317
|
+
return rewardPerYearUsd / stakedUsd * 100;
|
|
47318
|
+
}
|
|
47319
|
+
var MAX_PLAUSIBLE_TIMESTAMP = 64000000000n;
|
|
47320
|
+
function decodeRewardData(data) {
|
|
47321
|
+
if (!data) return null;
|
|
47322
|
+
const at = (i) => {
|
|
47323
|
+
try {
|
|
47324
|
+
const v = Array.isArray(data) ? data[i] : void 0;
|
|
47325
|
+
if (typeof v === "bigint") return v;
|
|
47326
|
+
if (typeof v === "string" && v !== "0x") return BigInt(v);
|
|
47327
|
+
if (typeof v === "number") return BigInt(Math.trunc(v));
|
|
47328
|
+
} catch {
|
|
47329
|
+
}
|
|
47330
|
+
return 0n;
|
|
47331
|
+
};
|
|
47332
|
+
if (!Array.isArray(data)) {
|
|
47333
|
+
const pf = data.period_finish;
|
|
47334
|
+
const rt = data.rate;
|
|
47335
|
+
if (pf === void 0 || rt === void 0) return null;
|
|
47336
|
+
return { periodFinish: BigInt(pf), rate: BigInt(rt) };
|
|
47337
|
+
}
|
|
47338
|
+
let periodFinish = at(1);
|
|
47339
|
+
let rate = at(2);
|
|
47340
|
+
if (periodFinish > MAX_PLAUSIBLE_TIMESTAMP) {
|
|
47341
|
+
periodFinish = at(2);
|
|
47342
|
+
rate = at(3);
|
|
47343
|
+
}
|
|
47344
|
+
if (periodFinish > MAX_PLAUSIBLE_TIMESTAMP) return null;
|
|
47345
|
+
return { periodFinish, rate };
|
|
47346
|
+
}
|
|
47347
|
+
var LLAMA_CHAIN_SLUG = {
|
|
47348
|
+
[Chain.ETHEREUM_MAINNET]: "ethereum",
|
|
47349
|
+
[Chain.OP_MAINNET]: "optimism",
|
|
47350
|
+
[Chain.ARBITRUM_ONE]: "arbitrum"
|
|
47351
|
+
};
|
|
47352
|
+
async function fetchPrices(keys) {
|
|
47353
|
+
const ids = Array.from(
|
|
47354
|
+
new Set(
|
|
47355
|
+
keys.map(({ chainId, address }) => {
|
|
47356
|
+
const slug = LLAMA_CHAIN_SLUG[chainId];
|
|
47357
|
+
return slug ? `${slug}:${address.toLowerCase()}` : null;
|
|
47358
|
+
}).filter((x) => !!x)
|
|
47359
|
+
)
|
|
47360
|
+
);
|
|
47361
|
+
if (ids.length === 0) return {};
|
|
47362
|
+
const out = {};
|
|
47363
|
+
const CHUNK = 60;
|
|
47364
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
47365
|
+
const slice2 = ids.slice(i, i + CHUNK);
|
|
47366
|
+
try {
|
|
47367
|
+
const res = await fetch(
|
|
47368
|
+
`https://coins.llama.fi/prices/current/${slice2.join(",")}`,
|
|
47369
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
47370
|
+
);
|
|
47371
|
+
if (!res.ok) continue;
|
|
47372
|
+
const json = await res.json();
|
|
47373
|
+
for (const [id, v] of Object.entries(json?.coins ?? {})) {
|
|
47374
|
+
if (typeof v?.price === "number") out[id.toLowerCase()] = v.price;
|
|
47375
|
+
}
|
|
47376
|
+
} catch (e) {
|
|
47377
|
+
console.error("[llamalend-gauge] price fetch failed:", e);
|
|
47378
|
+
}
|
|
47379
|
+
}
|
|
47380
|
+
return out;
|
|
47381
|
+
}
|
|
47382
|
+
var priceOf = (prices, chainId, address) => prices[`${LLAMA_CHAIN_SLUG[chainId]}:${address.toLowerCase()}`] ?? 0;
|
|
47383
|
+
function rosterFor(chainId) {
|
|
47384
|
+
const markets = llamaLendChainData(Lender.LLAMALEND, chainId)?.markets ?? [];
|
|
47385
|
+
return markets.filter((m) => m.gauge && m.gauge !== ZERO2).map((m) => ({
|
|
47386
|
+
controller: m.controller,
|
|
47387
|
+
vault: m.vault,
|
|
47388
|
+
gauge: m.gauge,
|
|
47389
|
+
borrowedToken: m.borrowedToken,
|
|
47390
|
+
name: m.name
|
|
47391
|
+
}));
|
|
47392
|
+
}
|
|
47393
|
+
var lenderKeyFor = (controller) => `${Lender.LLAMALEND}_${controller.replace(/^0x/i, "").toUpperCase()}`;
|
|
47394
|
+
async function fetchForChain(chainId, nowSeconds) {
|
|
47395
|
+
const markets = rosterFor(chainId);
|
|
47396
|
+
if (markets.length === 0) return {};
|
|
47397
|
+
const isL1 = L1_CHAINS.has(chainId);
|
|
47398
|
+
const week = BigInt(Math.floor(nowSeconds / 604800));
|
|
47399
|
+
const round1 = markets.flatMap((m) => [
|
|
47400
|
+
// L2 child gauges take the week; the L1 form takes none and reverts there.
|
|
47401
|
+
isL1 ? { address: m.gauge, name: "inflation_rate", params: [] } : { address: m.gauge, name: "inflation_rate", params: [week] },
|
|
47402
|
+
{ address: m.gauge, name: "working_supply", params: [] },
|
|
47403
|
+
{ address: m.gauge, name: "totalSupply", params: [] },
|
|
47404
|
+
{ address: m.gauge, name: "is_killed", params: [] },
|
|
47405
|
+
{ address: m.gauge, name: "reward_count", params: [] },
|
|
47406
|
+
{ address: m.vault, name: "convertToAssets", params: [WAD14] },
|
|
47407
|
+
isL1 ? {
|
|
47408
|
+
address: GAUGE_CONTROLLER,
|
|
47409
|
+
name: "gauge_relative_weight",
|
|
47410
|
+
params: [m.gauge]
|
|
47411
|
+
} : (
|
|
47412
|
+
// No gauge controller off L1; the child gauge's rate is already its own.
|
|
47413
|
+
{ address: m.gauge, name: "totalSupply", params: [] }
|
|
47414
|
+
)
|
|
47415
|
+
]);
|
|
47416
|
+
const r1 = await multicallRetryUniversal({
|
|
47417
|
+
chain: chainId,
|
|
47418
|
+
calls: round1,
|
|
47419
|
+
abi: GAUGE_ABI,
|
|
47420
|
+
allowFailure: true
|
|
47421
|
+
});
|
|
47422
|
+
const big16 = (v) => {
|
|
47423
|
+
try {
|
|
47424
|
+
if (typeof v === "bigint") return v;
|
|
47425
|
+
if (typeof v === "string" && v !== "0x") return BigInt(v);
|
|
47426
|
+
if (typeof v === "number") return BigInt(Math.trunc(v));
|
|
47427
|
+
} catch {
|
|
47428
|
+
}
|
|
47429
|
+
return 0n;
|
|
47430
|
+
};
|
|
47431
|
+
const STRIDE = 7;
|
|
47432
|
+
const state = markets.map((m, i) => {
|
|
47433
|
+
const b = i * STRIDE;
|
|
47434
|
+
return {
|
|
47435
|
+
market: m,
|
|
47436
|
+
inflationRate: big16(r1[b]),
|
|
47437
|
+
workingSupply: big16(r1[b + 1]),
|
|
47438
|
+
totalSupply: big16(r1[b + 2]),
|
|
47439
|
+
isKilled: r1[b + 3] === true,
|
|
47440
|
+
rewardCount: Number(big16(r1[b + 4])),
|
|
47441
|
+
pricePerShare: big16(r1[b + 5]),
|
|
47442
|
+
// Off L1 the child gauge's own rate is already market-scoped, so the
|
|
47443
|
+
// weight is the identity.
|
|
47444
|
+
relativeWeight: isL1 ? big16(r1[b + 6]) : WAD14
|
|
47445
|
+
};
|
|
47446
|
+
});
|
|
47447
|
+
const tokenCalls = state.flatMap(
|
|
47448
|
+
(s) => Array.from({ length: s.rewardCount }, (_3, i) => ({
|
|
47449
|
+
address: s.market.gauge,
|
|
47450
|
+
name: "reward_tokens",
|
|
47451
|
+
params: [BigInt(i)]
|
|
47452
|
+
}))
|
|
47453
|
+
);
|
|
47454
|
+
const r2 = tokenCalls.length ? await multicallRetryUniversal({
|
|
47455
|
+
chain: chainId,
|
|
47456
|
+
calls: tokenCalls,
|
|
47457
|
+
abi: GAUGE_ABI,
|
|
47458
|
+
allowFailure: true
|
|
47459
|
+
}) : [];
|
|
47460
|
+
let cursor = 0;
|
|
47461
|
+
const withTokens = state.map((s) => {
|
|
47462
|
+
const tokens = r2.slice(cursor, cursor + s.rewardCount).filter((t) => typeof t === "string" && t !== ZERO2);
|
|
47463
|
+
cursor += s.rewardCount;
|
|
47464
|
+
return { ...s, tokens };
|
|
47465
|
+
});
|
|
47466
|
+
const dataCalls = withTokens.flatMap(
|
|
47467
|
+
(s) => s.tokens.flatMap((t) => [
|
|
47468
|
+
{ address: s.market.gauge, name: "reward_data", params: [t] },
|
|
47469
|
+
{ address: t, name: "decimals", params: [] },
|
|
47470
|
+
{ address: t, name: "symbol", params: [] }
|
|
47471
|
+
])
|
|
47472
|
+
);
|
|
47473
|
+
const r3 = dataCalls.length ? await multicallRetryUniversal({
|
|
47474
|
+
chain: chainId,
|
|
47475
|
+
calls: dataCalls,
|
|
47476
|
+
abi: GAUGE_ABI,
|
|
47477
|
+
allowFailure: true
|
|
47478
|
+
}) : [];
|
|
47479
|
+
const priceKeys = [];
|
|
47480
|
+
for (const s of withTokens) {
|
|
47481
|
+
priceKeys.push({ chainId, address: s.market.borrowedToken });
|
|
47482
|
+
for (const t of s.tokens) priceKeys.push({ chainId, address: t });
|
|
47483
|
+
}
|
|
47484
|
+
const CRV_ETH = "0xD533a949740bb3306d119CC777fa900bA034cd52";
|
|
47485
|
+
if (isL1) priceKeys.push({ chainId, address: CRV_ETH });
|
|
47486
|
+
const prices = await fetchPrices(priceKeys);
|
|
47487
|
+
const crvPrice = isL1 ? priceOf(prices, chainId, CRV_ETH) : 0;
|
|
47488
|
+
const out = {};
|
|
47489
|
+
let dCursor = 0;
|
|
47490
|
+
for (const s of withTokens) {
|
|
47491
|
+
const assetPrice = priceOf(prices, chainId, s.market.borrowedToken);
|
|
47492
|
+
const streams = [];
|
|
47493
|
+
const crvApr = crvGaugeApr({
|
|
47494
|
+
inflationRate: s.inflationRate,
|
|
47495
|
+
relativeWeight: s.relativeWeight,
|
|
47496
|
+
workingSupply: s.workingSupply,
|
|
47497
|
+
pricePerShare: s.pricePerShare,
|
|
47498
|
+
crvPriceUsd: crvPrice,
|
|
47499
|
+
assetPriceUsd: assetPrice,
|
|
47500
|
+
isKilled: s.isKilled
|
|
47501
|
+
});
|
|
47502
|
+
if (crvApr > 0) {
|
|
47503
|
+
streams.push({
|
|
47504
|
+
side: "deposit",
|
|
47505
|
+
apr: crvApr,
|
|
47506
|
+
kind: "token",
|
|
47507
|
+
token: {
|
|
47508
|
+
address: CRV_ETH.toLowerCase(),
|
|
47509
|
+
symbol: "CRV",
|
|
47510
|
+
decimals: 18,
|
|
47511
|
+
priceUsd: crvPrice
|
|
47512
|
+
},
|
|
47513
|
+
source: {
|
|
47514
|
+
id: "curve:gauge-crv",
|
|
47515
|
+
label: "Curve gauge \xB7 CRV",
|
|
47516
|
+
platform: "protocol",
|
|
47517
|
+
link: `https://www.curve.finance/lend/ethereum/markets/${s.market.controller}/`,
|
|
47518
|
+
refs: {
|
|
47519
|
+
gauge: s.market.gauge,
|
|
47520
|
+
// The headline is the UNBOOSTED rate; a maxed veCRV lock earns
|
|
47521
|
+
// 2.5x it. Published so a consumer can show the range Curve does
|
|
47522
|
+
// rather than re-deriving the factor.
|
|
47523
|
+
maxBoostApr: crvApr * MAX_BOOST
|
|
47524
|
+
}
|
|
47525
|
+
},
|
|
47526
|
+
claim: "accrual"
|
|
47527
|
+
});
|
|
47528
|
+
}
|
|
47529
|
+
for (const token of s.tokens) {
|
|
47530
|
+
const data = r3[dCursor];
|
|
47531
|
+
const decRaw = r3[dCursor + 1];
|
|
47532
|
+
const symRaw = r3[dCursor + 2];
|
|
47533
|
+
dCursor += 3;
|
|
47534
|
+
const decoded = decodeRewardData(data);
|
|
47535
|
+
if (!decoded) continue;
|
|
47536
|
+
const { periodFinish, rate } = decoded;
|
|
47537
|
+
const decimals = typeof decRaw === "number" ? decRaw : Number(big16(decRaw) || 18n);
|
|
47538
|
+
const rewardPrice = priceOf(prices, chainId, token);
|
|
47539
|
+
const apr = extraRewardApr({
|
|
47540
|
+
rate,
|
|
47541
|
+
periodFinish,
|
|
47542
|
+
rewardDecimals: decimals,
|
|
47543
|
+
rewardPriceUsd: rewardPrice,
|
|
47544
|
+
totalSupply: s.totalSupply,
|
|
47545
|
+
pricePerShare: s.pricePerShare,
|
|
47546
|
+
assetPriceUsd: assetPrice,
|
|
47547
|
+
nowSeconds
|
|
47548
|
+
});
|
|
47549
|
+
if (apr <= 0) continue;
|
|
47550
|
+
streams.push({
|
|
47551
|
+
side: "deposit",
|
|
47552
|
+
apr,
|
|
47553
|
+
kind: "token",
|
|
47554
|
+
token: {
|
|
47555
|
+
address: token.toLowerCase(),
|
|
47556
|
+
symbol: typeof symRaw === "string" ? symRaw : void 0,
|
|
47557
|
+
decimals,
|
|
47558
|
+
priceUsd: rewardPrice
|
|
47559
|
+
},
|
|
47560
|
+
source: {
|
|
47561
|
+
id: "curve:gauge-extra",
|
|
47562
|
+
label: `Curve gauge \xB7 ${typeof symRaw === "string" ? symRaw : "reward"}`,
|
|
47563
|
+
platform: "protocol",
|
|
47564
|
+
link: `https://www.curve.finance/lend/ethereum/markets/${s.market.controller}/`,
|
|
47565
|
+
refs: { gauge: s.market.gauge, rewardToken: token }
|
|
47566
|
+
},
|
|
47567
|
+
claim: "accrual",
|
|
47568
|
+
// The whole point of carrying this: the rate survives expiry. Bounded
|
|
47569
|
+
// above by the decoder, so it can never overflow the consumer's column.
|
|
47570
|
+
endsAt: Number(periodFinish) || void 0
|
|
47571
|
+
});
|
|
47572
|
+
}
|
|
47573
|
+
if (streams.length === 0) continue;
|
|
47574
|
+
const deposit = streams.reduce((sum, st) => sum + st.apr, 0);
|
|
47575
|
+
const lenderKey = lenderKeyFor(s.market.controller);
|
|
47576
|
+
const asset = s.market.borrowedToken.toLowerCase();
|
|
47577
|
+
const reward = {
|
|
47578
|
+
distribution: "onchain-incentives",
|
|
47579
|
+
deposit,
|
|
47580
|
+
// Gauge rewards pay the LEND side only — the gauge stakes vault shares,
|
|
47581
|
+
// and a borrower holds none.
|
|
47582
|
+
borrow: 0,
|
|
47583
|
+
additionalDepositData: void 0,
|
|
47584
|
+
additionalBorrowData: void 0,
|
|
47585
|
+
streams
|
|
47586
|
+
};
|
|
47587
|
+
if (!out[chainId]) out[chainId] = {};
|
|
47588
|
+
if (!out[chainId][lenderKey]) out[chainId][lenderKey] = {};
|
|
47589
|
+
out[chainId][lenderKey][asset] = reward;
|
|
47590
|
+
}
|
|
47591
|
+
return out;
|
|
47592
|
+
}
|
|
47593
|
+
var GAUGE_CHAINS = [
|
|
47594
|
+
Chain.ETHEREUM_MAINNET,
|
|
47595
|
+
Chain.OP_MAINNET,
|
|
47596
|
+
Chain.ARBITRUM_ONE
|
|
47597
|
+
];
|
|
47598
|
+
var llamaLendGaugeRewardFetcher = {
|
|
47599
|
+
label: "LLAMALEND_GAUGE",
|
|
47600
|
+
// Lender-keyed: the gauge belongs to exactly one market, so there is no
|
|
47601
|
+
// deployment ambiguity to resolve against reserve tokens.
|
|
47602
|
+
fetch: async () => {
|
|
47603
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
47604
|
+
const results = await Promise.all(
|
|
47605
|
+
GAUGE_CHAINS.map(async (chainId) => {
|
|
47606
|
+
try {
|
|
47607
|
+
return await fetchForChain(chainId, nowSeconds);
|
|
47608
|
+
} catch (e) {
|
|
47609
|
+
console.error(`[llamalend-gauge] read failed on chain ${chainId}:`, e);
|
|
47610
|
+
return {};
|
|
47611
|
+
}
|
|
47612
|
+
})
|
|
47613
|
+
);
|
|
47614
|
+
const byLender = {};
|
|
47615
|
+
for (const r of results) {
|
|
47616
|
+
for (const [chainId, lenders] of Object.entries(r)) {
|
|
47617
|
+
if (!byLender[chainId]) byLender[chainId] = {};
|
|
47618
|
+
Object.assign(byLender[chainId], lenders);
|
|
47619
|
+
}
|
|
47620
|
+
}
|
|
47621
|
+
return { byLender };
|
|
47622
|
+
}
|
|
47623
|
+
};
|
|
47187
47624
|
|
|
47188
47625
|
// src/yields/rewards/fetchLenderRewards.ts
|
|
47189
47626
|
function mergeRewardResults(target, source) {
|
|
@@ -47199,7 +47636,8 @@ var rewardFetchers = [
|
|
|
47199
47636
|
aaveMerklRewardFetcher,
|
|
47200
47637
|
eulerMerklRewardFetcher,
|
|
47201
47638
|
morphoCollateralMerklRewardFetcher,
|
|
47202
|
-
dtrinityRebateRewardFetcher
|
|
47639
|
+
dtrinityRebateRewardFetcher,
|
|
47640
|
+
llamaLendGaugeRewardFetcher
|
|
47203
47641
|
];
|
|
47204
47642
|
function mergeReserveTokenRewards(target, source) {
|
|
47205
47643
|
for (const [chainId, byToken] of Object.entries(source)) {
|
|
@@ -53701,7 +54139,7 @@ query EvkByAssets($assets: [Bytes!]!) {
|
|
|
53701
54139
|
}
|
|
53702
54140
|
}
|
|
53703
54141
|
`;
|
|
53704
|
-
var
|
|
54142
|
+
var ZERO3 = 0n;
|
|
53705
54143
|
var RAY_TO_PERCENT3 = 1e25;
|
|
53706
54144
|
function readAddress2(field13) {
|
|
53707
54145
|
if (!field13) return void 0;
|
|
@@ -53716,28 +54154,28 @@ function parseVaultFee(v) {
|
|
|
53716
54154
|
return n;
|
|
53717
54155
|
}
|
|
53718
54156
|
function safeBigInt(v) {
|
|
53719
|
-
if (v == null || v === "") return
|
|
54157
|
+
if (v == null || v === "") return ZERO3;
|
|
53720
54158
|
try {
|
|
53721
54159
|
return BigInt(v);
|
|
53722
54160
|
} catch {
|
|
53723
|
-
return
|
|
54161
|
+
return ZERO3;
|
|
53724
54162
|
}
|
|
53725
54163
|
}
|
|
53726
54164
|
function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent, evkIndex) {
|
|
53727
54165
|
if (!strategies?.length) return 0;
|
|
53728
54166
|
const totalAssets = safeBigInt(totalAssetsRaw);
|
|
53729
|
-
if (totalAssets ===
|
|
53730
|
-
let weightedRay =
|
|
54167
|
+
if (totalAssets === ZERO3) return 0;
|
|
54168
|
+
let weightedRay = ZERO3;
|
|
53731
54169
|
for (const s of strategies) {
|
|
53732
54170
|
const evk = s.strategy?.toLowerCase();
|
|
53733
54171
|
if (!evk) continue;
|
|
53734
54172
|
const apyRay = evkIndex.bySupplyApyRay.get(evk);
|
|
53735
54173
|
if (apyRay == null) continue;
|
|
53736
54174
|
const allocated = safeBigInt(s.allocatedAssets);
|
|
53737
|
-
if (allocated ===
|
|
54175
|
+
if (allocated === ZERO3) continue;
|
|
53738
54176
|
weightedRay += allocated * apyRay;
|
|
53739
54177
|
}
|
|
53740
|
-
if (weightedRay ===
|
|
54178
|
+
if (weightedRay === ZERO3) return 0;
|
|
53741
54179
|
const apyRayPerAsset = weightedRay / totalAssets;
|
|
53742
54180
|
const grossPercent = apyToAprPercent(Number(apyRayPerAsset) / RAY_TO_PERCENT3);
|
|
53743
54181
|
const netPercent = grossPercent * (1 - feePercent / 100);
|
|
@@ -53745,24 +54183,24 @@ function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent, evkInd
|
|
|
53745
54183
|
}
|
|
53746
54184
|
function computeRealLiquidity(strategies, totalAssetsRaw, evkIndex) {
|
|
53747
54185
|
const totalAssets = safeBigInt(totalAssetsRaw);
|
|
53748
|
-
if (totalAssets ===
|
|
54186
|
+
if (totalAssets === ZERO3) return ZERO3;
|
|
53749
54187
|
if (evkIndex.byCash.size === 0 && evkIndex.bySupplyApyRay.size === 0) {
|
|
53750
54188
|
return totalAssets;
|
|
53751
54189
|
}
|
|
53752
54190
|
if (!strategies?.length) {
|
|
53753
54191
|
return totalAssets;
|
|
53754
54192
|
}
|
|
53755
|
-
let allocSum =
|
|
53756
|
-
let withdrawable =
|
|
54193
|
+
let allocSum = ZERO3;
|
|
54194
|
+
let withdrawable = ZERO3;
|
|
53757
54195
|
for (const s of strategies) {
|
|
53758
54196
|
const alloc = safeBigInt(s.allocatedAssets);
|
|
53759
|
-
if (alloc ===
|
|
54197
|
+
if (alloc === ZERO3) continue;
|
|
53760
54198
|
allocSum += alloc;
|
|
53761
54199
|
const evk = s.strategy?.toLowerCase();
|
|
53762
54200
|
const cash = evk ? evkIndex.byCash.get(evk) : void 0;
|
|
53763
54201
|
withdrawable += cash == null ? alloc : alloc < cash ? alloc : cash;
|
|
53764
54202
|
}
|
|
53765
|
-
const idle = totalAssets > allocSum ? totalAssets - allocSum :
|
|
54203
|
+
const idle = totalAssets > allocSum ? totalAssets - allocSum : ZERO3;
|
|
53766
54204
|
const result = idle + withdrawable;
|
|
53767
54205
|
return result > totalAssets ? totalAssets : result;
|
|
53768
54206
|
}
|
|
@@ -54102,19 +54540,19 @@ async function fetchTermMaxVaultsFromApi(chainId, prices = {}, tokenList = {}, f
|
|
|
54102
54540
|
if (!address || !underlying) continue;
|
|
54103
54541
|
if (r.isEnabled === false) continue;
|
|
54104
54542
|
const assetDecimals = num4(r?.asset?.decimals) || 18;
|
|
54105
|
-
const
|
|
54543
|
+
const scale3 = 10 ** assetDecimals;
|
|
54106
54544
|
const assetEntry = tokenList[underlying];
|
|
54107
54545
|
const priceKey = toOracleKey(assetEntry?.assetGroup) || toGenericPriceKey(underlying, chainId);
|
|
54108
54546
|
const priceUsd = prices[priceKey];
|
|
54109
54547
|
const totalAssets = big14(r.totalAssets);
|
|
54110
54548
|
const totalSupply = big14(r.totalSupplyAmt);
|
|
54111
|
-
const totalAssetsFormatted = Number(totalAssets) /
|
|
54549
|
+
const totalAssetsFormatted = Number(totalAssets) / scale3;
|
|
54112
54550
|
const supplyRate = num4(r.apr) * 100;
|
|
54113
54551
|
const rewardsRate = num4(r?.incentiveData?.TMX_APR) * 100;
|
|
54114
54552
|
const rawLiquidity = BigInt(big14(r.redeemableAmt ?? r.idleFunds ?? "0"));
|
|
54115
54553
|
const totalAssetsBig = BigInt(totalAssets);
|
|
54116
54554
|
const liquidity = (rawLiquidity > totalAssetsBig ? totalAssetsBig : rawLiquidity).toString();
|
|
54117
|
-
const liquidityFormatted = Number(liquidity) /
|
|
54555
|
+
const liquidityFormatted = Number(liquidity) / scale3;
|
|
54118
54556
|
const totalSupplyValue = num4(r.totalSupplyValue);
|
|
54119
54557
|
out[address] = {
|
|
54120
54558
|
address,
|
|
@@ -54315,9 +54753,9 @@ var fetchTermMaxVaultsFromChain = async (chainId, multicallRetry, prices = {}, t
|
|
|
54315
54753
|
if (r.aprRaw !== void 0 && r.aprRaw > 0n) {
|
|
54316
54754
|
supplyRate = Number(r.aprRaw) / Number(DECIMAL_BASE2) * 100;
|
|
54317
54755
|
}
|
|
54318
|
-
const
|
|
54319
|
-
const totalAssetsFormatted = Number(r.totalAssets) /
|
|
54320
|
-
const liquidityFormatted = Number(idle) /
|
|
54756
|
+
const scale3 = 10 ** assetDecimals;
|
|
54757
|
+
const totalAssetsFormatted = Number(r.totalAssets) / scale3;
|
|
54758
|
+
const liquidityFormatted = Number(idle) / scale3;
|
|
54321
54759
|
const convertToAssets = r.totalSupply > 0n ? (r.totalAssets * 10n ** BigInt(r.decimals) / r.totalSupply).toString() : "0";
|
|
54322
54760
|
const entry = {
|
|
54323
54761
|
address: r.address,
|
|
@@ -55439,7 +55877,7 @@ var readerVedaAccountant = (entry) => {
|
|
|
55439
55877
|
}
|
|
55440
55878
|
};
|
|
55441
55879
|
}
|
|
55442
|
-
const
|
|
55880
|
+
const scale3 = 10n ** BigInt(18 - underlyingDec);
|
|
55443
55881
|
return {
|
|
55444
55882
|
calls: [
|
|
55445
55883
|
{ address: entry.address, name: "totalSupply", params: [] },
|
|
@@ -55450,7 +55888,7 @@ var readerVedaAccountant = (entry) => {
|
|
|
55450
55888
|
const totalSupply = toBigInt13(supply);
|
|
55451
55889
|
const rawRate = toBigInt13(rate);
|
|
55452
55890
|
if (totalSupply === void 0 || rawRate === void 0) return void 0;
|
|
55453
|
-
const exchangeRate = rawRate *
|
|
55891
|
+
const exchangeRate = rawRate * scale3;
|
|
55454
55892
|
return {
|
|
55455
55893
|
totalAssets: rescaleDecimals(
|
|
55456
55894
|
totalSupply * exchangeRate / ONE_E189,
|
|
@@ -60686,8 +61124,8 @@ var deriveTotalSupply = (totalAssetsRaw, pricePerShareRaw, decimals) => {
|
|
|
60686
61124
|
if (assets === 0n) return "0";
|
|
60687
61125
|
const pps = BigInt(pricePerShareRaw || "0");
|
|
60688
61126
|
if (pps <= 0n) return totalAssetsRaw;
|
|
60689
|
-
const
|
|
60690
|
-
return (assets *
|
|
61127
|
+
const scale3 = 10n ** BigInt(decimals);
|
|
61128
|
+
return (assets * scale3 / pps).toString();
|
|
60691
61129
|
} catch {
|
|
60692
61130
|
return totalAssetsRaw || "0";
|
|
60693
61131
|
}
|