Adapter

Curve Fees

Sub-Adapters 6

Preview and test each sub adapter.

Curve - Ethereum (curve-ethereum)

Curve - Arbitrum (curve-arbitrum)

Curve - Optimism (curve-optimism)

Curve - Polygon (curve-polygon)

Curve - Avalanche (curve-avalanche)

Curve - Fantom (curve-fantom)

Adapter Code

Check the entire code written for the Adapter.

Source code

Showing TS source.
1export const name = 'Curve Fees';
2export const version = '0.1.3';
3export const license = 'MIT';
4export const changelog = 'Bugfix avalanche aave pool has volume denominated in usd';
5
6interface NetInfo {
7  subgraph: string;
8  blockchain: string;
9  protocolLaunch: string;
10}
11
12// Pools reporting wrong volumes
13const exclude_pools = {
14  'fantom': ['fusdt'], 
15  'arbitrum': ['mim'], 
16}
17// Pools with no asset types
18const assetTypesFromPoolName = {
19    'aave': 'USD',
20    '3pool': 'USD',
21    '2pool': 'USD',
22    'ren': 'BTC',
23    'mim': 'USD',
24  }
25const FEES_TYPES = {
26  'protocol': 'PROTOCOL',
27  'total': 'TOTAL'
28}
29
30// https://api.thegraph.com/subgraphs/name/curvefi/curve and before that 'sistemico/curve', 
31const networks: { [network: string]: NetInfo } = {
32  ethereum: {
33    subgraph: 'curvefi/curve', 
34    blockchain: 'Ethereum',
35    protocolLaunch: '2020-01-01',
36  },
37  arbitrum: {
38    subgraph: 'dmihal/curve-arbitrum', 
39    blockchain: 'Arbitrum',
40    protocolLaunch: '2021-09-20', 
41  },
42  optimism: {
43    subgraph: 'dmihal/curve-optimism', 
44    blockchain: 'Optimism',
45    protocolLaunch: '2022-01-18', 
46  },
47  polygon: {
48    subgraph: 'dmihal/curve-polygon', 
49    blockchain: 'Polygon',
50    protocolLaunch: '2021-05-03', 
51  },
52  avalanche: {
53    subgraph: 'dmihal/curve-avalanche', 
54    blockchain: 'Avalanche',
55    protocolLaunch: '2021-10-06', 
56  },
57  fantom: {
58    subgraph: 'dmihal/curve-fantom', 
59    blockchain: 'Fantom',
60    protocolLaunch: '2021-05-09', 
61  },
62}
63
64export function setup(sdk: Context) {
65  const createFeeDataQuery = (subgraph: string, network: string, feesType: string) => async (date: string): Promise<number> => {
66    const startDate = date;
67    const endDate = sdk.date.offsetDaysFormatted(date, +1);
68    const oneDay = await createFeeRangeQuery(subgraph, network, feesType)(startDate, endDate);
69    return oneDay;
70  }
71
72const graphQuery = `query fees($timestamp_gte: Int!, $timestamp_lte: Int!) 
73  {
74    dailyVolumes (
75      orderBy: timestamp
76      orderDirection: desc
77      first: 1000
78      where: {
79        timestamp_gte: $timestamp_gte
80        timestamp_lt: $timestamp_lte
81      }
82    ) {
83      pool {
84        fee
85        adminFee
86        assetType
87        name
88      }
89      volume
90      timestamp
91    }
92  }
93  `;
94  const createFeeRangeQuery = 
95  (subgraph: string, network: string, feesType: string) => async (startDate: string, endDate: string): Promise<number> => {
96    const data = await sdk.graph.query(
97      subgraph,
98      graphQuery,
99      {
100        variables: {
101          timestamp_gte: sdk.date.dateToTimestamp(startDate),
102          timestamp_lte: sdk.date.dateToTimestamp(endDate),
103          network
104        },
105      }
106    );
107    const volumesLength = data.dailyVolumes.length;
108    if (volumesLength === 0) {
109      throw new Error(`No curve data found between ${startDate} and ${endDate} from ${subgraph}`);
110    }
111    // return volumesLength
112    // Convert symbol (returned by curve graph as type) to coingecko id
113    //const types = data.dailyVolumes.map(vol => vol.pool.assetType)
114    //  .filter((value, index, self) => self.indexOf(value) === index);
115    // USD ETH BTC LINK EUR
116    const get_coingecko_id = {
117      "USD": 'usd-coin',
118      "ETH": 'ethereum',
119      "BTC": 'bitcoin',
120      "LINK": 'chainlink',
121      "EUR": "stasis-eurs" 
122    };
123    const asset_type_price:any = {'null': 0};
124    await Promise.all(
125      Object.keys(get_coingecko_id).map(async (item) => {
126        asset_type_price[item] = parseFloat(
127          await sdk.coinGecko.getHistoricalPrice(get_coingecko_id[item], endDate)
128        );
129    }));
130    // sdk.log(asset_type_price)
131    const feesPerPool = data.dailyVolumes.map((vol: any):number => {
132      const feeMult = (feesType == FEES_TYPES.protocol)? parseFloat(vol.pool.adminFee) : 1;
133
134      // Handle particular cases 
135      // Pools with wrong volumes 
136      if (exclude_pools[network] && exclude_pools[network].indexOf(vol.pool.name) > -1) {
137        return 0; // returns wrong volume: fusdt on fantom or mim on arbi
138      } 
139      // And pools with no asset type
140      if (!vol.pool.assetType) { 
141        vol.pool.assetType = assetTypesFromPoolName[vol.pool.name]; 
142      }
143
144      // Compute fees as volume * fee * feeMult * asset_price_usd
145      // sdk.log('vol', vol)
146      return parseFloat(vol.volume) * parseFloat(vol.pool.fee)
147         * asset_type_price[vol.pool.assetType] * feeMult;
148    })
149    sdk.log('feesPerPool', feesPerPool)
150    
151    const feesDuringRange = feesPerPool.reduce((acc: number, curr: number) => acc + curr, 0.);
152    return feesDuringRange;
153  }
154
155  const metadata = {
156    category: 'dex',
157    name: 'Curve',
158    description: 'Curve is a community-owned permissionless, decentralized exchange',
159    feeDescription: 'Trading fees are paid by traders to liquidity providers and pool admins',
160    source: 'The Graph Protocol',
161    tokenTicker: 'CRV',
162    tokenCoingecko: 'curve-dao-token',
163    website: 'https://curve.fi/',
164    icon: sdk.ipfs.getDataURILoader('QmeGCLQAfUANUB79AJ6hMnY7DeBdX3WssantuZDBXNbAF8', 'image/png'),
165    protocolLaunch: '2020-01-01',
166  };
167
168  sdk.registerBundle('curve', metadata);
169
170  Object.entries(networks).map(([network, { subgraph, blockchain, protocolLaunch }]: [string, NetInfo]) => {
171    sdk.register({
172      id: `curve-${network}`,
173      bundle: 'curve',
174      queries: {
175        oneDayTotalFees: createFeeDataQuery(subgraph, network, FEES_TYPES.total),
176        oneDayProtocolFees: createFeeDataQuery(subgraph, network, FEES_TYPES.protocol),
177      },
178      metadata: {
179        ...metadata,
180        subtitle: blockchain,
181        blockchain,
182        protocolLaunch,
183      },
184    })
185  })
186}

It's something off?

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

Adapter Info

Version

0.1.3

License

MIT

IPFS CID

QmdyGqimDtn1uUkYZ9i9vZYB17zZ1VTQTNwr9yDniWuotg

CID (source)

QmaexW1xJBh619uC85waeaWHxq713BwVryiDVXHReRVGMb

Collections

fees

Author

jochemla.sismo.eth