@reserve-protocol/dtf-sdk 0.1.4 → 0.1.6
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/abi/main.d.ts +30 -0
- package/dist/abi/main.d.ts.map +1 -1
- package/dist/abi/rtoken.d.ts +22 -0
- package/dist/abi/rtoken.d.ts.map +1 -0
- package/dist/analytics/compute-performance.d.ts +25 -0
- package/dist/analytics/compute-performance.d.ts.map +1 -1
- package/dist/dtf/fetch-dtf.d.ts +1 -16
- package/dist/dtf/fetch-dtf.d.ts.map +1 -1
- package/dist/dtf/read-config.d.ts.map +1 -1
- package/dist/governance/compute-proposal-state.d.ts.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1047 -13
- package/dist/prices/zapper-quote.d.ts +14 -0
- package/dist/prices/zapper-quote.d.ts.map +1 -0
- package/dist/signals/compute-signals.d.ts +30 -0
- package/dist/signals/compute-signals.d.ts.map +1 -0
- package/dist/signals/index.d.ts +4 -0
- package/dist/signals/index.d.ts.map +1 -0
- package/dist/signals/thresholds.d.ts +17 -0
- package/dist/signals/thresholds.d.ts.map +1 -0
- package/dist/signals/types.d.ts +8 -0
- package/dist/signals/types.d.ts.map +1 -0
- package/dist/types.d.ts +72 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/yield-dtf/collateral-yields.d.ts +12 -0
- package/dist/yield-dtf/collateral-yields.d.ts.map +1 -0
- package/dist/yield-dtf/fetch-apy.d.ts +12 -0
- package/dist/yield-dtf/fetch-apy.d.ts.map +1 -0
- package/dist/yield-dtf/fetch-discover.d.ts +17 -0
- package/dist/yield-dtf/fetch-discover.d.ts.map +1 -0
- package/dist/yield-dtf/fetch-revenue.d.ts +11 -0
- package/dist/yield-dtf/fetch-revenue.d.ts.map +1 -0
- package/dist/yield-dtf/read-config.d.ts.map +1 -1
- package/dist/yield-dtf/read-status.d.ts +13 -0
- package/dist/yield-dtf/read-status.d.ts.map +1 -0
- 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 });
|
|
@@ -12641,7 +12834,7 @@ async function fetchDtfBasket(chainId, folioAddress, baseUrl = RESERVE_API_BASE_
|
|
|
12641
12834
|
const url = `${baseUrl}/current/dtf?address=${folioAddress.toLowerCase()}&chainId=${chainId}`;
|
|
12642
12835
|
const response = await fetchWithRetry(url);
|
|
12643
12836
|
if (!response.ok) {
|
|
12644
|
-
throw new Error(`Reserve API /current/dtf failed: ${response.status} ${response.statusText}`);
|
|
12837
|
+
throw new Error(`Reserve API /current/dtf failed for ${folioAddress} on chain ${chainId}: ${response.status} ${response.statusText}`);
|
|
12645
12838
|
}
|
|
12646
12839
|
return await response.json();
|
|
12647
12840
|
}
|
|
@@ -12650,7 +12843,7 @@ async function fetchDtfBaskets(chainId, folioAddresses, baseUrl = RESERVE_API_BA
|
|
|
12650
12843
|
const url = `${baseUrl}/current/dtfs?addresses=${addresses}&chainId=${chainId}`;
|
|
12651
12844
|
const response = await fetchWithRetry(url);
|
|
12652
12845
|
if (!response.ok) {
|
|
12653
|
-
throw new Error(`Reserve API /current/dtfs failed: ${response.status} ${response.statusText}`);
|
|
12846
|
+
throw new Error(`Reserve API /current/dtfs failed for [${folioAddresses.join(", ")}] on chain ${chainId}: ${response.status} ${response.statusText}`);
|
|
12654
12847
|
}
|
|
12655
12848
|
return await response.json();
|
|
12656
12849
|
}
|
|
@@ -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
|
|
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
|
|
12968
|
+
const json = await response.json();
|
|
12969
|
+
const r = json.result ?? json;
|
|
12765
12970
|
return {
|
|
12766
|
-
amountOut: BigInt(
|
|
12767
|
-
|
|
12768
|
-
|
|
12769
|
-
|
|
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 D18_NUM = 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) / D18_NUM;
|
|
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") / D18_NUM * 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) / D18_NUM : 1,
|
|
13571
|
+
rsrStaked: t.rToken?.rsrStaked ?? "0",
|
|
13572
|
+
rsrExchangeRate: t.rToken ? Number(t.rToken.rsrExchangeRate) / D18_NUM : 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({
|
|
@@ -13454,7 +14127,7 @@ async function fetchRebalanceHistory(chainId, folioAddress, opts, baseUrl = RESE
|
|
|
13454
14127
|
const url = `${baseUrl}/dtf/rebalance?address=${folioAddress.toLowerCase()}&chainId=${chainId}&skip=${skip}&limit=${limit}`;
|
|
13455
14128
|
const response = await fetchWithRetry(url);
|
|
13456
14129
|
if (!response.ok) {
|
|
13457
|
-
throw new Error(`Reserve API /dtf/rebalance failed: ${response.status} ${response.statusText}`);
|
|
14130
|
+
throw new Error(`Reserve API /dtf/rebalance failed for ${folioAddress} on chain ${chainId}: ${response.status} ${response.statusText}`);
|
|
13458
14131
|
}
|
|
13459
14132
|
return await response.json();
|
|
13460
14133
|
}
|
|
@@ -13462,7 +14135,7 @@ async function fetchRebalanceDetail(chainId, folioAddress, nonce, baseUrl = RESE
|
|
|
13462
14135
|
const url = `${baseUrl}/dtf/rebalance?address=${folioAddress.toLowerCase()}&chainId=${chainId}&nonce=${nonce}`;
|
|
13463
14136
|
const response = await fetchWithRetry(url);
|
|
13464
14137
|
if (!response.ok) {
|
|
13465
|
-
throw new Error(`Reserve API /dtf/rebalance detail failed: ${response.status} ${response.statusText}`);
|
|
14138
|
+
throw new Error(`Reserve API /dtf/rebalance detail failed for ${folioAddress} nonce ${nonce} on chain ${chainId}: ${response.status} ${response.statusText}`);
|
|
13466
14139
|
}
|
|
13467
14140
|
return await response.json();
|
|
13468
14141
|
}
|
|
@@ -17470,7 +18143,7 @@ async function fetchTokenPrices(chainId, tokenAddresses, baseUrl = RESERVE_API_B
|
|
|
17470
18143
|
const url = `${baseUrl}/current/prices?chainId=${chainId}&tokens=${tokens}`;
|
|
17471
18144
|
const response = await fetchWithRetry(url);
|
|
17472
18145
|
if (!response.ok) {
|
|
17473
|
-
throw new Error(`Reserve API prices failed: ${response.status} ${response.statusText}`);
|
|
18146
|
+
throw new Error(`Reserve API prices failed for chain ${chainId} (${tokenAddresses.length} tokens): ${response.status} ${response.statusText}`);
|
|
17474
18147
|
}
|
|
17475
18148
|
const data = await response.json();
|
|
17476
18149
|
const prices = {};
|
|
@@ -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
|
};
|