Sub-Adapters 11

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)

Aave - Version 3 - Harmony (aave-v3-harmony-proto)

Adapter Code

Check the entire code written for the Adapter.

Source code

Showing TS source.
1export const name = 'Aave Fees';
2export const version = '0.3.7';
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
28type V3Reserve = {
29  lifetimeFlashLoanLPPremium : string
30  lifetimeFlashLoanProtocolPremium: string
31  lifetimePortalLPFee: string
32  lifetimePortalProtocolFee: string
33  // in v3 lifetimeReserveFactorAccrued contains the claimed amount and accruedToTreasury the currently claimable
34  // for gas saving it's not automatically transfered to treasury any more
35  lifetimeReserveFactorAccrued: string
36  accruedToTreasury: string
37  lifetimeDepositorsInterestEarned: string
38  priceInUsd: string
39  reserve: {
40    decimals: number
41    symbol: string
42  }
43}
44
45const SUBGRAPHS = {
46  V1: 'aave/protocol-multy-raw',
47  V2: 'aave/protocol-v2',
48  POLYGON: 'aave/aave-v2-matic',
49  POLYGON_V3: 'aave/protocol-v3-polygon',
50  AVALANCHE: 'aave/protocol-v2-avalanche',
51  AVALANCHE_V3: 'aave/protocol-v3-avalanche',
52  ARBITRUM_V3: 'aave/protocol-v3-arbitrum',
53  OPTIMISM_V3: 'aave/protocol-v3-optimism',
54  FANTOM_V3: 'aave/protocol-v3-fantom',
55  HARMONY_V3: 'aave/protocol-v3-harmony'
56}
57
58const POOL_IDS = {
59  V1: '0x24a42fd28c976a61df5d00d0599c34c4f90748c8',
60  V2: '0xb53c1a33016b2dc2ff3653530bff1848a515c8c5',
61  V2_AMM: '0xacc030ef66f9dfeae9cbb0cd1b25654b82cfa8d5',
62  V2_POLYGON: '0xd05e3e715d945b59290df0ae8ef85c1bdb684744',
63  V2_AVALANCHE: '0xb6a86025f0fe1862b372cb0ca18ce3ede02a318f',
64  // v3 uses the same address on all networks
65  V3: '0xa97684ead0e402dc232d5a977953df7ecbab3cdb'
66}
67
68function expectNextDayExists(reserves: {nextDay: []}[]) {
69  if(!reserves.some(reserve => reserve.nextDay?.length !== 0)){
70    throw new Error('day might not be finished yet')
71  }
72}
73
74const ONE_DAY = 24 * 60 * 60;
75
76export function setup(sdk: Context) {
77  async function getV1ReservesSnapshot(poolId: string, timestamp: number) {
78    const query = `{
79      reserves(where: { pool: "${poolId}" }) {
80        id
81        paramsHistory(
82          where: { timestamp_lte: ${timestamp}, timestamp_gte: ${timestamp - ONE_DAY} },
83          orderBy: "timestamp",
84          orderDirection: "desc",
85          first: 1
86        ) {
87          id
88          priceInUsd
89          reserve {
90            decimals
91            symbol
92          }
93          lifetimeFlashloanDepositorsFee
94          lifetimeFlashloanProtocolFee
95          lifetimeOriginationFee
96          lifetimeDepositorsInterestEarned
97        }
98        nextDay: paramsHistory(
99          where: { timestamp_gte: ${timestamp}, timestamp_lte: ${timestamp + ONE_DAY} },
100          first: 1
101        ) {
102          id
103        }
104      }
105    }`;
106
107    const result = await sdk.graph.query(SUBGRAPHS.V1, query)
108    expectNextDayExists(result.reserves)
109    const reserves = result.reserves
110      .map((r: any) => r.paramsHistory[0])
111      .filter((r: any) => r)
112
113    return reserves
114  }
115
116  function calculateV1Fees(startReserves: V1Reserve[], endReserves: V1Reserve[]) {
117    return endReserves.reduce((acc: number, reserve: V1Reserve) => {
118      const startReserve = startReserves
119        .find((r: any) => r.reserve.symbol === reserve.reserve.symbol)
120
121      if (!startReserve) {
122        return acc;
123      }
124
125      const priceInUsd = parseFloat(reserve.priceInUsd);
126
127      const depositorInterest = parseFloat(reserve.lifetimeDepositorsInterestEarned)
128        - parseFloat(startReserve.lifetimeDepositorsInterestEarned);
129      const depositorInterestUSD = depositorInterest * priceInUsd / (10 ** reserve.reserve.decimals);
130
131      const originationFees = parseFloat(reserve.lifetimeOriginationFee)
132        - parseFloat(startReserve.lifetimeOriginationFee);
133      const originationFeesUSD = originationFees * priceInUsd / (10 ** reserve.reserve.decimals);
134
135      const flashloanDepositorsFees = parseFloat(reserve.lifetimeFlashloanDepositorsFee)
136        - parseFloat(startReserve.lifetimeFlashloanDepositorsFee);
137      const flashloanDepositorsFeesUSD = flashloanDepositorsFees * priceInUsd / (10 ** reserve.reserve.decimals);
138
139      const flashloanProtocolFees = parseFloat(reserve.lifetimeFlashloanProtocolFee)
140        - parseFloat(startReserve.lifetimeFlashloanProtocolFee);
141      const flashloanProtocolFeesUSD = flashloanProtocolFees * priceInUsd / (10 ** reserve.reserve.decimals);
142
143      return acc
144        + depositorInterestUSD
145        + originationFeesUSD
146        + flashloanProtocolFeesUSD
147        + flashloanDepositorsFeesUSD;
148    }, 0);
149  }
150
151  const getV1Fees = async (date: string): Promise<number> => {
152    const poolId = POOL_IDS.V1;
153    const startTimestamp = sdk.date.dateToTimestamp(date);
154    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
155
156    const startReserves = await getV1ReservesSnapshot(poolId, startTimestamp);
157    const endReserves = await getV1ReservesSnapshot(poolId, nextDayTimestamp);
158
159    return calculateV1Fees(startReserves, endReserves);
160  }
161
162  ////
163  // V2 deployments
164  ////
165
166  async function getV2ReservesSnapshot(poolId: string, timestamp: number, subgraph: string) {
167    const query = `{
168      reserves(where: { pool: "${poolId}" }) {
169        id
170        paramsHistory(
171          where: { timestamp_lte: ${timestamp}, timestamp_gte: ${timestamp - ONE_DAY} },
172          orderBy: "timestamp",
173          orderDirection: "desc",
174          first: 1
175        ) {
176          id
177          priceInEth
178          priceInUsd
179          reserve {
180            decimals
181            symbol
182          }
183          lifetimeFlashLoanPremium
184          lifetimeReserveFactorAccrued
185          lifetimeDepositorsInterestEarned
186        }
187        nextDay: paramsHistory(
188          where: { timestamp_gte: ${timestamp}, timestamp_lte: ${timestamp + ONE_DAY} },
189          first: 1
190        ) {
191          id
192        }
193      }
194    }`;
195
196    const result = await sdk.graph.query(subgraph, query)
197    expectNextDayExists(result.reserves)
198    const reserves = result.reserves
199      .map((r: any) => r.paramsHistory[0])
200      .filter((r: any) => r)
201
202    return reserves
203  }
204
205  function calculateV2Fees(startReserves: V2Reserve[], endReserves: V2Reserve[], usdPriceFeed?: boolean) {
206    return endReserves.reduce((acc: number, reserve: V2Reserve) => {
207      const startReserve = startReserves
208        .find((r: any) => r.reserve.symbol === reserve.reserve.symbol)
209
210      if (!startReserve) {
211        return acc;
212      }
213
214      const priceInUsd = usdPriceFeed
215        ? parseFloat(reserve.priceInUsd) / (10 ** 8)
216        : parseFloat(reserve.priceInUsd)
217
218      const depositorInterest = parseFloat(reserve.lifetimeDepositorsInterestEarned)
219        - (parseFloat(startReserve?.lifetimeDepositorsInterestEarned) || 0);
220      const depositorInterestUSD = depositorInterest * priceInUsd / (10 ** reserve.reserve.decimals);
221
222      const flashloanPremium = parseFloat(reserve.lifetimeFlashLoanPremium)
223        - (parseFloat(startReserve?.lifetimeFlashLoanPremium) || 0);
224      const flashloanPremiumUSD = flashloanPremium * priceInUsd / (10 ** reserve.reserve.decimals);
225
226      const reserveFactor = parseFloat(reserve.lifetimeReserveFactorAccrued)
227        - (parseFloat(startReserve.lifetimeReserveFactorAccrued) || 0);
228      const reserveFactorUSD = reserveFactor * priceInUsd / (10 ** reserve.reserve.decimals);
229
230      return acc
231        + depositorInterestUSD
232        + flashloanPremiumUSD
233        + reserveFactorUSD;
234    }, 0);
235  }
236
237  const getV2Fees = (
238    poolId: string,
239    subgraph: string,
240    usdPriceFeed?: boolean
241  ) => async (date: string): Promise<number> => {
242    const startTimestamp = sdk.date.dateToTimestamp(date);
243    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
244
245    const startReserves = await getV2ReservesSnapshot(poolId, startTimestamp, subgraph);
246    const endReserves = await getV2ReservesSnapshot(poolId, nextDayTimestamp, subgraph);
247
248    return calculateV2Fees(startReserves, endReserves, usdPriceFeed);
249  }
250
251  async function getV3ReservesSnapshot(poolId: string, timestamp: number, subgraph: string) {
252    const query = `{
253      reserves(where: { pool: "${poolId}" }) {
254        id
255        paramsHistory(
256          where: { timestamp_lte: ${timestamp}, timestamp_gte: ${timestamp - ONE_DAY} },
257          orderBy: "timestamp",
258          orderDirection: "desc",
259          first: 1
260        ) {
261          id
262          priceInEth
263          priceInUsd
264          reserve {
265            decimals
266            symbol
267          }
268          lifetimeFlashLoanLPPremium
269          lifetimeFlashLoanProtocolPremium
270          lifetimePortalLPFee
271          lifetimePortalProtocolFee
272          lifetimeReserveFactorAccrued
273          lifetimeDepositorsInterestEarned: lifetimeSuppliersInterestEarned
274          accruedToTreasury
275        }
276        nextDay: paramsHistory(
277          where: { timestamp_gte: ${timestamp}, timestamp_lte: ${timestamp + ONE_DAY} },
278          first: 1
279        ) {
280          id
281        }
282      }
283    }`;
284
285    const result = await sdk.graph.query(subgraph, query)
286    expectNextDayExists(result.reserves)
287    const reserves = result.reserves
288      .map((r: any) => r.paramsHistory[0])
289      .filter((r: any) => r)
290
291    return reserves
292  }
293
294  function calculateV3FeeBreakdown(startReserves: V3Reserve[], endReserves: V3Reserve[], usdPriceFeed?: boolean) {
295    return endReserves.reduce((acc, reserve: V3Reserve) => {
296      const startReserve = startReserves
297        .find((r: any) => r.reserve.symbol === reserve.reserve.symbol)
298
299      if (!startReserve) {
300        return acc;
301      }
302
303      const priceInUsd = usdPriceFeed
304        ? parseFloat(reserve.priceInUsd) / (10 ** 8)
305        : parseFloat(reserve.priceInUsd)
306
307      const depositorInterest = parseFloat(reserve.lifetimeDepositorsInterestEarned)
308        - parseFloat(startReserve?.lifetimeDepositorsInterestEarned);
309      const depositorInterestUSD = depositorInterest * priceInUsd / (10 ** reserve.reserve.decimals);
310
311      const flashloanLPPremium = parseFloat(reserve.lifetimeFlashLoanLPPremium)
312        - parseFloat(startReserve.lifetimeFlashLoanLPPremium);
313      const flashloanLPPremiumUSD = flashloanLPPremium * priceInUsd / (10 ** reserve.reserve.decimals);
314
315      const flashloanProtocolPremium = parseFloat(reserve.lifetimeFlashLoanProtocolPremium)
316        - parseFloat(startReserve.lifetimeFlashLoanProtocolPremium);
317      const flashloanProtocolPremiumUSD = flashloanProtocolPremium * priceInUsd / (10 ** reserve.reserve.decimals);
318
319      const portalLPFee = parseFloat(reserve.lifetimePortalLPFee)
320        - parseFloat(startReserve?.lifetimePortalLPFee);
321      const portalLPFeeUSD = portalLPFee * priceInUsd / (10 ** reserve.reserve.decimals);
322
323      const portalProtocolFee = parseFloat(reserve.lifetimePortalProtocolFee)
324        - parseFloat(startReserve?.lifetimePortalProtocolFee);
325      const portalProtocolFeeUSD = portalProtocolFee * priceInUsd / (10 ** reserve.reserve.decimals);
326
327      const treasuryIncome = parseFloat(reserve.lifetimeReserveFactorAccrued) - parseFloat(startReserve?.lifetimeReserveFactorAccrued);
328
329      const outstandingTreasuryIncome = parseFloat(reserve.accruedToTreasury) - parseFloat(startReserve?.accruedToTreasury);
330
331      const treasuryIncomeUSD = treasuryIncome * priceInUsd / (10 ** reserve.reserve.decimals);
332
333      const outstandingTreasuryIncomeUSD = outstandingTreasuryIncome * priceInUsd / (10 ** reserve.reserve.decimals);
334
335      acc.outstandingTreasuryIncomeUSD += outstandingTreasuryIncomeUSD;
336      acc.treasuryIncomeUSD += treasuryIncomeUSD;
337      acc.depositorInterestUSD += depositorInterestUSD;
338      acc.flashloanLPPremiumUSD += flashloanLPPremiumUSD;
339      acc.flashloanProtocolPremiumUSD += flashloanProtocolPremiumUSD;
340      acc.portalLPFeeUSD += portalLPFeeUSD;
341      acc.portalProtocolFeeUSD += portalProtocolFeeUSD;
342      return acc;
343    }, {
344      depositorInterestUSD: 0,
345      flashloanLPPremiumUSD: 0,
346      flashloanProtocolPremiumUSD: 0,
347      portalLPFeeUSD: 0,
348      portalProtocolFeeUSD: 0,
349      treasuryIncomeUSD: 0,
350      outstandingTreasuryIncomeUSD: 0
351    });
352  }
353
354  const getV3Fees = (
355    poolId: string,
356    subgraph: string,
357  ) => async (date: string): Promise<number> => {
358    const startTimestamp = sdk.date.dateToTimestamp(date);
359    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
360
361    const startReserves = await getV3ReservesSnapshot(poolId, startTimestamp, subgraph);
362    const endReserves = await getV3ReservesSnapshot(poolId, nextDayTimestamp, subgraph);
363
364    const breakdown = calculateV3FeeBreakdown(startReserves, endReserves, true);
365
366    return breakdown.depositorInterestUSD + breakdown.outstandingTreasuryIncomeUSD + breakdown.treasuryIncomeUSD;
367  }
368
369  const getV3FeeBreakdown = (
370     poolId: string,
371    subgraph: string,
372  ) => async (date: string): Promise<any> => {
373    const startTimestamp = sdk.date.dateToTimestamp(date);    
374    const nextDayTimestamp = sdk.date.dateToTimestamp(sdk.date.offsetDaysFormatted(date, 1));
375
376    const startReserves = await getV3ReservesSnapshot(poolId, startTimestamp, subgraph);
377    const endReserves = await getV3ReservesSnapshot(poolId, nextDayTimestamp, subgraph);
378
379    return calculateV3FeeBreakdown(startReserves, endReserves, true);
380  }
381
382  const metadata = {
383    name: 'Aave',
384    icon: sdk.ipfs.getDataURILoader('QmW4X8Q36jjPm8fzU21NzFKRxNzReQy4JnehKbRrgybFh6', 'image/svg+xml'),
385    category: 'lending',
386    description:
387      'Aave is an open source and non-custodial liquidity protocol for earning interest on deposits and borrowing assets.',
388    feeDescription:
389      'Fees are accrued from the dynamics of providing liquidity and borrowing, going to liquidity suppliers and the Aave DAO treasury.',
390    blockchain: 'Ethereum',
391    source: 'The Graph Protocol',
392    website: 'https://aave.com',
393    tokenTicker: 'AAVE',
394    tokenCoingecko: 'aave',
395    tokenLaunch: '2020-09-14', // TODO: add real token launch data
396    protocolLaunch: '2020-01-08',
397  };
398
399  sdk.registerBundle('aave', metadata);
400
401  sdk.register({
402    id: 'aave-v1',
403    bundle: 'aave',
404    queries: {
405      oneDayTotalFees: getV1Fees,
406    },
407    metadata: {
408      ...metadata,
409      subtitle: 'Version 1',
410      protocolLaunch: '2020-01-08',
411    },
412  });
413
414  sdk.register({
415    id: 'aave-v2',
416    bundle: 'aave',
417    queries: {
418      oneDayTotalFees: getV2Fees(POOL_IDS.V2, SUBGRAPHS.V2),
419    },
420    metadata: {
421      ...metadata,
422      subtitle: 'Version 2',
423      protocolLaunch: '2020-12-03',
424    },
425  });
426
427  sdk.register({
428    id: 'aave-v2-amm',
429    bundle: 'aave',
430    queries: {
431      oneDayTotalFees: getV2Fees(POOL_IDS.V2_AMM, SUBGRAPHS.V2),
432    },
433    metadata: {
434      ...metadata,
435      subtitle: 'Version 2 - AMM',
436      protocolLaunch: '2021-03-08',
437    },
438  });
439
440  sdk.register({
441    id: 'aave-v2-polygon-proto',
442    bundle: 'aave',
443    queries: {
444      oneDayTotalFees: getV2Fees(POOL_IDS.V2_POLYGON, SUBGRAPHS.POLYGON),
445    },
446    metadata: {
447      ...metadata,
448      subtitle: 'Version 2 - Polygon',
449      protocolLaunch: '2021-03-31',
450      blockchain: 'Polygon',
451    },
452  });
453
454  sdk.register({
455    id: 'aave-v3-polygon-proto',
456    bundle: 'aave',
457    queries: {
458      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.POLYGON_V3),
459      oneDayFeeBreakdown: getV3FeeBreakdown(POOL_IDS.V3, SUBGRAPHS.POLYGON_V3)
460    },
461    metadata: {
462      ...metadata,
463      subtitle: 'Version 3 - Polygon',
464      protocolLaunch: '2022-03-14',
465      blockchain: 'Polygon',
466    },
467  });
468
469  sdk.register({
470    id: 'aave-v2-avalanche-proto',
471    bundle: 'aave',
472    queries: {
473      oneDayTotalFees: getV2Fees(POOL_IDS.V2_AVALANCHE, SUBGRAPHS.AVALANCHE, true),
474    },
475    metadata: {
476      ...metadata,
477      subtitle: 'Version 2 - Avalanche',
478      protocolLaunch: '2021-10-04',
479      blockchain: 'Avalanche',
480    },
481  });
482
483  sdk.register({
484    id: 'aave-v3-avalanche-proto',
485    bundle: 'aave',
486    queries: {
487      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.AVALANCHE_V3),
488      oneDayFeeBreakdown: getV3FeeBreakdown(POOL_IDS.V3, SUBGRAPHS.AVALANCHE_V3)
489    },
490    metadata: {
491      ...metadata,
492      subtitle: 'Version 3 - Avalanche',
493      protocolLaunch: '2022-03-14',
494      blockchain: 'Avalanche',
495    },
496  });
497
498  sdk.register({
499    id: 'aave-v3-optimism-proto',
500    bundle: 'aave',
501    queries: {
502      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.OPTIMISM_V3),
503      oneDayFeeBreakdown: getV3FeeBreakdown(POOL_IDS.V3, SUBGRAPHS.OPTIMISM_V3)
504    },
505    metadata: {
506      ...metadata,
507      subtitle: 'Version 3 - Optimism',
508      protocolLaunch: '2022-03-14',
509      blockchain: 'Optimism',
510    },
511  });
512
513  sdk.register({
514    id: 'aave-v3-arbitrum-proto',
515    bundle: 'aave',
516    queries: {
517      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.ARBITRUM_V3),
518      oneDayFeeBreakdown: getV3FeeBreakdown(POOL_IDS.V3, SUBGRAPHS.ARBITRUM_V3)
519    },
520    metadata: {
521      ...metadata,
522      subtitle: 'Version 3 - Arbitrum',
523      protocolLaunch: '2022-03-14',
524      blockchain: 'Arbitrum One',
525    },
526  });
527
528  sdk.register({
529    id: 'aave-v3-fantom-proto',
530    bundle: 'aave',
531    queries: {
532      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.FANTOM_V3),
533      oneDayFeeBreakdown: getV3FeeBreakdown(POOL_IDS.V3, SUBGRAPHS.FANTOM_V3)
534    },
535    metadata: {
536      ...metadata,
537      subtitle: 'Version 3 - Fantom',
538      protocolLaunch: '2022-03-14',
539      blockchain: 'Fantom',
540    },
541  });
542
543  sdk.register({
544    id: 'aave-v3-harmony-proto',
545    bundle: 'aave',
546    queries: {
547      oneDayTotalFees: getV3Fees(POOL_IDS.V3, SUBGRAPHS.HARMONY_V3),
548      oneDayFeeBreakdown: getV3FeeBreakdown(POOL_IDS.V3, SUBGRAPHS.HARMONY_V3)
549    },
550    metadata: {
551      ...metadata,
552      subtitle: 'Version 3 - Harmony',
553      protocolLaunch: '2022-03-14',
554      blockchain: 'Harmony',
555    },
556  });
557}
558

It's something off?

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

Adapter Info

Version

0.3.7

License

MIT

IPFS CID

QmPYhn3amCEbNmfb1JKxiBmTXrcw3ZFx7WdGi9QXmdfPeJ

CID (source)

QmRJ9aFzq3NErmu4cTGSKbAKXFDhdHotkWUxfHJsmj8CRh

Collections

Author

mihal.eth