@reserve-protocol/dtf-sdk 0.1.3 → 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.
- 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 +50 -0
- package/dist/analytics/compute-performance.d.ts.map +1 -0
- package/dist/dtf/fetch-dtf.d.ts +1 -16
- package/dist/dtf/fetch-dtf.d.ts.map +1 -1
- package/dist/dtf/mint.d.ts +1 -0
- package/dist/dtf/mint.d.ts.map +1 -1
- package/dist/dtf/read-config.d.ts.map +1 -1
- package/dist/governance/fetch-proposals.d.ts.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1184 -78
- package/dist/prices/zapper-quote.d.ts +14 -0
- package/dist/prices/zapper-quote.d.ts.map +1 -0
- package/dist/rebalance/read-bid-quote.d.ts +13 -0
- package/dist/rebalance/read-bid-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 +75 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vote-lock/read-vote-lock.d.ts +2 -0
- package/dist/vote-lock/read-vote-lock.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 });
|
|
@@ -12547,16 +12740,19 @@ var GOV_FRAGMENT = `
|
|
|
12547
12740
|
timelock {
|
|
12548
12741
|
id
|
|
12549
12742
|
executionDelay
|
|
12743
|
+
guardians
|
|
12550
12744
|
}
|
|
12551
12745
|
`;
|
|
12552
12746
|
var DTF_QUERY = `
|
|
12553
12747
|
query getDTF($id: String!) {
|
|
12554
12748
|
dtf(id: $id) {
|
|
12555
12749
|
id
|
|
12750
|
+
timestamp
|
|
12556
12751
|
auctionLength
|
|
12557
12752
|
mandate
|
|
12558
12753
|
tvlFee
|
|
12559
12754
|
mintingFee
|
|
12755
|
+
bidsEnabled
|
|
12560
12756
|
auctionLaunchers
|
|
12561
12757
|
brandManagers
|
|
12562
12758
|
ownerGovernance {
|
|
@@ -12582,7 +12778,8 @@ function parseGovernance(raw) {
|
|
|
12582
12778
|
timelockAddress: raw.timelock?.id ?? "0x0000000000000000000000000000000000000000",
|
|
12583
12779
|
votingDelay: Number(raw.votingDelay ?? 0),
|
|
12584
12780
|
votingPeriod: Number(raw.votingPeriod ?? 0),
|
|
12585
|
-
executionDelay: Number(raw.timelock?.executionDelay ?? 0)
|
|
12781
|
+
executionDelay: Number(raw.timelock?.executionDelay ?? 0),
|
|
12782
|
+
guardians: raw.timelock?.guardians ?? []
|
|
12586
12783
|
};
|
|
12587
12784
|
}
|
|
12588
12785
|
async function fetchDtfConfig(publicClient, chainId, folioAddress) {
|
|
@@ -12601,6 +12798,7 @@ async function fetchDtfConfig(publicClient, chainId, folioAddress) {
|
|
|
12601
12798
|
return {
|
|
12602
12799
|
tokens,
|
|
12603
12800
|
auctionLength: Number(dtf.auctionLength ?? 300),
|
|
12801
|
+
bidsEnabled: dtf.bidsEnabled ?? true,
|
|
12604
12802
|
ownerGovernance: parseGovernance(dtf.ownerGovernance),
|
|
12605
12803
|
tradingGovernance: parseGovernance(dtf.tradingGovernance),
|
|
12606
12804
|
stTokenGovernance: parseGovernance(dtf.stToken?.governance),
|
|
@@ -12609,7 +12807,8 @@ async function fetchDtfConfig(publicClient, chainId, folioAddress) {
|
|
|
12609
12807
|
tvlFee: dtf.tvlFee ?? "0",
|
|
12610
12808
|
mintingFee: dtf.mintingFee ?? "0",
|
|
12611
12809
|
auctionLaunchers: dtf.auctionLaunchers ?? [],
|
|
12612
|
-
brandManagers: dtf.brandManagers ?? []
|
|
12810
|
+
brandManagers: dtf.brandManagers ?? [],
|
|
12811
|
+
deployedAt: Number(dtf.timestamp ?? 0)
|
|
12613
12812
|
};
|
|
12614
12813
|
}
|
|
12615
12814
|
// src/dtf/read-basket.ts
|
|
@@ -12750,17 +12949,36 @@ async function fetchDtfPrice(chainId, folioAddress, baseUrl = RESERVE_API_BASE_U
|
|
|
12750
12949
|
return data.price;
|
|
12751
12950
|
}
|
|
12752
12951
|
async function fetchZapQuote(chainId, params, baseUrl = RESERVE_API_BASE_URL) {
|
|
12753
|
-
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()}`;
|
|
12754
12964
|
const response = await fetchWithRetry(url);
|
|
12755
12965
|
if (!response.ok) {
|
|
12756
|
-
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}`);
|
|
12757
12967
|
}
|
|
12758
|
-
const
|
|
12968
|
+
const json = await response.json();
|
|
12969
|
+
const r = json.result ?? json;
|
|
12759
12970
|
return {
|
|
12760
|
-
amountOut: BigInt(
|
|
12761
|
-
|
|
12762
|
-
|
|
12763
|
-
|
|
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")
|
|
12764
12982
|
};
|
|
12765
12983
|
}
|
|
12766
12984
|
async function fetchVoteLockPositions(baseUrl = RESERVE_API_BASE_URL) {
|
|
@@ -12915,6 +13133,27 @@ var mainAbi = [
|
|
|
12915
13133
|
outputs: [{ internalType: "contract IRevenueTrader", name: "", type: "address" }],
|
|
12916
13134
|
stateMutability: "view",
|
|
12917
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"
|
|
12918
13157
|
}
|
|
12919
13158
|
];
|
|
12920
13159
|
|
|
@@ -13184,7 +13423,7 @@ async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
|
|
|
13184
13423
|
throw new Error(`No FacadeRead address for chainId ${chainId}`);
|
|
13185
13424
|
}
|
|
13186
13425
|
const components = await readYieldDtfComponents(publicClient, rTokenAddress);
|
|
13187
|
-
const [basket, backing, price, nameResult, symbolResult, stRSRInfo, distribution] = await Promise.all([
|
|
13426
|
+
const [basket, backing, price, nameResult, symbolResult, totalSupplyResult, stRSRInfo, distribution] = await Promise.all([
|
|
13188
13427
|
readYieldDtfBasket(publicClient, facadeAddress, rTokenAddress),
|
|
13189
13428
|
readBackingOverview(publicClient, facadeAddress, rTokenAddress),
|
|
13190
13429
|
readYieldDtfPrice(publicClient, facadeAddress, rTokenAddress),
|
|
@@ -13198,9 +13437,17 @@ async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
|
|
|
13198
13437
|
abi: ERC20_META_ABI,
|
|
13199
13438
|
functionName: "symbol"
|
|
13200
13439
|
}),
|
|
13440
|
+
publicClient.readContract({
|
|
13441
|
+
address: rTokenAddress,
|
|
13442
|
+
abi: ERC20_META_ABI,
|
|
13443
|
+
functionName: "totalSupply"
|
|
13444
|
+
}),
|
|
13201
13445
|
readStRSRInfo(publicClient, components.stRSR),
|
|
13202
13446
|
readDistribution(publicClient, components.distributor)
|
|
13203
13447
|
]);
|
|
13448
|
+
const totalSupply = totalSupplyResult;
|
|
13449
|
+
const avgPrice = (Number(price.low) + Number(price.high)) / 2;
|
|
13450
|
+
const tvl = avgPrice * Number(totalSupply) / (1000000000000000000 * 1000000000000000000);
|
|
13204
13451
|
return {
|
|
13205
13452
|
type: "yield",
|
|
13206
13453
|
components,
|
|
@@ -13210,12 +13457,444 @@ async function fetchYieldDtfConfig(publicClient, chainId, rTokenAddress) {
|
|
|
13210
13457
|
backing,
|
|
13211
13458
|
priceLow: price.low,
|
|
13212
13459
|
priceHigh: price.high,
|
|
13460
|
+
totalSupply,
|
|
13461
|
+
tvl,
|
|
13213
13462
|
exchangeRate: stRSRInfo.exchangeRate,
|
|
13214
13463
|
unstakingDelay: stRSRInfo.unstakingDelay,
|
|
13215
13464
|
rTokenTotal: distribution.rTokenTotal,
|
|
13216
13465
|
rsrTotal: distribution.rsrTotal
|
|
13217
13466
|
};
|
|
13218
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
|
+
}
|
|
13219
13898
|
// src/yield-dtf/issue.ts
|
|
13220
13899
|
async function readIssueQuote(publicClient, facadeAddress, rTokenAddress, amount) {
|
|
13221
13900
|
const result = await publicClient.readContract({
|
|
@@ -13276,6 +13955,13 @@ async function readMintFee(publicClient, folioAddress) {
|
|
|
13276
13955
|
functionName: "mintFee"
|
|
13277
13956
|
});
|
|
13278
13957
|
}
|
|
13958
|
+
async function readTvlFee(publicClient, folioAddress) {
|
|
13959
|
+
return await publicClient.readContract({
|
|
13960
|
+
address: folioAddress,
|
|
13961
|
+
abi: folio_default,
|
|
13962
|
+
functionName: "tvlFee"
|
|
13963
|
+
});
|
|
13964
|
+
}
|
|
13279
13965
|
function buildMintCalldata(folioAddress, shares, receiver, minSharesOut) {
|
|
13280
13966
|
assert6(shares > 0n, "shares must be greater than 0");
|
|
13281
13967
|
return {
|
|
@@ -15238,79 +15924,48 @@ async function readProposalActions(publicClient, governorAddress, proposalId, fr
|
|
|
15238
15924
|
};
|
|
15239
15925
|
}
|
|
15240
15926
|
// src/governance/fetch-proposals.ts
|
|
15241
|
-
var
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
|
|
15250
|
-
|
|
15251
|
-
|
|
15252
|
-
|
|
15253
|
-
|
|
15254
|
-
|
|
15255
|
-
|
|
15256
|
-
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
|
|
15260
|
-
|
|
15261
|
-
|
|
15262
|
-
|
|
15263
|
-
|
|
15264
|
-
|
|
15265
|
-
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
15271
|
-
) {
|
|
15272
|
-
id
|
|
15273
|
-
proposer { address }
|
|
15274
|
-
state
|
|
15275
|
-
description
|
|
15276
|
-
forWeightedVotes
|
|
15277
|
-
againstWeightedVotes
|
|
15278
|
-
abstainWeightedVotes
|
|
15279
|
-
quorumVotes
|
|
15280
|
-
voteStart
|
|
15281
|
-
voteEnd
|
|
15282
|
-
creationTime
|
|
15283
|
-
executionTime
|
|
15284
|
-
cancellationTime
|
|
15285
|
-
governance { id }
|
|
15286
|
-
}
|
|
15287
|
-
}
|
|
15288
|
-
`;
|
|
15289
|
-
var ALL_PROPOSALS_WITH_STATES_QUERY = `
|
|
15290
|
-
query getAllProposals($first: Int!, $states: [String!]) {
|
|
15927
|
+
var PROPOSAL_FIELDS = `
|
|
15928
|
+
id
|
|
15929
|
+
proposer { address }
|
|
15930
|
+
state
|
|
15931
|
+
description
|
|
15932
|
+
forWeightedVotes
|
|
15933
|
+
againstWeightedVotes
|
|
15934
|
+
abstainWeightedVotes
|
|
15935
|
+
quorumVotes
|
|
15936
|
+
voteStart
|
|
15937
|
+
voteEnd
|
|
15938
|
+
creationTime
|
|
15939
|
+
executionTime
|
|
15940
|
+
cancellationTime`;
|
|
15941
|
+
function buildProposalQuery(opts) {
|
|
15942
|
+
const params = ["$first: Int!"];
|
|
15943
|
+
const where = [];
|
|
15944
|
+
if (opts.governance) {
|
|
15945
|
+
params.push("$governance: String!");
|
|
15946
|
+
where.push("governance: $governance");
|
|
15947
|
+
}
|
|
15948
|
+
if (opts.states) {
|
|
15949
|
+
params.push("$states: [String!]");
|
|
15950
|
+
where.push("state_in: $states");
|
|
15951
|
+
}
|
|
15952
|
+
const whereClause = where.length > 0 ? `where: { ${where.join(", ")} }` : "";
|
|
15953
|
+
const extra = opts.includeGovernance ? `
|
|
15954
|
+
governance { id }` : "";
|
|
15955
|
+
return `
|
|
15956
|
+
query getProposals(${params.join(", ")}) {
|
|
15291
15957
|
proposals(
|
|
15292
|
-
|
|
15958
|
+
${whereClause}
|
|
15293
15959
|
orderBy: creationTime
|
|
15294
15960
|
orderDirection: desc
|
|
15295
15961
|
first: $first
|
|
15296
|
-
) {
|
|
15297
|
-
id
|
|
15298
|
-
proposer { address }
|
|
15299
|
-
state
|
|
15300
|
-
description
|
|
15301
|
-
forWeightedVotes
|
|
15302
|
-
againstWeightedVotes
|
|
15303
|
-
abstainWeightedVotes
|
|
15304
|
-
quorumVotes
|
|
15305
|
-
voteStart
|
|
15306
|
-
voteEnd
|
|
15307
|
-
creationTime
|
|
15308
|
-
executionTime
|
|
15309
|
-
cancellationTime
|
|
15310
|
-
governance { id }
|
|
15962
|
+
) {${PROPOSAL_FIELDS}${extra}
|
|
15311
15963
|
}
|
|
15312
|
-
}
|
|
15313
|
-
|
|
15964
|
+
}`;
|
|
15965
|
+
}
|
|
15966
|
+
var PROPOSALS_QUERY = buildProposalQuery({ governance: true });
|
|
15967
|
+
var ALL_PROPOSALS_QUERY = buildProposalQuery({ includeGovernance: true });
|
|
15968
|
+
var ALL_PROPOSALS_WITH_STATES_QUERY = buildProposalQuery({ states: true, includeGovernance: true });
|
|
15314
15969
|
async function fetchProposals(chainId, governorAddress, first = 20) {
|
|
15315
15970
|
const url = SUBGRAPH_URLS[chainId];
|
|
15316
15971
|
if (!url)
|
|
@@ -16546,6 +17201,21 @@ async function readActiveAuction(publicClient, folioAddress) {
|
|
|
16546
17201
|
isActive
|
|
16547
17202
|
};
|
|
16548
17203
|
}
|
|
17204
|
+
// src/rebalance/read-bid-quote.ts
|
|
17205
|
+
async function readBidQuote(publicClient, folioAddress, auctionId, sellToken, buyToken, maxSellAmount, timestamp) {
|
|
17206
|
+
const ts = timestamp ?? BigInt(Math.floor(Date.now() / 1000));
|
|
17207
|
+
const result = await publicClient.readContract({
|
|
17208
|
+
address: folioAddress,
|
|
17209
|
+
abi: folio_default,
|
|
17210
|
+
functionName: "getBid",
|
|
17211
|
+
args: [auctionId, sellToken, buyToken, ts, maxSellAmount]
|
|
17212
|
+
});
|
|
17213
|
+
return {
|
|
17214
|
+
sellAmount: result[0],
|
|
17215
|
+
bidAmount: result[1],
|
|
17216
|
+
price: result[2]
|
|
17217
|
+
};
|
|
17218
|
+
}
|
|
16549
17219
|
// src/rebalance/transform.ts
|
|
16550
17220
|
function transformV5Rebalance(raw) {
|
|
16551
17221
|
const [nonce, priceControl, tokenParams, limits, timestamps] = raw;
|
|
@@ -17427,6 +18097,13 @@ async function readMaxWithdraw(publicClient, stToken, account) {
|
|
|
17427
18097
|
args: [account]
|
|
17428
18098
|
});
|
|
17429
18099
|
}
|
|
18100
|
+
async function readUnstakingDelay(publicClient, stToken) {
|
|
18101
|
+
return await publicClient.readContract({
|
|
18102
|
+
address: stToken,
|
|
18103
|
+
abi: vote_lock_default,
|
|
18104
|
+
functionName: "unstakingDelay"
|
|
18105
|
+
});
|
|
18106
|
+
}
|
|
17430
18107
|
async function readRewardTokens(publicClient, stToken) {
|
|
17431
18108
|
return await publicClient.readContract({
|
|
17432
18109
|
address: stToken,
|
|
@@ -17434,6 +18111,18 @@ async function readRewardTokens(publicClient, stToken) {
|
|
|
17434
18111
|
functionName: "getAllRewardTokens"
|
|
17435
18112
|
});
|
|
17436
18113
|
}
|
|
18114
|
+
async function readVoteLockExchangeRate(publicClient, stToken) {
|
|
18115
|
+
try {
|
|
18116
|
+
return await publicClient.readContract({
|
|
18117
|
+
address: stToken,
|
|
18118
|
+
abi: vote_lock_default,
|
|
18119
|
+
functionName: "convertToAssets",
|
|
18120
|
+
args: [10n ** 18n]
|
|
18121
|
+
});
|
|
18122
|
+
} catch {
|
|
18123
|
+
return 10n ** 18n;
|
|
18124
|
+
}
|
|
18125
|
+
}
|
|
17437
18126
|
async function readVoteLockAsset(publicClient, stToken) {
|
|
17438
18127
|
return await publicClient.readContract({
|
|
17439
18128
|
address: stToken,
|
|
@@ -17595,6 +18284,27 @@ async function backfillChainlinkPrices(priceClient, days, batchSize = 50, feedAd
|
|
|
17595
18284
|
}
|
|
17596
18285
|
return records;
|
|
17597
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
|
+
}
|
|
17598
18308
|
// src/revenue/fetch-revenue.ts
|
|
17599
18309
|
var REVENUE_QUERY = `
|
|
17600
18310
|
query GetDTFRevenue($id: String!) {
|
|
@@ -18026,6 +18736,361 @@ function computeHistoricalBurnTotals(burns, prices) {
|
|
|
18026
18736
|
}
|
|
18027
18737
|
return { totalBurnedUsdHistorical };
|
|
18028
18738
|
}
|
|
18739
|
+
// src/analytics/compute-performance.ts
|
|
18740
|
+
function computeMaxDrawdown(prices) {
|
|
18741
|
+
if (prices.length < 2)
|
|
18742
|
+
return 0;
|
|
18743
|
+
let peak = -Infinity;
|
|
18744
|
+
let maxDrawdown = 0;
|
|
18745
|
+
for (const p of prices) {
|
|
18746
|
+
if (p.price <= 0)
|
|
18747
|
+
continue;
|
|
18748
|
+
if (p.price > peak)
|
|
18749
|
+
peak = p.price;
|
|
18750
|
+
const drawdown = (peak - p.price) / peak * 100;
|
|
18751
|
+
if (drawdown > maxDrawdown)
|
|
18752
|
+
maxDrawdown = drawdown;
|
|
18753
|
+
}
|
|
18754
|
+
return Math.round(maxDrawdown * 100) / 100;
|
|
18755
|
+
}
|
|
18756
|
+
function computeVolatility(prices) {
|
|
18757
|
+
if (prices.length < 3)
|
|
18758
|
+
return 0;
|
|
18759
|
+
const returns = [];
|
|
18760
|
+
for (let i = 1;i < prices.length; i++) {
|
|
18761
|
+
const prev = prices[i - 1].price;
|
|
18762
|
+
const curr = prices[i].price;
|
|
18763
|
+
if (prev <= 0)
|
|
18764
|
+
continue;
|
|
18765
|
+
returns.push((curr - prev) / prev);
|
|
18766
|
+
}
|
|
18767
|
+
if (returns.length < 2)
|
|
18768
|
+
return 0;
|
|
18769
|
+
const mean = returns.reduce((s, r) => s + r, 0) / returns.length;
|
|
18770
|
+
const variance = returns.reduce((s, r) => s + (r - mean) ** 2, 0) / (returns.length - 1);
|
|
18771
|
+
const dailyStdDev = Math.sqrt(variance);
|
|
18772
|
+
return Math.round(dailyStdDev * Math.sqrt(365) * 1e4) / 1e4;
|
|
18773
|
+
}
|
|
18774
|
+
function computeSharpeRatio(prices, riskFreeRate = 0) {
|
|
18775
|
+
if (prices.length < 3)
|
|
18776
|
+
return 0;
|
|
18777
|
+
const vol = computeVolatility(prices);
|
|
18778
|
+
if (vol === 0)
|
|
18779
|
+
return 0;
|
|
18780
|
+
const first = prices[0].price;
|
|
18781
|
+
const last = prices[prices.length - 1].price;
|
|
18782
|
+
if (first <= 0)
|
|
18783
|
+
return 0;
|
|
18784
|
+
const totalReturn = (last - first) / first;
|
|
18785
|
+
const annualizedReturn = totalReturn * (365 / (prices.length - 1));
|
|
18786
|
+
return Math.round((annualizedReturn - riskFreeRate) / vol * 100) / 100;
|
|
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
|
+
}
|
|
18029
19094
|
export {
|
|
18030
19095
|
wrapInProposal,
|
|
18031
19096
|
vote_lock_default as voteLockAbi,
|
|
@@ -18037,16 +19102,22 @@ export {
|
|
|
18037
19102
|
timelock_default as timelockAbi,
|
|
18038
19103
|
submitZapDeploy,
|
|
18039
19104
|
stRSRAbi,
|
|
19105
|
+
rtokenAbi,
|
|
18040
19106
|
resolveToken,
|
|
18041
19107
|
readRedeemQuote as readYieldRedeemQuote,
|
|
18042
19108
|
readIssueQuote as readYieldIssueQuote,
|
|
19109
|
+
readYieldDtfStatus,
|
|
18043
19110
|
readYieldDtfPrice,
|
|
18044
19111
|
readYieldDtfComponents,
|
|
18045
19112
|
readYieldDtfBasket,
|
|
18046
19113
|
readVotingPower,
|
|
18047
19114
|
readVoteLockInfo,
|
|
19115
|
+
readVoteLockExchangeRate,
|
|
18048
19116
|
readVoteLockAsset,
|
|
19117
|
+
readUnstakingDelay,
|
|
19118
|
+
readTvlFee,
|
|
18049
19119
|
readTotalSupply,
|
|
19120
|
+
readThrottleStatus,
|
|
18050
19121
|
readSymbol,
|
|
18051
19122
|
readStRSRInfo,
|
|
18052
19123
|
readRewardTokens,
|
|
@@ -18070,6 +19141,7 @@ export {
|
|
|
18070
19141
|
readDtfRoles,
|
|
18071
19142
|
readDistribution,
|
|
18072
19143
|
readChainlinkPrice,
|
|
19144
|
+
readBidQuote,
|
|
18073
19145
|
readBasket,
|
|
18074
19146
|
readBalanceOf,
|
|
18075
19147
|
readBackingOverview,
|
|
@@ -18091,8 +19163,12 @@ export {
|
|
|
18091
19163
|
generateDeploymentNonce,
|
|
18092
19164
|
formatRoleName,
|
|
18093
19165
|
folio_default as folioAbi,
|
|
19166
|
+
fetchZapSlippage,
|
|
18094
19167
|
fetchZapQuote,
|
|
19168
|
+
fetchYieldDtfRevenue,
|
|
19169
|
+
fetchYieldDtfDiscover,
|
|
18095
19170
|
fetchYieldDtfConfig,
|
|
19171
|
+
fetchYieldDtfApy,
|
|
18096
19172
|
fetchWithRetry,
|
|
18097
19173
|
fetchVoteLockPositions,
|
|
18098
19174
|
fetchTokenVolatility,
|
|
@@ -18113,6 +19189,7 @@ export {
|
|
|
18113
19189
|
fetchDtfConfig,
|
|
18114
19190
|
fetchDtfBaskets,
|
|
18115
19191
|
fetchDtfBasket,
|
|
19192
|
+
fetchCollateralYields,
|
|
18116
19193
|
fetchAllProposals,
|
|
18117
19194
|
facadeReadAbi,
|
|
18118
19195
|
extractDeployedAddress,
|
|
@@ -18141,16 +19218,29 @@ export {
|
|
|
18141
19218
|
decodeProposalActions,
|
|
18142
19219
|
createPriceClient,
|
|
18143
19220
|
createDtfClients,
|
|
19221
|
+
computeVolatility,
|
|
19222
|
+
computeVaR,
|
|
19223
|
+
computeTrackingError,
|
|
18144
19224
|
computeTargetBasket,
|
|
18145
19225
|
computeStartRebalanceParams,
|
|
19226
|
+
computeSharpeRatio,
|
|
18146
19227
|
computeRsrBurnProjection,
|
|
18147
19228
|
computeRevenueUsd,
|
|
18148
19229
|
computeProposalState,
|
|
19230
|
+
computePriceSignals,
|
|
19231
|
+
computeOperationalSignals,
|
|
18149
19232
|
computeOpenAuctionParams,
|
|
19233
|
+
computeMaxDrawdown,
|
|
18150
19234
|
computeLockedRsr,
|
|
19235
|
+
computeLiquiditySignals,
|
|
19236
|
+
computeHolderSignals,
|
|
18151
19237
|
computeHistoricalBurnTotals,
|
|
19238
|
+
computeFeeSignals,
|
|
18152
19239
|
computeFeeMetrics,
|
|
19240
|
+
computeCorrelation,
|
|
18153
19241
|
computeBurnAccuracy,
|
|
19242
|
+
computeBeta,
|
|
19243
|
+
computeBasketSignals,
|
|
18154
19244
|
calculatePriceFromRange,
|
|
18155
19245
|
buildVoteLockWithDelegateCalldata,
|
|
18156
19246
|
buildVoteLockCalldata,
|
|
@@ -18190,8 +19280,15 @@ export {
|
|
|
18190
19280
|
YIELD_SUBGRAPH_URLS,
|
|
18191
19281
|
VOTE_LOCK_ADDRESS,
|
|
18192
19282
|
VOLATILITY_TO_PRICE_ERROR,
|
|
19283
|
+
VAR_95_HIGH,
|
|
18193
19284
|
V5_SPELL_ADDRESS,
|
|
18194
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,
|
|
18195
19292
|
SUPPORTED_CHAINS,
|
|
18196
19293
|
SUBGRAPH_URLS,
|
|
18197
19294
|
STALE_PRICE_THRESHOLD_S,
|
|
@@ -18204,11 +19301,17 @@ export {
|
|
|
18204
19301
|
PROPOSAL_STATE_MAP,
|
|
18205
19302
|
PROPOSAL_STATES,
|
|
18206
19303
|
PRICE_CONTROL,
|
|
19304
|
+
MINT_FEE_HIGH,
|
|
19305
|
+
HHI_CONCENTRATED,
|
|
18207
19306
|
GOVERNANCE_SPELL_ADDRESS,
|
|
18208
19307
|
GOVERNANCE_DEPLOYER_ADDRESS,
|
|
18209
19308
|
FOLIO_ROLES,
|
|
19309
|
+
FEE_VERY_HIGH_ANNUAL,
|
|
19310
|
+
FEE_HIGH_ANNUAL,
|
|
18210
19311
|
FACADE_READ_ADDRESS,
|
|
18211
19312
|
ERC20_META_ABI,
|
|
19313
|
+
EFFECTIVE_N_LOW,
|
|
19314
|
+
DRAWDOWN_HIGH,
|
|
18212
19315
|
DEPLOYER_ADDRESS,
|
|
18213
19316
|
DEFAULT_TVL_FEE,
|
|
18214
19317
|
DEFAULT_TRADING_GOV_PARAMS,
|
|
@@ -18223,5 +19326,8 @@ export {
|
|
|
18223
19326
|
CHAINLINK_RSR_USD,
|
|
18224
19327
|
CHAINLINK_DECIMALS,
|
|
18225
19328
|
CHAINLINK_BTC_USD,
|
|
19329
|
+
BETA_LOW,
|
|
19330
|
+
BETA_HIGH,
|
|
19331
|
+
BACKING_LOW,
|
|
18226
19332
|
AUCTION_LAUNCHER_WINDOW
|
|
18227
19333
|
};
|