@reserve-protocol/dtf-sdk 0.1.4 → 0.1.5

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.
Files changed (35) hide show
  1. package/dist/abi/main.d.ts +30 -0
  2. package/dist/abi/main.d.ts.map +1 -1
  3. package/dist/abi/rtoken.d.ts +22 -0
  4. package/dist/abi/rtoken.d.ts.map +1 -0
  5. package/dist/analytics/compute-performance.d.ts +25 -0
  6. package/dist/analytics/compute-performance.d.ts.map +1 -1
  7. package/dist/dtf/fetch-dtf.d.ts +1 -16
  8. package/dist/dtf/fetch-dtf.d.ts.map +1 -1
  9. package/dist/index.d.ts +12 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1042 -8
  12. package/dist/prices/zapper-quote.d.ts +14 -0
  13. package/dist/prices/zapper-quote.d.ts.map +1 -0
  14. package/dist/signals/compute-signals.d.ts +30 -0
  15. package/dist/signals/compute-signals.d.ts.map +1 -0
  16. package/dist/signals/index.d.ts +4 -0
  17. package/dist/signals/index.d.ts.map +1 -0
  18. package/dist/signals/thresholds.d.ts +17 -0
  19. package/dist/signals/thresholds.d.ts.map +1 -0
  20. package/dist/signals/types.d.ts +8 -0
  21. package/dist/signals/types.d.ts.map +1 -0
  22. package/dist/types.d.ts +72 -2
  23. package/dist/types.d.ts.map +1 -1
  24. package/dist/yield-dtf/collateral-yields.d.ts +12 -0
  25. package/dist/yield-dtf/collateral-yields.d.ts.map +1 -0
  26. package/dist/yield-dtf/fetch-apy.d.ts +12 -0
  27. package/dist/yield-dtf/fetch-apy.d.ts.map +1 -0
  28. package/dist/yield-dtf/fetch-discover.d.ts +17 -0
  29. package/dist/yield-dtf/fetch-discover.d.ts.map +1 -0
  30. package/dist/yield-dtf/fetch-revenue.d.ts +11 -0
  31. package/dist/yield-dtf/fetch-revenue.d.ts.map +1 -0
  32. package/dist/yield-dtf/read-config.d.ts.map +1 -1
  33. package/dist/yield-dtf/read-status.d.ts +13 -0
  34. package/dist/yield-dtf/read-status.d.ts.map +1 -0
  35. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -171,6 +171,199 @@ import {
171
171
  __toESM
172
172
  } from "./index-sdksp5px.js";
173
173
 
174
+ // ../../node_modules/.bun/@reserve-protocol+rtokens@1.1.23/node_modules/@reserve-protocol/rtokens/rtokens/mainnet-rtoken-map.json
175
+ var require_mainnet_rtoken_map = __commonJS((exports, module) => {
176
+ module.exports = {
177
+ "0x005F893EcD7bF9667195642f7649DA8163e23658": {
178
+ address: "0x005F893EcD7bF9667195642f7649DA8163e23658",
179
+ name: "Degen ETH",
180
+ symbol: "dgnETH",
181
+ logo: "dgneth.svg",
182
+ decimals: 18,
183
+ about: "Degen ETH is a high-yield diversified ETH strategy index designed to sustainably outperform LST market yields. Degen ETH uses a two-token model: dgnETH, which is pegged to ETH and backed 1:1 by DeFi yield strategies, and sdgnETH, obtained by depositing dgnETH in a staking vault, which accrues all yield from dgnETH's underlying assets.",
184
+ website: "https://degeneth.com",
185
+ support: {
186
+ email: "",
187
+ url: ""
188
+ },
189
+ social: {
190
+ twitter: "https://x.com/dgnETH_"
191
+ }
192
+ },
193
+ "0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F": {
194
+ address: "0xA0d69E286B938e21CBf7E51D71F6A4c8918f482F",
195
+ name: "Electronic Dollar",
196
+ symbol: "eUSD",
197
+ logo: "eusd.svg",
198
+ decimals: 18,
199
+ about: "The eUSD RToken is a fully collateralized US-dollar stablecoin built on the Reserve Protocol"
200
+ },
201
+ "0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8": {
202
+ address: "0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8",
203
+ name: "ETHPlus",
204
+ symbol: "ETH+",
205
+ logo: "ethplus.svg",
206
+ decimals: 18,
207
+ about: "A reward generating Ethereum Liquid Staking Token basket with over-collateralized protection",
208
+ website: "https://register.app/#/overview?token=0xE72B141DF173b999AE7c1aDcbF60Cc9833Ce56a8",
209
+ support: {
210
+ url: "https://twitter.com/ETHPlus_"
211
+ },
212
+ social: {
213
+ twitter: "https://twitter.com/ETHPlus_"
214
+ }
215
+ },
216
+ "0xaCdf0DBA4B9839b96221a8487e9ca660a48212be": {
217
+ address: "0xaCdf0DBA4B9839b96221a8487e9ca660a48212be",
218
+ name: "High Yield USD",
219
+ symbol: "hyUSD",
220
+ logo: "hyusd.svg",
221
+ decimals: 18,
222
+ about: "hyUSD is a secure high yield savings flatcoin with up to 6% rewards outpacing inflation in over 100 countries around the world 🌎",
223
+ website: "https://linktr.ee/hyusd",
224
+ support: {
225
+ email: "contact@high-yield.io",
226
+ url: ""
227
+ },
228
+ social: {
229
+ twitter: "https://twitter.com/HighYieldUSD"
230
+ }
231
+ },
232
+ "0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b": {
233
+ address: "0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b",
234
+ name: "USDC Plus",
235
+ symbol: "USDC+",
236
+ logo: "usdcplus.svg",
237
+ decimals: 18,
238
+ about: "USDC PLUS (USDC+): A community governed yield bearing USDC index optimized for yield to holders and overcollateralization protection.",
239
+ website: "https://register.app/#/overview?token=0xFc0B1EEf20e4c68B3DCF36c4537Cfa7Ce46CA70b"
240
+ },
241
+ "0x0d86883FAf4FfD7aEb116390af37746F45b6f378": {
242
+ address: "0x0d86883FAf4FfD7aEb116390af37746F45b6f378",
243
+ name: "Web 3 Dollar",
244
+ symbol: "USD3",
245
+ logo: "usd3.svg",
246
+ decimals: 18,
247
+ about: "Earn the DeFi rate any time you're in stables",
248
+ support: {
249
+ email: "",
250
+ url: ""
251
+ },
252
+ social: {
253
+ twitter: "https://twitter.com/USD_3"
254
+ }
255
+ },
256
+ "0x78da5799CF427Fee11e9996982F4150eCe7a99A7": {
257
+ address: "0x78da5799CF427Fee11e9996982F4150eCe7a99A7",
258
+ name: "Revenue Generating USD",
259
+ symbol: "rgUSD",
260
+ logo: "rgusd.svg",
261
+ decimals: 18,
262
+ about: "Hold $1 USD peg, and deploy collateral to generate safe, on-chain yield to incentivize liquidity for itself and partners."
263
+ }
264
+ };
265
+ });
266
+
267
+ // ../../node_modules/.bun/@reserve-protocol+rtokens@1.1.23/node_modules/@reserve-protocol/rtokens/rtokens/base-rtoken-map.json
268
+ var require_base_rtoken_map = __commonJS((exports, module) => {
269
+ module.exports = {
270
+ "0xCc7FF230365bD730eE4B352cC2492CEdAC49383e": {
271
+ address: "0xCc7FF230365bD730eE4B352cC2492CEdAC49383e",
272
+ name: "High Yield USD",
273
+ symbol: "hyUSD",
274
+ logo: "hyusd.svg",
275
+ decimals: 18,
276
+ about: "hyUSD is a secure high yield savings flatcoin with up to 6% rewards outpacing inflation in over 100 countries around the world 🌎",
277
+ website: "https://linktr.ee/hyusd",
278
+ support: {
279
+ email: "contact@high-yield.io",
280
+ url: ""
281
+ },
282
+ social: {
283
+ twitter: "https://twitter.com/HighYieldUSD"
284
+ }
285
+ },
286
+ "0x8f0987DDb485219c767770e2080E5cC01ddc772a": {
287
+ address: "0x8f0987DDb485219c767770e2080E5cC01ddc772a",
288
+ name: "Base Yield Index",
289
+ symbol: "BSDX",
290
+ logo: "bsdx.svg",
291
+ decimals: 18
292
+ },
293
+ "0xCb327b99fF831bF8223cCEd12B1338FF3aA322Ff": {
294
+ address: "0xCb327b99fF831bF8223cCEd12B1338FF3aA322Ff",
295
+ name: "Based ETH",
296
+ symbol: "bsdETH",
297
+ logo: "bsdeth.svg",
298
+ decimals: 18,
299
+ about: "A yield generating Ethereum Liquid Staking Token basket with over-collateralization protection."
300
+ },
301
+ "0xC9a3e2B3064c1c0546D3D0edc0A748E9f93Cf18d": {
302
+ address: "0xC9a3e2B3064c1c0546D3D0edc0A748E9f93Cf18d",
303
+ name: "Vaya",
304
+ symbol: "Vaya",
305
+ logo: "vaya.svg",
306
+ decimals: 18,
307
+ about: "A decentralized stablecoin which is striking to get the ideal balance between maximizing the worth of your finances and safeguarding its security.",
308
+ website: "https://vaya-stablecoin.com",
309
+ support: {
310
+ url: "https://twitter.com/Vaya_stablecoin"
311
+ },
312
+ social: {
313
+ twitter: "https://twitter.com/Vaya_stablecoin"
314
+ }
315
+ },
316
+ "0x641B0453487C9D14c5df96d45a481ef1dc84e31f": {
317
+ address: "0x641B0453487C9D14c5df96d45a481ef1dc84e31f",
318
+ name: "Maat",
319
+ symbol: "MAAT",
320
+ logo: "maat.svg",
321
+ decimals: 18,
322
+ about: "Monetary Average Across Time. The Dollar, Bitcoin, Ether unified.",
323
+ support: {
324
+ email: "maatcurrency@gmail.com"
325
+ },
326
+ social: {
327
+ twitter: "https://twitter.com/FlatcoinMaat"
328
+ }
329
+ }
330
+ };
331
+ });
332
+
333
+ // ../../node_modules/.bun/@reserve-protocol+rtokens@1.1.23/node_modules/@reserve-protocol/rtokens/rtokens/arbitrum-rtoken-map.json
334
+ var require_arbitrum_rtoken_map = __commonJS((exports, module) => {
335
+ module.exports = {
336
+ "0x0BBF664D46becc28593368c97236FAa0fb397595": {
337
+ address: "0x0BBF664D46becc28593368c97236FAa0fb397595",
338
+ name: "KNOX Dollar",
339
+ symbol: "KNOX",
340
+ logo: "knox.svg",
341
+ decimals: 18,
342
+ about: "Where value anchors",
343
+ support: {
344
+ email: "knoxusd@gmail.com"
345
+ },
346
+ social: {
347
+ twitter: "https://twitter.com/KNOX_Dollar"
348
+ }
349
+ }
350
+ };
351
+ });
352
+
353
+ // ../../node_modules/.bun/@reserve-protocol+rtokens@1.1.23/node_modules/@reserve-protocol/rtokens/index.js
354
+ var require_rtokens = __commonJS((exports, module) => {
355
+ var chainId = {
356
+ mainnet: 1,
357
+ base: 8453,
358
+ arbitrum: 42161
359
+ };
360
+ module.exports = {
361
+ [chainId.mainnet]: require_mainnet_rtoken_map(),
362
+ [chainId.base]: require_base_rtoken_map(),
363
+ [chainId.arbitrum]: require_arbitrum_rtoken_map()
364
+ };
365
+ });
366
+
174
367
  // ../../node_modules/.bun/@reserve-protocol+dtf-rebalance-lib@3.2.1+cdf17018f2c68680/node_modules/@reserve-protocol/dtf-rebalance-lib/dist/types.js
175
368
  var require_types = __commonJS((exports) => {
176
369
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -12756,17 +12949,36 @@ async function fetchDtfPrice(chainId, folioAddress, baseUrl = RESERVE_API_BASE_U
12756
12949
  return data.price;
12757
12950
  }
12758
12951
  async function fetchZapQuote(chainId, params, baseUrl = RESERVE_API_BASE_URL) {
12759
- const url = `${baseUrl}/zapper/${chainId}/swap?tokenIn=${params.tokenIn.toLowerCase()}&tokenOut=${params.tokenOut.toLowerCase()}&amountIn=${params.amountIn.toString()}&slippage=${params.slippage}&sender=${params.sender.toLowerCase()}&recipient=${params.recipient.toLowerCase()}`;
12952
+ const queryParams = new URLSearchParams({
12953
+ chainId: String(chainId),
12954
+ signer: params.signer.toLowerCase(),
12955
+ tokenIn: params.tokenIn.toLowerCase(),
12956
+ tokenOut: params.tokenOut.toLowerCase(),
12957
+ amountIn: params.amountIn.toString(),
12958
+ slippage: String(params.slippage),
12959
+ trade: String(params.trade ?? true)
12960
+ });
12961
+ if (params.bypassCache)
12962
+ queryParams.set("bypassCache", "true");
12963
+ const url = `${baseUrl}/api/zapper/${chainId}/swap?${queryParams.toString()}`;
12760
12964
  const response = await fetchWithRetry(url);
12761
12965
  if (!response.ok) {
12762
- throw new Error(`Reserve API /zapper/swap failed: ${response.status} ${response.statusText}`);
12966
+ throw new Error(`Reserve API /api/zapper/swap failed: ${response.status} ${response.statusText}`);
12763
12967
  }
12764
- const data = await response.json();
12968
+ const json = await response.json();
12969
+ const r = json.result ?? json;
12765
12970
  return {
12766
- amountOut: BigInt(data.amountOut),
12767
- to: data.to,
12768
- data: data.data,
12769
- value: BigInt(data.value)
12971
+ amountOut: BigInt(r.amountOut ?? "0"),
12972
+ amountOutValue: r.amountOutValue ?? null,
12973
+ amountInValue: r.amountInValue ?? null,
12974
+ priceImpact: r.priceImpact ?? 0,
12975
+ truePriceImpact: r.truePriceImpact ?? 0,
12976
+ gas: r.gas ?? null,
12977
+ dust: r.dust ?? [],
12978
+ dustValue: r.dustValue ?? null,
12979
+ to: r.to ?? "0x0000000000000000000000000000000000000000",
12980
+ data: r.data ?? "0x",
12981
+ value: BigInt(r.value ?? "0")
12770
12982
  };
12771
12983
  }
12772
12984
  async function fetchVoteLockPositions(baseUrl = RESERVE_API_BASE_URL) {
@@ -12921,6 +13133,27 @@ var mainAbi = [
12921
13133
  outputs: [{ internalType: "contract IRevenueTrader", name: "", type: "address" }],
12922
13134
  stateMutability: "view",
12923
13135
  type: "function"
13136
+ },
13137
+ {
13138
+ inputs: [],
13139
+ name: "frozen",
13140
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
13141
+ stateMutability: "view",
13142
+ type: "function"
13143
+ },
13144
+ {
13145
+ inputs: [],
13146
+ name: "issuancePausedOrFrozen",
13147
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
13148
+ stateMutability: "view",
13149
+ type: "function"
13150
+ },
13151
+ {
13152
+ inputs: [],
13153
+ name: "tradingPausedOrFrozen",
13154
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
13155
+ stateMutability: "view",
13156
+ type: "function"
12924
13157
  }
12925
13158
  ];
12926
13159
 
@@ -13190,7 +13423,7 @@ async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
13190
13423
  throw new Error(`No FacadeRead address for chainId ${chainId}`);
13191
13424
  }
13192
13425
  const components = await readYieldDtfComponents(publicClient, rTokenAddress);
13193
- const [basket, backing, price, nameResult, symbolResult, stRSRInfo, distribution] = await Promise.all([
13426
+ const [basket, backing, price, nameResult, symbolResult, totalSupplyResult, stRSRInfo, distribution] = await Promise.all([
13194
13427
  readYieldDtfBasket(publicClient, facadeAddress, rTokenAddress),
13195
13428
  readBackingOverview(publicClient, facadeAddress, rTokenAddress),
13196
13429
  readYieldDtfPrice(publicClient, facadeAddress, rTokenAddress),
@@ -13204,9 +13437,17 @@ async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
13204
13437
  abi: ERC20_META_ABI,
13205
13438
  functionName: "symbol"
13206
13439
  }),
13440
+ publicClient.readContract({
13441
+ address: rTokenAddress,
13442
+ abi: ERC20_META_ABI,
13443
+ functionName: "totalSupply"
13444
+ }),
13207
13445
  readStRSRInfo(publicClient, components.stRSR),
13208
13446
  readDistribution(publicClient, components.distributor)
13209
13447
  ]);
13448
+ const totalSupply = totalSupplyResult;
13449
+ const avgPrice = (Number(price.low) + Number(price.high)) / 2;
13450
+ const tvl = avgPrice * Number(totalSupply) / (1000000000000000000 * 1000000000000000000);
13210
13451
  return {
13211
13452
  type: "yield",
13212
13453
  components,
@@ -13216,12 +13457,444 @@ async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
13216
13457
  backing,
13217
13458
  priceLow: price.low,
13218
13459
  priceHigh: price.high,
13460
+ totalSupply,
13461
+ tvl,
13219
13462
  exchangeRate: stRSRInfo.exchangeRate,
13220
13463
  unstakingDelay: stRSRInfo.unstakingDelay,
13221
13464
  rTokenTotal: distribution.rTokenTotal,
13222
13465
  rsrTotal: distribution.rsrTotal
13223
13466
  };
13224
13467
  }
13468
+ // src/yield-dtf/fetch-discover.ts
13469
+ var import_rtokens = __toESM(require_rtokens(), 1);
13470
+ var rtokens = import_rtokens.default;
13471
+ var D182 = 1000000000000000000;
13472
+ var PERCENT_SCALE = 100;
13473
+ var TOKENS_QUERY = `
13474
+ query GetYieldDtfs($tokenIds: [String]!) {
13475
+ tokens(where: { id_in: $tokenIds }) {
13476
+ id
13477
+ lastPriceUSD
13478
+ name
13479
+ symbol
13480
+ totalSupply
13481
+ cumulativeVolume
13482
+ rToken {
13483
+ backing
13484
+ rsrStaked
13485
+ rsrExchangeRate
13486
+ holdersRewardShare
13487
+ stakersRewardShare
13488
+ targetUnits
13489
+ collaterals {
13490
+ id
13491
+ symbol
13492
+ }
13493
+ collateralDistribution
13494
+ revenueDistribution {
13495
+ rTokenDist
13496
+ rsrDist
13497
+ destination
13498
+ }
13499
+ }
13500
+ }
13501
+ }
13502
+ `;
13503
+ function parseCollateralDistribution(raw) {
13504
+ if (!raw)
13505
+ return {};
13506
+ try {
13507
+ const parsed = JSON.parse(raw);
13508
+ const result = {};
13509
+ for (const key of Object.keys(parsed)) {
13510
+ result[key.toLowerCase()] = parsed[key];
13511
+ }
13512
+ return result;
13513
+ } catch {
13514
+ return {};
13515
+ }
13516
+ }
13517
+ function computeBasketApy(collaterals, distribution, collateralYields) {
13518
+ if (collaterals.length === 0)
13519
+ return null;
13520
+ let basketApy = 0;
13521
+ for (const collateral of collaterals) {
13522
+ const yieldPct = collateralYields[collateral.symbol.toLowerCase()] || 0;
13523
+ const weight = Number(distribution[collateral.id.toLowerCase()]?.dist) || 0;
13524
+ basketApy += yieldPct * weight;
13525
+ }
13526
+ return basketApy;
13527
+ }
13528
+ async function fetchYieldDtfDiscover(chainId, options) {
13529
+ const url = YIELD_SUBGRAPH_URLS[chainId];
13530
+ if (!url)
13531
+ return [];
13532
+ const chainRtokens = rtokens[chainId.toString()];
13533
+ if (!chainRtokens || Object.keys(chainRtokens).length === 0)
13534
+ return [];
13535
+ const tokenIds = Object.keys(chainRtokens).map((a) => a.toLowerCase());
13536
+ const data = await querySubgraph(chainId, TOKENS_QUERY, { tokenIds }, url);
13537
+ const collateralYields = options?.collateralYields;
13538
+ const rsrPriceUsd = options?.rsrPriceUsd;
13539
+ return data.tokens.map((t) => {
13540
+ const price = Number(t.lastPriceUSD);
13541
+ const totalSupplyRaw = Number(t.totalSupply) / D182;
13542
+ const marketCap = price > 0 && totalSupplyRaw > 0 ? price * totalSupplyRaw : 0;
13543
+ const collaterals = t.rToken?.collaterals ?? [];
13544
+ const distribution = parseCollateralDistribution(t.rToken?.collateralDistribution ?? null);
13545
+ let holdingApy = null;
13546
+ let stakingApy = null;
13547
+ if (collateralYields) {
13548
+ const basketApy = computeBasketApy(collaterals, distribution, collateralYields);
13549
+ if (basketApy !== null) {
13550
+ const holdersShare = t.rToken ? Number(t.rToken.holdersRewardShare) / PERCENT_SCALE : 0;
13551
+ holdingApy = basketApy * holdersShare;
13552
+ if (rsrPriceUsd != null && rsrPriceUsd > 0) {
13553
+ const stakersShare = t.rToken ? Number(t.rToken.stakersRewardShare) / PERCENT_SCALE : 0;
13554
+ const supplyUsd = price > 0 ? price * totalSupplyRaw : 0;
13555
+ const stakeUsd = Number(t.rToken?.rsrStaked ?? "0") / D182 * rsrPriceUsd;
13556
+ stakingApy = stakeUsd > 0 ? basketApy * supplyUsd / stakeUsd * stakersShare : basketApy * stakersShare;
13557
+ }
13558
+ }
13559
+ }
13560
+ return {
13561
+ address: t.id,
13562
+ chainId,
13563
+ name: t.name,
13564
+ symbol: t.symbol,
13565
+ decimals: 18,
13566
+ price: price > 0 ? price : null,
13567
+ marketCap: marketCap > 0 ? marketCap : null,
13568
+ totalSupply: t.totalSupply,
13569
+ basketRate: null,
13570
+ backing: t.rToken ? Number(t.rToken.backing) / D182 : 1,
13571
+ rsrStaked: t.rToken?.rsrStaked ?? "0",
13572
+ rsrExchangeRate: t.rToken ? Number(t.rToken.rsrExchangeRate) / D182 : 1,
13573
+ holdersRewardShare: t.rToken ? Number(t.rToken.holdersRewardShare) / PERCENT_SCALE : 0,
13574
+ stakersRewardShare: t.rToken ? Number(t.rToken.stakersRewardShare) / PERCENT_SCALE : 0,
13575
+ targetUnits: t.rToken?.targetUnits ?? null,
13576
+ collaterals: collaterals.map((c) => ({
13577
+ address: c.id,
13578
+ symbol: c.symbol
13579
+ })),
13580
+ holdingApy,
13581
+ stakingApy
13582
+ };
13583
+ });
13584
+ }
13585
+ // src/yield-dtf/collateral-yields.ts
13586
+ var POOL_MAP = {
13587
+ 1: {
13588
+ "acee1e4d-a73c-4e20-98f7-e87c13d446e4": "apxeth",
13589
+ "405d8dad-5c99-4c91-90d3-82813ade1ff1": "sadai",
13590
+ "a349fea4-d780-4e16-973e-70ca9b606db2": "sausdc",
13591
+ "60d657c9-5f63-4771-a85b-2cf8d507ec00": "sausdt",
13592
+ "1d53fa29-b918-4d74-9508-8fcf8173ca51": "sausdp",
13593
+ "cc110152-36c2-4e10-9c12-c5b4eb662143": "cdai",
13594
+ "cefa9bb8-c230-459a-a855-3b94e96acd8c": "cusdc",
13595
+ "57647093-2868-4e65-97ab-9cae8ec74e7d": "cusdt",
13596
+ "6c2b7a5c-6c4f-49ea-a08c-0366b772f2c2": "cusdp",
13597
+ "1d876729-4445-4623-8b6b-c5290db5d100": "cwbtc",
13598
+ "1e5da7c6-59bb-49bd-9f97-4f4fceeffad4": "ceth",
13599
+ "fa4d7ee4-0001-4133-9e8d-cf7d5d194a91": "fusdc",
13600
+ "ed227286-abb0-4a34-ada5-39f7ebd81afb": "fdai",
13601
+ "6600934f-6323-447d-8a7d-67fbede8529d": "fusdt",
13602
+ "747c1d2a-c668-4682-b9f9-296708a3dd90": "wsteth",
13603
+ "d4b3c522-6127-4b89-bedf-83641cdcd2eb": "reth",
13604
+ "7da72d09-56ca-4ec5-a45f-59114353e487": "wcusdcv3",
13605
+ "f4d5b566-e815-4ca2-bb07-7bcd8bc797f1": "wcusdtv3",
13606
+ "8a20c472-142c-4442-b724-40f2183c073e": "stkcvxmim-3lp3crv-f",
13607
+ "ad3d7253-fb8f-402f-a6f8-821bc0a055cb": "stkcvxcrv3crypto",
13608
+ "7394f1bc-840a-4ff0-9e87-5e0ef932943a": "stkcvx3crv",
13609
+ "c04005c9-7e34-41a6-91c4-295834ed8ac0": "stkcvxeusd3crv-f",
13610
+ "325ad2d6-70b1-48d7-a557-c2c99a036f87": "mrp-ausdc",
13611
+ "1343a280-7812-4bc3-8f98-d1c37e11d271": "mrp-ausdt",
13612
+ "b8bcdf8e-96ed-40ca-a7aa-aa048b9874e5": "mrp-adai",
13613
+ "7be52986-18c2-450f-b74b-d65fb1205bbf": "mrp-aweth",
13614
+ "ff61171d-d7b0-4989-816c-b9bf02a15f00": "mrp-awbtc",
13615
+ "eab8d63d-8a8f-48cb-8027-583508831d24": "mrp-asteth",
13616
+ "0f45d730-b279-4629-8e11-ccb5cc3038b4": "cbeth",
13617
+ "c8a24fee-ec00-4f38-86c0-9f6daebc4225": "sdai",
13618
+ "55de30c3-bf9f-4d4e-9e0b-536a8ef5ab35": "sfrax",
13619
+ "aa70268e-4b52-42bf-a116-608b370f9501": "saethusdc",
13620
+ "d118f505-e75f-4152-bad3-49a2dc7482bf": "saethpyusd",
13621
+ "01146cce-9140-4e03-9a2e-82c99ccc42f1": "stkcvxpyusdusdc",
13622
+ "5b3aebb3-891d-47fc-92e2-927ada3d5b82": "sfrxeth",
13623
+ "d741644d-86ea-44ad-af5e-3042de381173": "re7weth",
13624
+ "a3ffd3fe-b21c-44eb-94d5-22c80057a600": "stkcvxcrvusdusdt-f",
13625
+ "755fcec6-f4fd-4150-9184-60f099206694": "stkcvxcrvusdusdc-f",
13626
+ "d1dacce1-7815-420c-bb6d-d3c4320e1b2a": "steakpyusd",
13627
+ "043a8330-bc29-4164-aa1c-28de7bf87755": "bbusdt",
13628
+ "152b7ce2-7193-475d-9b15-3f17fee66047": "stkcvxeth+eth",
13629
+ "74346f6f-c7ee-4506-a204-baf48e13decb": "stkcvxeth+eth-f",
13630
+ "66985a81-9c51-46ca-9977-42b4fe7bc6df": "susde",
13631
+ "90bfb3c2-5d35-4959-a275-ba5085b08aa3": "ethx",
13632
+ "d8c4eff5-c8a9-46fc-a888-057c4c668e72": "susds",
13633
+ "423681e3-4787-40ce-ae43-e9f67c5269b3": "woeth",
13634
+ "f981a304-bb6c-45b8-b0c5-fd2f515ad23a": "saethusdt",
13635
+ "85fc6934-c94d-4ebe-9c60-66beb363669f": "saethrlusd",
13636
+ "46bd2bdf-6d92-4066-b482-e885ee172264": "weeth",
13637
+ "b55f43a8-f444-4cd8-a3a4-0a4e786ba566": "steakusdc"
13638
+ },
13639
+ 8453: {
13640
+ "df65c4f4-e33a-481c-bac8-0c2252867c93": "wcusdbcv3",
13641
+ "0c8567f8-ba5b-41ad-80de-00a71895eb19": "wcusdcv3",
13642
+ "9d09b0be-f6c2-463a-ad2c-4552b3e12bd9": "wsgusdbc",
13643
+ "7e0661bf-8cf3-45e6-9424-31916d4c7b84": "sabasusdc",
13644
+ "833ec61b-f9e6-46ac-9eff-2785808b2389": "sabasusdbc",
13645
+ "b90eba2e-ed29-414e-b16d-82f9c3eae707": "meusd",
13646
+ "bde35fef-649f-4514-a564-e7e7da05eb52": "wsamm-eusd/usdc",
13647
+ "69c0fc74-dee5-4c60-9aed-a593661d54ea": "wvamm-weth/aero",
13648
+ "7b542141-5eed-4d70-bee6-0f9733beb362": "wvamm-mog/weth",
13649
+ "be8a4206-6543-4690-a5c2-b3e032245aa2": "wsamm-usdz/usdc",
13650
+ "593056a0-1e39-451d-acc8-081526625ab3": "wvamm-weth/cbbtc",
13651
+ "8af246ee-cf26-4c8e-88f8-f2021a69e44d": "wvamm-weth/well",
13652
+ "7e15dae2-ba5c-4658-b1a2-efb908a15200": "wvamm-weth/degen",
13653
+ "f388573e-5c0f-4dac-9f70-116a4aabaf17": "wsuperoethb"
13654
+ }
13655
+ };
13656
+ var LLAMA_CHAIN_MAP = {
13657
+ Ethereum: 1,
13658
+ Base: 8453
13659
+ };
13660
+ var CROSS_CHAIN_SYMBOLS = new Set(["wsteth", "cbeth"]);
13661
+ async function fetchCollateralYields() {
13662
+ const response = await fetchWithRetry("https://yields.llama.fi/pools", undefined, {
13663
+ timeoutMs: 30000
13664
+ });
13665
+ if (!response.ok) {
13666
+ throw new Error(`DefiLlama API failed: ${response.status} ${response.statusText}`);
13667
+ }
13668
+ const json = await response.json();
13669
+ const yields = {
13670
+ 1: {},
13671
+ 8453: {}
13672
+ };
13673
+ for (const pool of json.data) {
13674
+ const chainId = LLAMA_CHAIN_MAP[pool.chain];
13675
+ if (chainId === undefined)
13676
+ continue;
13677
+ const symbol = POOL_MAP[chainId]?.[pool.pool];
13678
+ if (!symbol)
13679
+ continue;
13680
+ yields[chainId][symbol] = pool.apyMean30d || 0;
13681
+ if (symbol === "cusdc" || symbol === "cusdt") {
13682
+ yields[chainId][`${symbol}-vault`] = yields[chainId][symbol];
13683
+ }
13684
+ if (CROSS_CHAIN_SYMBOLS.has(symbol)) {
13685
+ for (const targetChainId of Object.keys(yields)) {
13686
+ yields[Number(targetChainId)][symbol] = yields[chainId][symbol];
13687
+ }
13688
+ }
13689
+ }
13690
+ return yields;
13691
+ }
13692
+ // src/yield-dtf/fetch-apy.ts
13693
+ var MIN_SNAPSHOTS = 7;
13694
+ var TOKEN_SNAPSHOTS_QUERY = `query($token: String!) {
13695
+ tokenDailySnapshots(
13696
+ where: { token: $token }
13697
+ orderBy: timestamp
13698
+ orderDirection: desc
13699
+ first: 30
13700
+ ) { timestamp, basketRate }
13701
+ }`;
13702
+ var RTOKEN_SNAPSHOTS_QUERY = `query($rToken: String!) {
13703
+ rtokenDailySnapshots(
13704
+ where: { rToken: $rToken }
13705
+ orderBy: timestamp
13706
+ orderDirection: desc
13707
+ first: 30
13708
+ ) { timestamp, rsrExchangeRate }
13709
+ }`;
13710
+ async function fetchYieldDtfApy(chainId, rTokenAddress) {
13711
+ const url = YIELD_SUBGRAPH_URLS[chainId];
13712
+ if (!url)
13713
+ return { holdingApy: null, stakingApy: null };
13714
+ const addr = rTokenAddress.toLowerCase();
13715
+ const [tokenData, rTokenData] = await Promise.all([
13716
+ querySubgraph(chainId, TOKEN_SNAPSHOTS_QUERY, { token: addr }, url),
13717
+ querySubgraph(chainId, RTOKEN_SNAPSHOTS_QUERY, { rToken: addr }, url)
13718
+ ]);
13719
+ const holdingApy = computeCompoundApy(tokenData.tokenDailySnapshots.map((s) => ({
13720
+ timestamp: Number(s.timestamp),
13721
+ rate: Number(s.basketRate)
13722
+ })));
13723
+ const stakingApy = computeCompoundApy(rTokenData.rtokenDailySnapshots.map((s) => ({
13724
+ timestamp: Number(s.timestamp),
13725
+ rate: Number(s.rsrExchangeRate)
13726
+ })));
13727
+ return { holdingApy, stakingApy };
13728
+ }
13729
+ function computeCompoundApy(snapshots) {
13730
+ if (snapshots.length < MIN_SNAPSHOTS)
13731
+ return null;
13732
+ const newest = snapshots[0];
13733
+ const oldest = snapshots[snapshots.length - 1];
13734
+ if (oldest.rate === 0)
13735
+ return null;
13736
+ const ratio = newest.rate / oldest.rate;
13737
+ const daysBetween = (newest.timestamp - oldest.timestamp) / 86400;
13738
+ if (daysBetween <= 0)
13739
+ return null;
13740
+ return Math.pow(ratio, 365 / daysBetween) - 1;
13741
+ }
13742
+ // src/yield-dtf/fetch-revenue.ts
13743
+ async function fetchYieldDtfRevenue(chainId, rTokenAddress, days = 30) {
13744
+ const url = YIELD_SUBGRAPH_URLS[chainId];
13745
+ if (!url)
13746
+ return { snapshots: [], totalRTokenRevenueUSD: 0, totalRSRRevenueUSD: 0, totalRevenueUSD: 0 };
13747
+ const addr = rTokenAddress.toLowerCase();
13748
+ const fetchCount = days + 1;
13749
+ const rTokenQuery = `query($rToken: String!) {
13750
+ rtokenDailySnapshots(
13751
+ where: { rToken: $rToken }
13752
+ orderBy: timestamp
13753
+ orderDirection: desc
13754
+ first: ${fetchCount}
13755
+ ) {
13756
+ timestamp
13757
+ rsrStaked
13758
+ rsrExchangeRate
13759
+ rsrPrice
13760
+ }
13761
+ }`;
13762
+ const tokenQuery = `query($token: String!) {
13763
+ tokenDailySnapshots(
13764
+ where: { token: $token }
13765
+ orderBy: timestamp
13766
+ orderDirection: desc
13767
+ first: ${fetchCount}
13768
+ ) {
13769
+ timestamp
13770
+ basketRate
13771
+ dailyTotalSupply
13772
+ priceUSD
13773
+ }
13774
+ }`;
13775
+ const [rTokenData, tokenData] = await Promise.all([
13776
+ querySubgraph(chainId, rTokenQuery, { rToken: addr }, url),
13777
+ querySubgraph(chainId, tokenQuery, { token: addr }, url)
13778
+ ]);
13779
+ const stakerRevByTimestamp = new Map;
13780
+ const rSnaps = rTokenData.rtokenDailySnapshots;
13781
+ for (let i = 0;i < rSnaps.length - 1; i++) {
13782
+ const newer = rSnaps[i];
13783
+ const older = rSnaps[i + 1];
13784
+ const rateNew = Number(newer.rsrExchangeRate);
13785
+ const rateOld = Number(older.rsrExchangeRate);
13786
+ const rsrPrice = Number(newer.rsrPrice) || 0;
13787
+ let dailyRSRRevenueUSD = 0;
13788
+ if (rateOld > 0 && rateNew > rateOld) {
13789
+ const rsrStakedNorm = Number(newer.rsrStaked) / 1000000000000000000;
13790
+ dailyRSRRevenueUSD = rsrStakedNorm * ((rateNew - rateOld) / rateOld) * rsrPrice;
13791
+ }
13792
+ stakerRevByTimestamp.set(Number(newer.timestamp), {
13793
+ dailyRSRRevenueUSD,
13794
+ rsrStaked: newer.rsrStaked,
13795
+ rsrExchangeRate: rateNew,
13796
+ rsrPrice
13797
+ });
13798
+ }
13799
+ const holderRevByTimestamp = new Map;
13800
+ const tSnaps = tokenData.tokenDailySnapshots;
13801
+ for (let i = 0;i < tSnaps.length - 1; i++) {
13802
+ const newer = tSnaps[i];
13803
+ const older = tSnaps[i + 1];
13804
+ const rateNew = Number(newer.basketRate);
13805
+ const rateOld = Number(older.basketRate);
13806
+ const priceUSD = Number(newer.priceUSD) || 0;
13807
+ const totalSupplyNorm = Number(newer.dailyTotalSupply) / 1000000000000000000;
13808
+ let dailyRTokenRevenueUSD = 0;
13809
+ if (rateOld > 0 && rateNew > rateOld) {
13810
+ dailyRTokenRevenueUSD = totalSupplyNorm * ((rateNew - rateOld) / rateOld) * priceUSD;
13811
+ }
13812
+ holderRevByTimestamp.set(Number(newer.timestamp), dailyRTokenRevenueUSD);
13813
+ }
13814
+ const snapshots = [];
13815
+ let totalRTokenRevenueUSD = 0;
13816
+ let totalRSRRevenueUSD = 0;
13817
+ for (const [timestamp, staker] of stakerRevByTimestamp) {
13818
+ const holderRev = holderRevByTimestamp.get(timestamp) ?? findClosest(holderRevByTimestamp, timestamp) ?? 0;
13819
+ snapshots.push({
13820
+ timestamp,
13821
+ dailyRTokenRevenueUSD: holderRev,
13822
+ dailyRSRRevenueUSD: staker.dailyRSRRevenueUSD,
13823
+ rsrStaked: staker.rsrStaked,
13824
+ rsrExchangeRate: staker.rsrExchangeRate,
13825
+ rsrPrice: staker.rsrPrice
13826
+ });
13827
+ totalRTokenRevenueUSD += holderRev;
13828
+ totalRSRRevenueUSD += staker.dailyRSRRevenueUSD;
13829
+ }
13830
+ return {
13831
+ snapshots,
13832
+ totalRTokenRevenueUSD,
13833
+ totalRSRRevenueUSD,
13834
+ totalRevenueUSD: totalRTokenRevenueUSD + totalRSRRevenueUSD
13835
+ };
13836
+ }
13837
+ function findClosest(map, target) {
13838
+ let bestKey = 0;
13839
+ let bestDist = Infinity;
13840
+ for (const key of map.keys()) {
13841
+ const dist = Math.abs(key - target);
13842
+ if (dist < bestDist) {
13843
+ bestDist = dist;
13844
+ bestKey = key;
13845
+ }
13846
+ }
13847
+ if (bestDist > 43200)
13848
+ return null;
13849
+ return map.get(bestKey) ?? null;
13850
+ }
13851
+ // src/abi/rtoken.ts
13852
+ var rtokenAbi = [
13853
+ {
13854
+ inputs: [],
13855
+ name: "issuanceAvailable",
13856
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
13857
+ stateMutability: "view",
13858
+ type: "function"
13859
+ },
13860
+ {
13861
+ inputs: [],
13862
+ name: "redemptionAvailable",
13863
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
13864
+ stateMutability: "view",
13865
+ type: "function"
13866
+ }
13867
+ ];
13868
+
13869
+ // src/yield-dtf/read-status.ts
13870
+ async function readYieldDtfStatus(publicClient, mainAddress) {
13871
+ const results = await publicClient.multicall({
13872
+ contracts: [
13873
+ { address: mainAddress, abi: mainAbi, functionName: "frozen" },
13874
+ { address: mainAddress, abi: mainAbi, functionName: "issuancePausedOrFrozen" },
13875
+ { address: mainAddress, abi: mainAbi, functionName: "tradingPausedOrFrozen" }
13876
+ ],
13877
+ allowFailure: false
13878
+ });
13879
+ return {
13880
+ frozen: results[0],
13881
+ issuancePaused: results[1],
13882
+ tradingPaused: results[2]
13883
+ };
13884
+ }
13885
+ async function readThrottleStatus(publicClient, rTokenAddress) {
13886
+ const results = await publicClient.multicall({
13887
+ contracts: [
13888
+ { address: rTokenAddress, abi: rtokenAbi, functionName: "issuanceAvailable" },
13889
+ { address: rTokenAddress, abi: rtokenAbi, functionName: "redemptionAvailable" }
13890
+ ],
13891
+ allowFailure: false
13892
+ });
13893
+ return {
13894
+ issuanceAvailable: results[0],
13895
+ redemptionAvailable: results[1]
13896
+ };
13897
+ }
13225
13898
  // src/yield-dtf/issue.ts
13226
13899
  async function readIssueQuote(publicClient, facadeAddress, rTokenAddress, amount) {
13227
13900
  const result = await publicClient.readContract({
@@ -17611,6 +18284,27 @@ async function backfillChainlinkPrices(priceClient, days, batchSize = 50, feedAd
17611
18284
  }
17612
18285
  return records;
17613
18286
  }
18287
+ // src/prices/zapper-quote.ts
18288
+ var DUMMY_SIGNER = "0x0000000000000000000000000000000000000001";
18289
+ async function fetchZapSlippage(chainId, tokenIn, tokenOut, amountIn, slippage = 100, baseUrl = RESERVE_API_BASE_URL) {
18290
+ try {
18291
+ const quote = await fetchZapQuote(chainId, {
18292
+ tokenIn,
18293
+ tokenOut,
18294
+ amountIn,
18295
+ slippage,
18296
+ signer: DUMMY_SIGNER,
18297
+ trade: true
18298
+ }, baseUrl);
18299
+ return {
18300
+ priceImpact: quote.priceImpact,
18301
+ truePriceImpact: quote.truePriceImpact,
18302
+ gas: quote.gas
18303
+ };
18304
+ } catch {
18305
+ return null;
18306
+ }
18307
+ }
17614
18308
  // src/revenue/fetch-revenue.ts
17615
18309
  var REVENUE_QUERY = `
17616
18310
  query GetDTFRevenue($id: String!) {
@@ -18091,6 +18785,312 @@ function computeSharpeRatio(prices, riskFreeRate = 0) {
18091
18785
  const annualizedReturn = totalReturn * (365 / (prices.length - 1));
18092
18786
  return Math.round((annualizedReturn - riskFreeRate) / vol * 100) / 100;
18093
18787
  }
18788
+ function computeVaR(prices, confidence = 0.95) {
18789
+ if (prices.length < 3)
18790
+ return 0;
18791
+ const returns = [];
18792
+ for (let i = 1;i < prices.length; i++) {
18793
+ const prev = prices[i - 1].price;
18794
+ const curr = prices[i].price;
18795
+ if (prev <= 0)
18796
+ continue;
18797
+ returns.push((curr - prev) / prev);
18798
+ }
18799
+ if (returns.length < 2)
18800
+ return 0;
18801
+ const sorted = [...returns].sort((a, b) => a - b);
18802
+ const index2 = Math.floor((1 - confidence) * sorted.length);
18803
+ const varReturn = sorted[Math.min(index2, sorted.length - 1)];
18804
+ return Math.round(varReturn * 1e4) / 100;
18805
+ }
18806
+ function computeCorrelation(prices1, prices2) {
18807
+ if (prices1.length < 3 || prices2.length < 3)
18808
+ return 0;
18809
+ const len = Math.min(prices1.length, prices2.length);
18810
+ const returns1 = [];
18811
+ const returns2 = [];
18812
+ for (let i = 1;i < len; i++) {
18813
+ const prev1 = prices1[i - 1].price;
18814
+ const curr1 = prices1[i].price;
18815
+ const prev2 = prices2[i - 1].price;
18816
+ const curr2 = prices2[i].price;
18817
+ if (prev1 <= 0 || prev2 <= 0)
18818
+ continue;
18819
+ returns1.push((curr1 - prev1) / prev1);
18820
+ returns2.push((curr2 - prev2) / prev2);
18821
+ }
18822
+ if (returns1.length < 2)
18823
+ return 0;
18824
+ const mean1 = returns1.reduce((s, r) => s + r, 0) / returns1.length;
18825
+ const mean2 = returns2.reduce((s, r) => s + r, 0) / returns2.length;
18826
+ let cov = 0;
18827
+ let var1 = 0;
18828
+ let var2 = 0;
18829
+ for (let i = 0;i < returns1.length; i++) {
18830
+ const d1 = returns1[i] - mean1;
18831
+ const d2 = returns2[i] - mean2;
18832
+ cov += d1 * d2;
18833
+ var1 += d1 * d1;
18834
+ var2 += d2 * d2;
18835
+ }
18836
+ const denom = Math.sqrt(var1 * var2);
18837
+ if (denom === 0)
18838
+ return 0;
18839
+ return Math.round(cov / denom * 1e4) / 1e4;
18840
+ }
18841
+ function computeBeta(assetPrices, benchmarkPrices) {
18842
+ if (assetPrices.length < 3 || benchmarkPrices.length < 3)
18843
+ return 0;
18844
+ const len = Math.min(assetPrices.length, benchmarkPrices.length);
18845
+ const assetReturns = [];
18846
+ const benchReturns = [];
18847
+ for (let i = 1;i < len; i++) {
18848
+ const prevA = assetPrices[i - 1].price;
18849
+ const currA = assetPrices[i].price;
18850
+ const prevB = benchmarkPrices[i - 1].price;
18851
+ const currB = benchmarkPrices[i].price;
18852
+ if (prevA <= 0 || prevB <= 0)
18853
+ continue;
18854
+ assetReturns.push((currA - prevA) / prevA);
18855
+ benchReturns.push((currB - prevB) / prevB);
18856
+ }
18857
+ if (assetReturns.length < 2)
18858
+ return 0;
18859
+ const meanA = assetReturns.reduce((s, r) => s + r, 0) / assetReturns.length;
18860
+ const meanB = benchReturns.reduce((s, r) => s + r, 0) / benchReturns.length;
18861
+ let cov = 0;
18862
+ let varB = 0;
18863
+ for (let i = 0;i < assetReturns.length; i++) {
18864
+ const dA = assetReturns[i] - meanA;
18865
+ const dB = benchReturns[i] - meanB;
18866
+ cov += dA * dB;
18867
+ varB += dB * dB;
18868
+ }
18869
+ if (varB === 0)
18870
+ return 0;
18871
+ return Math.round(cov / varB * 1e4) / 1e4;
18872
+ }
18873
+ function computeTrackingError(assetPrices, benchmarkPrices) {
18874
+ if (assetPrices.length < 3 || benchmarkPrices.length < 3)
18875
+ return 0;
18876
+ const len = Math.min(assetPrices.length, benchmarkPrices.length);
18877
+ const diffs = [];
18878
+ for (let i = 1;i < len; i++) {
18879
+ const prevA = assetPrices[i - 1].price;
18880
+ const currA = assetPrices[i].price;
18881
+ const prevB = benchmarkPrices[i - 1].price;
18882
+ const currB = benchmarkPrices[i].price;
18883
+ if (prevA <= 0 || prevB <= 0)
18884
+ continue;
18885
+ const retA = (currA - prevA) / prevA;
18886
+ const retB = (currB - prevB) / prevB;
18887
+ diffs.push(retA - retB);
18888
+ }
18889
+ if (diffs.length < 2)
18890
+ return 0;
18891
+ const mean = diffs.reduce((s, d) => s + d, 0) / diffs.length;
18892
+ const variance = diffs.reduce((s, d) => s + (d - mean) ** 2, 0) / (diffs.length - 1);
18893
+ const dailyTE = Math.sqrt(variance);
18894
+ return Math.round(dailyTE * Math.sqrt(365) * 1e4) / 1e4;
18895
+ }
18896
+ // src/signals/thresholds.ts
18897
+ var TOKEN_WEIGHT_WARNING = 0.5;
18898
+ var TOKEN_WEIGHT_CRITICAL = 0.75;
18899
+ var HHI_CONCENTRATED = 0.25;
18900
+ var EFFECTIVE_N_LOW = 3;
18901
+ var TOP_HOLDER_WARNING = 30;
18902
+ var TOP5_HOLDERS_WARNING = 70;
18903
+ var TVL_FRAGILE = 50000;
18904
+ var TVL_VERY_LOW = 1e4;
18905
+ var FEE_HIGH_ANNUAL = 3;
18906
+ var FEE_VERY_HIGH_ANNUAL = 5;
18907
+ var MINT_FEE_HIGH = 0.5;
18908
+ var BACKING_LOW = 99.5;
18909
+ var VAR_95_HIGH = 10;
18910
+ var BETA_HIGH = 1.5;
18911
+ var BETA_LOW = 0.5;
18912
+ var DRAWDOWN_HIGH = 30;
18913
+
18914
+ // src/signals/compute-signals.ts
18915
+ function fmtUsd(n) {
18916
+ return `$${n.toLocaleString("en-US", { maximumFractionDigits: 0 })}`;
18917
+ }
18918
+ function computeBasketSignals(weights, symbols) {
18919
+ if (weights.length === 0)
18920
+ return [];
18921
+ const signals = [];
18922
+ for (let i = 0;i < weights.length; i++) {
18923
+ const w = weights[i];
18924
+ const label = symbols?.[i] ?? `Token #${i + 1}`;
18925
+ if (w > TOKEN_WEIGHT_CRITICAL) {
18926
+ signals.push({
18927
+ type: "concentration",
18928
+ severity: "critical",
18929
+ message: `${label} dominates basket at ${(w * 100).toFixed(1)}% (>${TOKEN_WEIGHT_CRITICAL * 100}% threshold)`
18930
+ });
18931
+ } else if (w > TOKEN_WEIGHT_WARNING) {
18932
+ signals.push({
18933
+ type: "concentration",
18934
+ severity: "warning",
18935
+ message: `${label} dominates basket at ${(w * 100).toFixed(1)}% (>${TOKEN_WEIGHT_WARNING * 100}% threshold)`
18936
+ });
18937
+ }
18938
+ }
18939
+ const hhi = weights.reduce((sum, w) => sum + w * w, 0);
18940
+ const effectiveN = hhi > 0 ? 1 / hhi : 0;
18941
+ if (hhi > HHI_CONCENTRATED) {
18942
+ signals.push({
18943
+ type: "concentration",
18944
+ severity: "warning",
18945
+ message: `High HHI concentration (${hhi.toFixed(2)} > ${HHI_CONCENTRATED}). ${effectiveN.toFixed(1)} effective tokens`
18946
+ });
18947
+ }
18948
+ if (effectiveN > 0 && effectiveN < EFFECTIVE_N_LOW) {
18949
+ signals.push({
18950
+ type: "concentration",
18951
+ severity: "warning",
18952
+ message: `Low diversification: ${effectiveN.toFixed(1)} effective tokens (< ${EFFECTIVE_N_LOW})`
18953
+ });
18954
+ }
18955
+ return signals;
18956
+ }
18957
+ function computeLiquiditySignals(tvlUsd) {
18958
+ if (tvlUsd === null)
18959
+ return [];
18960
+ if (tvlUsd < TVL_VERY_LOW) {
18961
+ return [{
18962
+ type: "liquidity",
18963
+ severity: "critical",
18964
+ message: `Very low TVL (${fmtUsd(tvlUsd)}) — below $10K threshold. Liquidity risk is extreme`
18965
+ }];
18966
+ }
18967
+ if (tvlUsd < TVL_FRAGILE) {
18968
+ return [{
18969
+ type: "liquidity",
18970
+ severity: "warning",
18971
+ message: `Low TVL (${fmtUsd(tvlUsd)}) — below $50K threshold`
18972
+ }];
18973
+ }
18974
+ return [];
18975
+ }
18976
+ function computeFeeSignals(tvlFeeAnnualPct, mintFeePct) {
18977
+ const signals = [];
18978
+ if (tvlFeeAnnualPct > FEE_VERY_HIGH_ANNUAL) {
18979
+ signals.push({
18980
+ type: "fee",
18981
+ severity: "warning",
18982
+ message: `High annual TVL fee (${tvlFeeAnnualPct.toFixed(2)}% > ${FEE_VERY_HIGH_ANNUAL}%)`
18983
+ });
18984
+ } else if (tvlFeeAnnualPct > FEE_HIGH_ANNUAL) {
18985
+ signals.push({
18986
+ type: "fee",
18987
+ severity: "info",
18988
+ message: `Above-average annual TVL fee (${tvlFeeAnnualPct.toFixed(2)}% > ${FEE_HIGH_ANNUAL}%)`
18989
+ });
18990
+ }
18991
+ if (mintFeePct !== undefined && mintFeePct > MINT_FEE_HIGH) {
18992
+ signals.push({
18993
+ type: "fee",
18994
+ severity: "info",
18995
+ message: `Mint fee of ${mintFeePct.toFixed(2)}% (> ${MINT_FEE_HIGH}%)`
18996
+ });
18997
+ }
18998
+ return signals;
18999
+ }
19000
+ function computeHolderSignals(holders) {
19001
+ if (holders.length === 0)
19002
+ return [];
19003
+ const signals = [];
19004
+ const topHolder = holders[0];
19005
+ if (topHolder.supplyPercent > TOP_HOLDER_WARNING) {
19006
+ signals.push({
19007
+ type: "holder-concentration",
19008
+ severity: "warning",
19009
+ message: `Top holder owns ${topHolder.supplyPercent.toFixed(1)}% of supply (>${TOP_HOLDER_WARNING}% threshold)`
19010
+ });
19011
+ }
19012
+ const top5Pct = holders.slice(0, 5).reduce((sum, h) => sum + h.supplyPercent, 0);
19013
+ if (top5Pct > TOP5_HOLDERS_WARNING) {
19014
+ signals.push({
19015
+ type: "holder-concentration",
19016
+ severity: "info",
19017
+ message: `Top 5 holders own ${top5Pct.toFixed(1)}% of supply (>${TOP5_HOLDERS_WARNING}% threshold)`
19018
+ });
19019
+ }
19020
+ return signals;
19021
+ }
19022
+ function computeOperationalSignals(status) {
19023
+ if (!status)
19024
+ return [];
19025
+ const signals = [];
19026
+ if (status.frozen) {
19027
+ signals.push({
19028
+ type: "operational",
19029
+ severity: "critical",
19030
+ message: "DTF is frozen — all operations halted"
19031
+ });
19032
+ }
19033
+ if (status.issuancePaused && !status.frozen) {
19034
+ signals.push({
19035
+ type: "operational",
19036
+ severity: "warning",
19037
+ message: "Issuance is paused"
19038
+ });
19039
+ }
19040
+ if (status.tradingPaused && !status.frozen) {
19041
+ signals.push({
19042
+ type: "operational",
19043
+ severity: "warning",
19044
+ message: "Trading is paused"
19045
+ });
19046
+ }
19047
+ if (status.backingPercent !== undefined && status.backingPercent < BACKING_LOW) {
19048
+ signals.push({
19049
+ type: "operational",
19050
+ severity: "critical",
19051
+ message: `Backing at ${status.backingPercent.toFixed(2)}% — below ${BACKING_LOW}% threshold`
19052
+ });
19053
+ }
19054
+ return signals;
19055
+ }
19056
+ function computePriceSignals(metrics) {
19057
+ const signals = [];
19058
+ if (metrics.var95Day !== undefined && metrics.var95Day !== null) {
19059
+ const absVar = Math.abs(metrics.var95Day);
19060
+ if (absVar > VAR_95_HIGH) {
19061
+ signals.push({
19062
+ type: "price",
19063
+ severity: "warning",
19064
+ message: `High daily VaR (${metrics.var95Day.toFixed(2)}%) — exceeds ${VAR_95_HIGH}% threshold`
19065
+ });
19066
+ }
19067
+ }
19068
+ if (metrics.beta !== undefined && metrics.beta !== null) {
19069
+ if (metrics.beta > BETA_HIGH) {
19070
+ signals.push({
19071
+ type: "price",
19072
+ severity: "warning",
19073
+ message: `High BTC beta (${metrics.beta.toFixed(2)}) — amplifies market moves (>${BETA_HIGH})`
19074
+ });
19075
+ } else if (metrics.beta < BETA_LOW) {
19076
+ signals.push({
19077
+ type: "price",
19078
+ severity: "info",
19079
+ message: `Low BTC beta (${metrics.beta.toFixed(2)}) — largely decorrelated (<${BETA_LOW})`
19080
+ });
19081
+ }
19082
+ }
19083
+ if (metrics.maxDrawdown !== undefined && metrics.maxDrawdown !== null) {
19084
+ if (metrics.maxDrawdown > DRAWDOWN_HIGH) {
19085
+ signals.push({
19086
+ type: "price",
19087
+ severity: "warning",
19088
+ message: `Severe max drawdown (${metrics.maxDrawdown.toFixed(2)}%) — exceeds ${DRAWDOWN_HIGH}% threshold`
19089
+ });
19090
+ }
19091
+ }
19092
+ return signals;
19093
+ }
18094
19094
  export {
18095
19095
  wrapInProposal,
18096
19096
  vote_lock_default as voteLockAbi,
@@ -18102,9 +19102,11 @@ export {
18102
19102
  timelock_default as timelockAbi,
18103
19103
  submitZapDeploy,
18104
19104
  stRSRAbi,
19105
+ rtokenAbi,
18105
19106
  resolveToken,
18106
19107
  readRedeemQuote as readYieldRedeemQuote,
18107
19108
  readIssueQuote as readYieldIssueQuote,
19109
+ readYieldDtfStatus,
18108
19110
  readYieldDtfPrice,
18109
19111
  readYieldDtfComponents,
18110
19112
  readYieldDtfBasket,
@@ -18115,6 +19117,7 @@ export {
18115
19117
  readUnstakingDelay,
18116
19118
  readTvlFee,
18117
19119
  readTotalSupply,
19120
+ readThrottleStatus,
18118
19121
  readSymbol,
18119
19122
  readStRSRInfo,
18120
19123
  readRewardTokens,
@@ -18160,8 +19163,12 @@ export {
18160
19163
  generateDeploymentNonce,
18161
19164
  formatRoleName,
18162
19165
  folio_default as folioAbi,
19166
+ fetchZapSlippage,
18163
19167
  fetchZapQuote,
19168
+ fetchYieldDtfRevenue,
19169
+ fetchYieldDtfDiscover,
18164
19170
  fetchYieldDtfConfig,
19171
+ fetchYieldDtfApy,
18165
19172
  fetchWithRetry,
18166
19173
  fetchVoteLockPositions,
18167
19174
  fetchTokenVolatility,
@@ -18182,6 +19189,7 @@ export {
18182
19189
  fetchDtfConfig,
18183
19190
  fetchDtfBaskets,
18184
19191
  fetchDtfBasket,
19192
+ fetchCollateralYields,
18185
19193
  fetchAllProposals,
18186
19194
  facadeReadAbi,
18187
19195
  extractDeployedAddress,
@@ -18211,18 +19219,28 @@ export {
18211
19219
  createPriceClient,
18212
19220
  createDtfClients,
18213
19221
  computeVolatility,
19222
+ computeVaR,
19223
+ computeTrackingError,
18214
19224
  computeTargetBasket,
18215
19225
  computeStartRebalanceParams,
18216
19226
  computeSharpeRatio,
18217
19227
  computeRsrBurnProjection,
18218
19228
  computeRevenueUsd,
18219
19229
  computeProposalState,
19230
+ computePriceSignals,
19231
+ computeOperationalSignals,
18220
19232
  computeOpenAuctionParams,
18221
19233
  computeMaxDrawdown,
18222
19234
  computeLockedRsr,
19235
+ computeLiquiditySignals,
19236
+ computeHolderSignals,
18223
19237
  computeHistoricalBurnTotals,
19238
+ computeFeeSignals,
18224
19239
  computeFeeMetrics,
19240
+ computeCorrelation,
18225
19241
  computeBurnAccuracy,
19242
+ computeBeta,
19243
+ computeBasketSignals,
18226
19244
  calculatePriceFromRange,
18227
19245
  buildVoteLockWithDelegateCalldata,
18228
19246
  buildVoteLockCalldata,
@@ -18262,8 +19280,15 @@ export {
18262
19280
  YIELD_SUBGRAPH_URLS,
18263
19281
  VOTE_LOCK_ADDRESS,
18264
19282
  VOLATILITY_TO_PRICE_ERROR,
19283
+ VAR_95_HIGH,
18265
19284
  V5_SPELL_ADDRESS,
18266
19285
  V4_SPELL_ADDRESS,
19286
+ TVL_VERY_LOW,
19287
+ TVL_FRAGILE,
19288
+ TOP_HOLDER_WARNING,
19289
+ TOP5_HOLDERS_WARNING,
19290
+ TOKEN_WEIGHT_WARNING,
19291
+ TOKEN_WEIGHT_CRITICAL,
18267
19292
  SUPPORTED_CHAINS,
18268
19293
  SUBGRAPH_URLS,
18269
19294
  STALE_PRICE_THRESHOLD_S,
@@ -18276,11 +19301,17 @@ export {
18276
19301
  PROPOSAL_STATE_MAP,
18277
19302
  PROPOSAL_STATES,
18278
19303
  PRICE_CONTROL,
19304
+ MINT_FEE_HIGH,
19305
+ HHI_CONCENTRATED,
18279
19306
  GOVERNANCE_SPELL_ADDRESS,
18280
19307
  GOVERNANCE_DEPLOYER_ADDRESS,
18281
19308
  FOLIO_ROLES,
19309
+ FEE_VERY_HIGH_ANNUAL,
19310
+ FEE_HIGH_ANNUAL,
18282
19311
  FACADE_READ_ADDRESS,
18283
19312
  ERC20_META_ABI,
19313
+ EFFECTIVE_N_LOW,
19314
+ DRAWDOWN_HIGH,
18284
19315
  DEPLOYER_ADDRESS,
18285
19316
  DEFAULT_TVL_FEE,
18286
19317
  DEFAULT_TRADING_GOV_PARAMS,
@@ -18295,5 +19326,8 @@ export {
18295
19326
  CHAINLINK_RSR_USD,
18296
19327
  CHAINLINK_DECIMALS,
18297
19328
  CHAINLINK_BTC_USD,
19329
+ BETA_LOW,
19330
+ BETA_HIGH,
19331
+ BACKING_LOW,
18298
19332
  AUCTION_LAUNCHER_WINDOW
18299
19333
  };