Adapter

Aave Fees - Clone

Sub-Adapters 10

Preview and test each sub adapter.

Aave - Version 1 (aave-v1)

Aave - Version 2 (aave-v2)

Aave - Version 2 - AMM (aave-v2-amm)

Aave - Version 2 - Polygon (aave-v2-polygon-proto)

Aave - Version 3 - Polygon (aave-v3-polygon-proto)

Aave - Version 2 - Avalanche (aave-v2-avalanche-proto)

Aave - Version 3 - Avalanche (aave-v3-avalanche-proto)

Aave - Version 3 - Optimism (aave-v3-optimism-proto)

Aave - Version 3 - Arbitrum (aave-v3-arbitrum-proto)

Aave - Version 3 - Fantom (aave-v3-fantom-proto)

Adapter Code

Check the entire code written for the Adapter.

Source code

Showing TS source.
1export const name = 'Aave Fees - Clone';
2export const version = '0.2.1';
3export const license = 'MIT';
4
5type V1Reserve = {
6  lifetimeFlashloanDepositorsFee: string
7  lifetimeFlashloanProtocolFee: string
8  lifetimeOriginationFee: string
9  lifetimeDepositorsInterestEarned: string
10  priceInUsd: string
11  reserve: {
12    decimals: number
13    symbol: string
14  }
15}
16
17type V2Reserve = {
18  lifetimeFlashLoanPremium: string
19  lifetimeReserveFactorAccrued: string
20  lifetimeDepositorsInterestEarned: string
21  priceInUsd: string
22  reserve: {
23    decimals: number
24    symbol: string
25  }
26}
27
28const SUBGRAPHS = {
29  V1: 'aave/protocol-multy-raw',
30  V2: 'aave/protocol-v2',
31  POLYGON: 'aave/aave-v2-matic',
32  POLYGON_V3: 'aave/protocol-v3-polygon',
33  AVALANCHE: 'aave/protocol-v2-avalanche',
34  AVALANCHE_V3: 'aave/protocol-v3-avalanche',
35  ARBITRUM_V3: 'aave/protocol-v3-arbitrum',
36  OPTIMISM_V3: 'aave/protocol-v3-optimism',
37  FANTOM_V3: 'aave/protocol-v3-fantom',
38  // harmony is not yet supported
39}
40
41const POOL_IDS = {
42  V1: '0x24a42fd28c976a61df5d00d0599c34c4f90748c8',
43  V2: '0xb53c1a33016b2dc2ff3653530bff1848a515c8c5',
44  V2_AMM: '0xacc030ef66f9dfeae9cbb0cd1b25654b82cfa8d5',
45  V2_POLYGON: '0xd05e3e715d945b59290df0ae8ef85c1bdb684744',
46  V2_AVALANCHE: '0xb6a86025f0fe1862b372cb0ca18ce3ede02a318f',
47  // v3 uses the same address on all networks
48  V3: '0xa97684ead0e402dc232d5a977953df7ecbab3cdb'
49}
50
51function expectNextDayExists(reserves: {nextDay: []}[]) {
52  if(!reserves.some(reserve => reserve.nextDay?.length !== 0)){
53    throw new Error('day might not be finished yet')
54  }
55}
56
57export function setup(sdk: Context) {
58  async function getV1ReservesSnapshot(poolId: string, timestamp: number) {
59    const query = `{
60      reserves(where: { pool: "${poolId}" }) {
61        id
62        paramsHistory(where: { timestamp_lte: ${timestamp} }, orderBy: "timestamp", orderDirection: "desc", first: 1) {
63          id
64          priceInUsd
65          reserve {
66            decimals
67            symbol
68          }
69          lifetimeFlashloanDepositorsFee
70          lifetimeFlashloanProtocolFee
71          lifetimeOriginationFee
72          lifetimeDepositorsInterestEarned
73        }
74        nextDay: paramsHistory(where: { timestamp_gte: ${timestamp} }, first: 1) {
75          id
76        }
77      }
78    }`;
79
80    const result = await sdk.graph.query(SUBGRAPHS.V1, query)
81    expectNextDayExists(result.reserves)
82    const reserves = result.reserves
83      .map((r: any) => r.paramsHistory[0])
84      .filter((r: any) => r)
85
86    return reserves
87  }
88
89  function calculateV1Fees(startReserves: V1Reserve[], endReserves: V1Reserve[]) {
90    return endReserves.reduce((acc: number, reserve: V1Reserve) => {
91      const startReserve = startReserves
92        .find((r: any) => r.reserve.symbol === reserve.reserve.symbol)
93
94      if (!startReserve) {
95        return 0;
96      }
97
98      const priceInUsd = parseFloat(reserve.priceInUsd);
99
100      const depositorInterest = parseFloat(reserve.lifetimeDepositorsInterestEarned)
101        - (parseFloat(startReserve?.lifetimeDepositorsInterestEarned) || 0);
102      const depositorInterestUSD = depositorInterest * priceInUsd / (10 ** reserve.reserve.decimals);
103
104      const originationFees = parseFloat(reserve.lifetimeOriginationFee)
105        - (parseFloat(startReserve?.lifetimeOriginationFee) || 0);
106      const originationFeesUSD = originationFees * priceInUsd / (10 ** reserve.reserve.decimals);
107
108      const flashloanDepositorsFees = parseFloat(reserve.lifetimeFlashloanDepositorsFee)
109        - (parseFloat(startReserve?.lifetimeFlashloanDepositorsFee) || 0);
110      const flashloanDepositorsFeesUSD = flashloanDepositorsFees * priceInUsd / (10 ** reserve.reserve.decimals);
111
112      const flashloanProtocolFees = parseFloat(reserve.lifetimeFlashloanProtocolFee)
113        - (parseFloat(startReserve?.lifetimeFlashloanProtocolFee) || 0);
114      const flashloanProtocolFeesUSD = flashloanProtocolFees * priceInUsd / (10 ** reserve.reserve.decimals);
115
116      return acc
117        + depositorInterestUSD
118        + originationFeesUSD
119        + flashloanProtocolFeesUSD
120        + flashloanDepositorsFeesUSD;
121    }, 0);
122  }
123
124  const getV1Fees = async (date: string): Promise<number> => {
125    const poolId = POOL_IDS.V1;
126    const startTimestamp = sdk.date.dateToTimestamp(date);
127    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
128
129    const startReserves = await getV1ReservesSnapshot(poolId, startTimestamp);
130    const endReserves = await getV1ReservesSnapshot(poolId, nextDayTimestamp);
131
132    return calculateV1Fees(startReserves, endReserves);
133  }
134
135  ////
136  // V2 deployments
137  ////
138
139  async function getV2ReservesSnapshot(poolId: string, timestamp: number, subgraph: string) {
140    const query = `{
141      reserves(where: { pool: "${poolId}" }) {
142        id
143        paramsHistory(where: { timestamp_lte: ${timestamp} }, orderBy: "timestamp", orderDirection: "desc", first: 1) {
144          id
145          priceInEth
146          priceInUsd
147          reserve {
148            decimals
149            symbol
150          }
151          lifetimeFlashLoanPremium
152          lifetimeReserveFactorAccrued
153          lifetimeDepositorsInterestEarned
154        }
155        nextDay: paramsHistory(where: { timestamp_gte: ${timestamp} }, first: 1) {
156          id
157        }
158      }
159    }`;
160
161    const result = await sdk.graph.query(subgraph, query)
162    expectNextDayExists(result.reserves)
163    const reserves = result.reserves
164      .map((r: any) => r.paramsHistory[0])
165      .filter((r: any) => r)
166
167    return reserves
168  }
169
170  function calculateV2Fees(startReserves: V2Reserve[], endReserves: V2Reserve[], usdPriceFeed?: boolean) {
171    return endReserves.reduce((acc: number, reserve: V2Reserve) => {
172      const startReserve = startReserves
173        .find((r: any) => r.reserve.symbol === reserve.reserve.symbol)
174
175      if (!startReserve) {
176        return 0;
177      }
178
179      const priceInUsd = usdPriceFeed
180        ? parseFloat(reserve.priceInUsd) / (10 ** 8)
181        : parseFloat(reserve.priceInUsd)
182
183      const depositorInterest = parseFloat(reserve.lifetimeDepositorsInterestEarned)
184        - (parseFloat(startReserve?.lifetimeDepositorsInterestEarned) || 0);
185      const depositorInterestUSD = depositorInterest * priceInUsd / (10 ** reserve.reserve.decimals);
186
187      const flashloanPremium = parseFloat(reserve.lifetimeFlashLoanPremium)
188        - (parseFloat(startReserve?.lifetimeFlashLoanPremium) || 0);
189      const flashloanPremiumUSD = flashloanPremium * priceInUsd / (10 ** reserve.reserve.decimals);
190
191      const reserveFactor = parseFloat(reserve.lifetimeReserveFactorAccrued)
192        - (parseFloat(startReserve?.lifetimeReserveFactorAccrued) || 0);
193      const reserveFactorUSD = reserveFactor * priceInUsd / (10 ** reserve.reserve.decimals);
194
195      return acc
196        + depositorInterestUSD
197        + flashloanPremiumUSD
198        + reserveFactorUSD;
199    }, 0);
200  }
201
202  const getV2Fees = (
203    poolId: string,
204    subgraph: string,
205    usdPriceFeed?: boolean
206  ) => async (date: string): Promise<number> => {
207    const startTimestamp = sdk.date.dateToTimestamp(date);
208    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
209
210    const startReserves = await getV2ReservesSnapshot(poolId, startTimestamp, subgraph);
211    const endReserves = await getV2ReservesSnapshot(poolId, nextDayTimestamp, subgraph);
212
213    return calculateV2Fees(startReserves, endReserves, usdPriceFeed);
214  }
215
216  async function getV3ReservesSnapshot(poolId: string, timestamp: number, subgraph: string) {
217    const query = `{
218      reserves(where: { pool: "${poolId}" }) {
219        id
220        paramsHistory(where: { timestamp_lte: ${timestamp} }, orderBy: "timestamp", orderDirection: "desc", first: 1) {
221          id
222          priceInEth
223          priceInUsd
224          reserve {
225            decimals
226            symbol
227          }
228          lifetimeFlashLoanPremium
229          lifetimeReserveFactorAccrued
230          lifetimeDepositorsInterestEarned: lifetimeSuppliersInterestEarned
231        }
232      }
233    }`;
234
235    const result = await sdk.graph.query(subgraph, query)
236
237    const reserves = result.reserves
238      .map((r: any) => r.paramsHistory[0])
239      .filter((r: any) => r)
240
241    return reserves
242  }
243
244  const getV3Fees = (
245    poolId: string,
246    subgraph: string,
247  ) => async (date: string): Promise<number> => {
248    const startTimestamp = sdk.date.dateToTimestamp(date);
249    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
250
251    const startReserves = await getV3ReservesSnapshot(poolId, startTimestamp, subgraph);
252    const endReserves = await getV3ReservesSnapshot(poolId, nextDayTimestamp, subgraph);
253
254    return calculateV2Fees(startReserves, endReserves, true);
255  }
256
257  const metadata = {
258    name: 'Aave',
259    icon: sdk.ipfs.getDataURILoader('QmW4X8Q36jjPm8fzU21NzFKRxNzReQy4JnehKbRrgybFh6', 'image/svg+xml'),
260    category: 'lending',
261    description:
262      'Aave is an open source and non-custodial liquidity protocol for earning interest on deposits and borrowing assets.',
263    feeDescription:
264      'Fees are accrued from the dynamics of providing liquidity and borrowing, going to liquidity suppliers and the Aave DAO treasury.',
265    blockchain: 'Ethereum',
266    source: 'The Graph Protocol',
267    website: 'https://aave.com',
268    tokenTicker: 'AAVE',
269    tokenCoingecko: 'aave',
270    tokenLaunch: '2020-09-14', // TODO: add real token launch data
271    protocolLaunch: '2020-01-08',
272  };
273
274  sdk.registerBundle('aave', metadata);
275
276  sdk.register({
277    id: 'aave-v1',
278    bundle: 'aave',
279    queries: {
280      oneDayTotalFees: getV1Fees,
281    },
282    metadata: {
283      ...metadata,
284      subtitle: 'Version 1',
285      protocolLaunch: '2020-01-08',
286    },
287  });
288
289  sdk.register({
290    id: 'aave-v2',
291    bundle: 'aave',
292    queries: {
293      oneDayTotalFees: getV2Fees(POOL_IDS.V2, SUBGRAPHS.V2),
294    },
295    metadata: {
296      ...metadata,
297      subtitle: 'Version 2',
298      protocolLaunch: '2020-12-03',
299    },
300  });
301
302  sdk.register({
303    id: 'aave-v2-amm',
304    bundle: 'aave',
305    queries: {
306      oneDayTotalFees: getV2Fees(POOL_IDS.V2_AMM, SUBGRAPHS.V2),
307    },
308    metadata: {
309      ...metadata,
310      subtitle: 'Version 2 - AMM',
311      protocolLaunch: '2021-03-08',
312    },
313  });
314
315  sdk.register({
316    id: 'aave-v2-polygon-proto',
317    bundle: 'aave',
318    queries: {
319      oneDayTotalFees: getV2Fees(POOL_IDS.V2_POLYGON, SUBGRAPHS.POLYGON),
320    },
321    metadata: {
322      ...metadata,
323      subtitle: 'Version 2 - Polygon',
324      protocolLaunch: '2021-03-31',
325      blockchain: 'Polygon',
326    },
327  });
328
329  sdk.register({
330    id: 'aave-v3-polygon-proto',
331    bundle: 'aave',
332    queries: {
333      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.POLYGON_V3),
334    },
335    metadata: {
336      ...metadata,
337      subtitle: 'Version 3 - Polygon',
338      protocolLaunch: '2022-03-14',
339      blockchain: 'Polygon',
340    },
341  });
342
343  sdk.register({
344    id: 'aave-v2-avalanche-proto',
345    bundle: 'aave',
346    queries: {
347      oneDayTotalFees: getV2Fees(POOL_IDS.V2_AVALANCHE, SUBGRAPHS.AVALANCHE, true),
348    },
349    metadata: {
350      ...metadata,
351      subtitle: 'Version 2 - Avalanche',
352      protocolLaunch: '2021-10-04',
353      blockchain: 'Avalanche',
354    },
355  });
356
357  sdk.register({
358    id: 'aave-v3-avalanche-proto',
359    bundle: 'aave',
360    queries: {
361      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.AVALANCHE_V3),
362    },
363    metadata: {
364      ...metadata,
365      subtitle: 'Version 3 - Avalanche',
366      protocolLaunch: '2022-03-14',
367      blockchain: 'Avalanche',
368    },
369  });
370
371  sdk.register({
372    id: 'aave-v3-optimism-proto',
373    bundle: 'aave',
374    queries: {
375      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.OPTIMISM_V3),
376    },
377    metadata: {
378      ...metadata,
379      subtitle: 'Version 3 - Optimism',
380      protocolLaunch: '2022-03-14',
381      blockchain: 'Optimism',
382    },
383  });
384
385  sdk.register({
386    id: 'aave-v3-arbitrum-proto',
387    bundle: 'aave',
388    queries: {
389      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.ARBITRUM_V3),
390    },
391    metadata: {
392      ...metadata,
393      subtitle: 'Version 3 - Arbitrum',
394      protocolLaunch: '2022-03-14',
395      blockchain: 'Arbitrum',
396    },
397  });
398
399  sdk.register({
400    id: 'aave-v3-fantom-proto',
401    bundle: 'aave',
402    queries: {
403      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.FANTOM_V3),
404    },
405    metadata: {
406      ...metadata,
407      subtitle: 'Version 3 - Fantom',
408      protocolLaunch: '2022-03-14',
409      blockchain: 'Fantom',
410    },
411  });
412}
413

It's something off?

Report it to the discussion board on Discord, we will take care of it.

Adapter Info

Version

0.2.1

License

MIT

IPFS CID

QmTbeeQ4LWHMPfd57SHPYo4Cz1u8brmMdzjWz2PpRN2z1V

CID (source)

QmWZJeRvTCiwULmcqZzqf1a94Vz58ggTFBKBearwEPkYQ9

Collections

fees

Author

0x2F058034a88772C9334F764FB591a1f344cb8d5D