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.