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

It's something off?

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

Adapter Info

Version

0.3.0

License

MIT

IPFS CID

QmUWC6T8foZ7ekYNUwsa7txhXzV4V3xSmWiSvFiL3VgBup

CID (source)

QmcXb5sa4tQnrSpCDbRRkvkiLShraBSuDS6ccayiBQtHx6

Author

0x2F058034a88772C9334F764FB591a1f344cb8d5D