|
| 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