Sub-Adapters 12

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 3 (aave-v3)

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

It's something off?

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

Adapter Info

Version

0.4.1

License

MIT

IPFS CID

QmRdinPhLTZZUyx7agEwtHTCNfwmsKrvRzzUURfdweHKvW

CID (source)

QmYua1Xfj91W2TUm8pbaXoFsp3LcYZ6BjC8K3erF4Ac7xf

Collections

Author

0x2F058034a88772C9334F764FB591a1f344cb8d5D