Skip to content

Commit e9ccde4

Browse files
Mstable v2 pr (#4467)
* Add fees and revenue for mstable v2 * update --------- Co-authored-by: pavel <[email protected]>
1 parent d6b4e7e commit e9ccde4

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

fees/mstable-v2/index.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { FetchOptions, SimpleAdapter } from "../../adapters/types";
2+
import { CHAIN } from "../../helpers/chains";
3+
import { GraphQLClient } from "graphql-request";
4+
import * as sdk from "@defillama/sdk";
5+
6+
const queryManagerFeeMinteds = `
7+
query managerFeeMinteds($manager: Bytes!, $startTimestamp: BigInt!, $endTimestamp: BigInt!, $first: Int!, $skip: Int!) {
8+
managerFeeMinteds(
9+
where: { manager: $manager, managerFee_not: 0, blockTimestamp_gte: $startTimestamp, blockTimestamp_lte: $endTimestamp },
10+
first: $first, skip: $skip, orderBy: blockTimestamp, orderDirection: desc
11+
) { managerFee, tokenPriceAtFeeMint, pool, manager, block }
12+
}`
13+
14+
const queryEntryFeeMinteds = `
15+
query entryFeeMinteds($manager: Bytes!, $startTimestamp: BigInt!, $endTimestamp: BigInt!, $first: Int!, $skip: Int!) {
16+
entryFeeMinteds(
17+
where: { managerAddress: $manager, time_gte: $startTimestamp, time_lte: $endTimestamp },
18+
first: $first, skip: $skip, orderBy: time, orderDirection: desc
19+
) { entryFeeAmount, tokenPrice }
20+
}`
21+
22+
const queryExitFeeMinteds = `
23+
query exitFeeMinteds($manager: Bytes!, $startTimestamp: BigInt!, $endTimestamp: BigInt!, $first: Int!, $skip: Int!) {
24+
exitFeeMinteds(
25+
where: { managerAddress: $manager, time_gte: $startTimestamp, time_lte: $endTimestamp },
26+
first: $first, skip: $skip, orderBy: time, orderDirection: desc
27+
) { exitFeeAmount, tokenPrice }
28+
}`
29+
30+
const CONFIG: any = {
31+
[CHAIN.ETHEREUM]: {
32+
endpoint: sdk.graph.modifyEndpoint("HSPZATdnDvYRNPBJm7eSrzkTeRZqhqYvy7c3Ngm9GCTL"),
33+
mstableManagerAddress: "0x3dd46846eed8D147841AE162C8425c08BD8E1b41",
34+
},
35+
};
36+
37+
const fetchHistoricalFees = async (chainId: string, query: string, dataField: string, startTimestamp: number, endTimestamp: number) => {
38+
const { endpoint, mstableManagerAddress } = CONFIG[chainId];
39+
40+
let allData: Array<any> = [];
41+
let skip = 0;
42+
const batchSize = 1000;
43+
44+
while (true) {
45+
try {
46+
const data = await new GraphQLClient(endpoint).request(query, {
47+
manager: mstableManagerAddress,
48+
startTimestamp: startTimestamp.toString(),
49+
endTimestamp: endTimestamp.toString(),
50+
first: batchSize,
51+
skip
52+
});
53+
54+
const entries = data[dataField];
55+
if (entries.length === 0) break;
56+
57+
allData = allData.concat(entries);
58+
skip += batchSize;
59+
60+
if (entries.length < batchSize) break;
61+
} catch (e: any) {
62+
throw new Error(`Error fetching data for chain ${chainId}: ${e.message}`);
63+
}
64+
}
65+
return allData;
66+
};
67+
68+
const calculateManagerFees = (dailyFees: any): number =>
69+
dailyFees.reduce((acc: number, dailyFeesDto: any) => {
70+
const managerFee = Number(dailyFeesDto.managerFee);
71+
const tokenPrice = Number(dailyFeesDto.tokenPriceAtFeeMint);
72+
const managerFeeFormatted = managerFee / 1e18;
73+
const tokenPriceFormatted = tokenPrice / 1e18;
74+
const managerFeeUsd = managerFeeFormatted * tokenPriceFormatted;
75+
return acc + managerFeeUsd;
76+
}, 0);
77+
78+
const calculateEntryFees = (data: any): number =>
79+
data.reduce((acc: number, item: any) => {
80+
const entryFee = Number(item.entryFeeAmount);
81+
const tokenPrice = Number(item.tokenPrice);
82+
const entryFeeFormatted = entryFee / 1e18;
83+
const tokenPriceFormatted = tokenPrice / 1e18;
84+
const result = entryFeeFormatted * tokenPriceFormatted;
85+
return acc + result;
86+
}, 0);
87+
88+
const calculateExitFees = (data: any): number =>
89+
data.reduce((acc: number, item: any) => {
90+
const exitFee = Number(item.exitFeeAmount);
91+
const tokenPrice = Number(item.tokenPrice);
92+
const exitFeeFormatted = exitFee / 1e18;
93+
const tokenPriceFormatted = tokenPrice / 1e18;
94+
const result = exitFeeFormatted * tokenPriceFormatted;
95+
return acc + result;
96+
}, 0);
97+
98+
const fetch = async (_1: any, _2: any, options: FetchOptions) => {
99+
const config = CONFIG[options.chain];
100+
if (!config) throw new Error(`Unsupported chain: ${options.chain}`);
101+
102+
const dailyManagerFeesEvents = await fetchHistoricalFees(options.chain, queryManagerFeeMinteds, 'managerFeeMinteds', options.startTimestamp, options.endTimestamp);
103+
const dailyEntryFeesEvents = await fetchHistoricalFees(options.chain, queryEntryFeeMinteds, 'entryFeeMinteds', options.startTimestamp, options.endTimestamp);
104+
const dailyExitFeesEvents = await fetchHistoricalFees(options.chain, queryExitFeeMinteds, 'exitFeeMinteds', options.startTimestamp, options.endTimestamp);
105+
106+
const managerFees = calculateManagerFees(dailyManagerFeesEvents);
107+
const entryFees = calculateEntryFees(dailyEntryFeesEvents);
108+
const exitFees = calculateExitFees(dailyExitFeesEvents);
109+
110+
const dailyFees = managerFees + entryFees + exitFees;
111+
112+
return {
113+
dailyFees,
114+
dailyRevenue: dailyFees,
115+
dailyProtocolRevenue: dailyFees,
116+
};
117+
}
118+
119+
const methodology = {
120+
Fees: 'All fees generated from mStable vaults.',
121+
Revenue: 'All revenue collected by the mStable protocol.',
122+
ProtocolRevenue: 'All revenue collected by the mStable protocol.',
123+
}
124+
125+
const adapter: SimpleAdapter = {
126+
fetch,
127+
methodology,
128+
chains: [CHAIN.ETHEREUM],
129+
start: '2025-08-12',
130+
}
131+
132+
export default adapter;

0 commit comments

Comments
 (0)