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.