diff --git a/aggregator-derivatives/bitoro/index.ts b/aggregator-derivatives/bitoro/index.ts index eb2e5c0f5a..94f42515b4 100644 --- a/aggregator-derivatives/bitoro/index.ts +++ b/aggregator-derivatives/bitoro/index.ts @@ -1,5 +1,5 @@ import fetchURL from "../../utils/fetchURL"; -import { FetchResultV2 } from "../../adapters/types"; +import { FetchResult, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const BitoroX_BASE_URL = "https://min-api.bitoro.network/btr/stats/global"; @@ -15,29 +15,31 @@ const getBitoroProUrl = (startTime: number, endTime: number): string => { return `${BitoroPro_BASE_URL}?start=${startTime}&end=${endTime}`; } -const fetchBitoroX = async (options: any): Promise => { - const { fromTimestamp, toTimestamp } = options; - const dailyVolume = await fetchURL(getBitoroXUrl(fromTimestamp, toTimestamp)); - const totalVolume = await fetchURL(getBitoroXUrl(startTimestamp_bitoro_x, toTimestamp)); +const fetchBitoroX = async (_:any, _b:any ,options: any): Promise => { + const { endTimestamp, startTimestamp } = options; + const dailyVolume = await fetchURL(getBitoroXUrl(startTimestamp, endTimestamp)); + const totalVolume = await fetchURL(getBitoroXUrl(startTimestamp_bitoro_x, endTimestamp)); return { + timestamp: startTimestamp, dailyVolume: dailyVolume.volume || 0, totalVolume: totalVolume.volume || 0, }; }; -const fetchBitoroPro = async (options: any): Promise => { +const fetchBitoroPro = async (_:any, _b:any ,options: any): Promise => { const { fromTimestamp, toTimestamp } = options; const dailyVolume = await fetchURL(getBitoroProUrl(fromTimestamp, toTimestamp)); const totalVolume = await fetchURL(getBitoroProUrl(startTimestamp_bitoro_pro, toTimestamp)); return { + timestamp: fromTimestamp, dailyVolume: dailyVolume.volume || 0, totalVolume: totalVolume.volume || 0, }; }; -export default { +const adapter: SimpleAdapter = { adapter: { [CHAIN.ARBITRUM]: { fetch: fetchBitoroX, @@ -47,6 +49,7 @@ export default { fetch: fetchBitoroPro, start: startTimestamp_bitoro_pro } - }, - version: 2 + } } + +export default adapter; diff --git a/aggregator-derivatives/perpie/index.ts b/aggregator-derivatives/perpie/index.ts index e14a3578f1..94668c8774 100644 --- a/aggregator-derivatives/perpie/index.ts +++ b/aggregator-derivatives/perpie/index.ts @@ -1,5 +1,6 @@ import { BreakdownAdapter, + Fetch, FetchOptions, FetchResult, FetchResultV2, @@ -45,14 +46,13 @@ const fetchVolumeAndFees: (chain: string) => FetchV2 = }; }; -const fetchAll: (chain: string) => FetchV2 = +const fetchAll: (chain: string) => Fetch = (chain: string) => - async (options: FetchOptions): Promise => { + async (_a: any, _t: any ,options: FetchOptions): Promise => { const volumeAndFees = await fetchVolumeAndFees(chain)(options); - return { ...volumeAndFees } as FetchResultV2; + return { ...volumeAndFees } as FetchResult; }; const adapter: BreakdownAdapter = { - version: 2, isExpensiveAdapter: true, breakdown: { derivatives: { diff --git a/aggregator-derivatives/vooi/index.ts b/aggregator-derivatives/vooi/index.ts index ac81af4297..ae4a8e5cb6 100644 --- a/aggregator-derivatives/vooi/index.ts +++ b/aggregator-derivatives/vooi/index.ts @@ -1,5 +1,5 @@ import fetchURL from "../../utils/fetchURL"; -import { FetchResult, FetchResultV2, SimpleAdapter } from "../../adapters/types"; +import { FetchResult } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const URL = "https://defilama-stats.vooi.workers.dev/"; @@ -11,12 +11,12 @@ interface IAPIResponse { dailyVolume: string; totalVolume: string; } -const fetch = async (options: any): Promise => { - let timestamp = options.toTimestamp +const fetch = async (timestamp: number): Promise => { const { dailyVolume, totalVolume }: IAPIResponse = ( (await fetchURL(`${URL}${endpoint}?ts=${timestamp}`)).data ); return { + timestamp, dailyVolume, totalVolume, }; @@ -29,5 +29,5 @@ export default { start: startTimestamp }, }, - version: 2 + // version: 2 // data accepts only one input to timestamp } diff --git a/aggregators/7k-aggregator/index.ts b/aggregators/7k-aggregator/index.ts new file mode 100644 index 0000000000..cc4447938f --- /dev/null +++ b/aggregators/7k-aggregator/index.ts @@ -0,0 +1,24 @@ +import fetchURL from '../../utils/fetchURL'; +import { FetchV2, SimpleAdapter } from '../../adapters/types'; +import { CHAIN } from '../../helpers/chains'; + +const URL = 'https://statistic.7k.ag'; + +const fetch: FetchV2 = async ({ fromTimestamp, toTimestamp }) => { + const dailyVolume = await fetchURL( + `${URL}/volume-with-ts?from_timestamp=${fromTimestamp}&to_timestamp=${toTimestamp}`, + ); + return { dailyVolume }; +}; + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.SUI]: { + fetch, + start: 1719563120, + }, + }, +}; + +export default adapter; diff --git a/aggregators/akka/index.ts b/aggregators/akka/index.ts new file mode 100644 index 0000000000..528cc4181c --- /dev/null +++ b/aggregators/akka/index.ts @@ -0,0 +1,35 @@ +import fetchURL from "../../utils/fetchURL" +import { FetchResult, SimpleAdapter } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; + +const URL = 'https://routerv2.akka.finance'; +const endpoint = '/v2/1116/statistics/dappradar'; +const startTimestamp = 1717200000;// 6/1/2024 + +interface IAPIResponse { + dailyVolume: string; + totalVolume: string; +} + +const fetch = async (timestamp: number): Promise => { + const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)); + const { dailyVolume, totalVolume }: IAPIResponse = (await fetchURL(`${URL}${endpoint}`)); + return { + dailyVolume, + totalVolume, + timestamp: dayTimestamp, + }; +} + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.CORE]: { + fetch, + start: startTimestamp, + }, + }, +}; + +export default adapter; diff --git a/aggregators/kanalabs/index.ts b/aggregators/kanalabs/index.ts index fc31fc0fe4..169079264d 100644 --- a/aggregators/kanalabs/index.ts +++ b/aggregators/kanalabs/index.ts @@ -10,14 +10,15 @@ export enum KanaChainID { "solana" = 1, "aptos" = 2, "polygon" = 3, - "ethereum" = 4, - "bsc" = 5, - "klaytn" = 6, - "sui" = 8, - "Arbitrum" = 9, + "bsc" = 4, + "sui" = 5, + "ethereum" = 6, + "base" = 7, + "klaytn" = 8, + "zkSync" = 9, "Avalanche" = 10, - "zkSync" = 11, - "base" = 12, + "Arbitrum" = 11, + "optimistic" = 12, } const fetch = (chain: KanaChainID) => async (timestamp: number) => { diff --git a/aggregators/magpie/index.ts b/aggregators/magpie/index.ts index fa409d15f5..a633797290 100644 --- a/aggregators/magpie/index.ts +++ b/aggregators/magpie/index.ts @@ -58,6 +58,41 @@ const fetch = async (timestamp: number, _: ChainBlocks, {chain}: FetchOptions): runAtCurrTime: true, start: 1662595200, }, + [CHAIN.SCROLL]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, + [CHAIN.MANTA]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, + [CHAIN.TAIKO]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, + [CHAIN.POLYGON_ZKEVM]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, + [CHAIN.BLAST]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, + [CHAIN.METIS]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, + [CHAIN.FANTOM]: { + fetch: fetch, + runAtCurrTime: true, + start: 1662595200, + }, }, isExpensiveAdapter: true, }; diff --git a/aggregators/swapgpt/index.ts b/aggregators/swapgpt/index.ts index 9bbb9f594c..60cccdccb4 100644 --- a/aggregators/swapgpt/index.ts +++ b/aggregators/swapgpt/index.ts @@ -1,42 +1,37 @@ -import fetchURL from "../../utils/fetchURL" -import { SimpleAdapter } from "../../adapters/types"; +import { httpGet } from "../../utils/fetchURL"; +import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; -import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; - - interface IVolumeall { - grouptimestamp: string; - amount: string; + totalVolumeUSD: string; + dailyVolumeUSD: Array<{ + startDateTime: string; + dailyVolumeUSD: string; + }> } -const baseUrl = "https://stats.panora.exchange"; -const endpoint = "stats/getDefiLamaStats"; - - -const fetch = async (timestamp: number) => { - const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) - const historicalVolume: IVolumeall[] = (await fetchURL(`${baseUrl}/${endpoint}`))?.volumeInUsd - const totalVolume = historicalVolume - .filter(volItem => (new Date(volItem.grouptimestamp).getTime() / 1000) <= dayTimestamp) - .reduce((acc, { amount }) => acc + Number(amount), 0) - - const dailyVolume = historicalVolume - .find(dayItem => (new Date(dayItem.grouptimestamp).getTime() / 1000) === dayTimestamp)?.amount +const baseUrl = "https://stats-api.panora.exchange"; +const endpoint = "getDefiLlamaStats"; +const fetch = async (options: FetchOptions) => { + const timestamp = options.startOfDay + const dateStr = new Date(timestamp * 1000).toISOString().split('T')[0]; + const response: IVolumeall = (await httpGet(`${baseUrl}/${endpoint}`)); + const totalVolume = response.totalVolumeUSD; + const dailyVolume = response.dailyVolumeUSD.find((d) => d.startDateTime.split('T')[0] === dateStr); return { - totalVolume: `${totalVolume}`, - dailyVolume: dailyVolume ? `${dailyVolume}` : undefined, - timestamp: dayTimestamp, - }; + dailyVolume: dailyVolume?.dailyVolumeUSD, + totalVolume + } }; const adapter: SimpleAdapter = { + version: 2, adapter: { [CHAIN.APTOS]: { - fetch: fetch, - start: (new Date('2023-11-28T00:00:00.000Z').getTime() / 1000), - } + fetch, + start: 1701129600, + }, }, }; diff --git a/dexs/aerodrome-slipstream/index.ts b/dexs/aerodrome-slipstream/index.ts index 3e69a75809..5708c90830 100644 --- a/dexs/aerodrome-slipstream/index.ts +++ b/dexs/aerodrome-slipstream/index.ts @@ -30,32 +30,50 @@ const fetch = async (timestamp: number, _: any, { api, getLogs, createBalances, let unfinished = true; while (unfinished) { - const forSwaps: IForSwap[] = (await api.call({ + const forSwapsUnfiltered: IForSwap[] = (await api.call({ target: gurar, params: [chunkSize, currentOffset], abi: abis.forSwaps, chain: CHAIN.BASE, - })).filter(t => Number(t.type) > 0).map((e: any) => { + })); + + const forSwaps: IForSwap[] = forSwapsUnfiltered.filter(t => Number(t.type) > 0).map((e: any) => { return { lp: e.lp, token0: e.token0, token1: e.token1, pool_fee: e.pool_fee, } - }) + }); - unfinished = forSwaps.length !== 0; + unfinished = forSwapsUnfiltered.length !== 0; currentOffset += chunkSize; allForSwaps.push(...forSwaps); } const targets = allForSwaps.map((forSwap: IForSwap) => forSwap.lp) - const logs: ILog[][] = await getLogs({ - targets, - eventAbi: event_swap, - flatten: false, - }) + let logs: ILog[][] = []; + const targetChunkSize = 5; + let currentTargetOffset = 0; + unfinished = true; + + while (unfinished) { + let endOffset = currentTargetOffset + targetChunkSize; + if (endOffset >= targets.length) { + unfinished = false; + endOffset = targets.length; + } + + let currentLogs: ILog[][] = await getLogs({ + targets: targets.slice(currentTargetOffset, endOffset), + eventAbi: event_swap, + flatten: false, + }) + + logs.push(...currentLogs); + currentTargetOffset += targetChunkSize; + } logs.forEach((logs: ILog[], idx: number) => { const { token1, pool_fee } = allForSwaps[idx] diff --git a/dexs/apestore/index.ts b/dexs/apestore/index.ts index 2d8f84098f..3e9e02dbbc 100644 --- a/dexs/apestore/index.ts +++ b/dexs/apestore/index.ts @@ -16,7 +16,7 @@ const adapter: Adapter = { fetch: async (options: FetchOptions): Promise => { const volumeData: VolumeInfo = await httpPost(URL, { date: options.startOfDay }, { headers: { - "Authorization": "8690be69-3c53-4bc1-8e99-e4fe0472b757" + "Authorization": "92ff54fa-80b7-4f2c-bae1-f862ea7525ae" }, }); diff --git a/dexs/apollox/index.ts b/dexs/apollox/index.ts index 558c6c8e06..ad07efe6d2 100644 --- a/dexs/apollox/index.ts +++ b/dexs/apollox/index.ts @@ -54,7 +54,7 @@ type TotalVolumeItem = { }, "cumVol": number } - + const TotalVolumeV1AndV2ForBscAPI = "https://fapi.apollox.finance/fapi/v1/openInterestAndTrader" const TotalVolumeAPI = "https://www.apollox.finance/bapi/futures/v1/public/future/apx/fee/all" @@ -63,11 +63,22 @@ const v2VolumeAPI = const v1VolumeAPI = "https://www.apollox.finance/fapi/v1/ticker/24hr"; +async function sleep (time: number) { + return new Promise((resolve) => setTimeout(() => resolve(), time)) +} +let sleepCount = 0 const fetchV2Volume = async (chain: Chain) => { - const { data = [] } = ( + console.log('fetch ', chain, sleepCount * 2 * 1e3) + // This is very important!!! because our API will throw error when send >=2 requests at the same time. + await sleep(sleepCount++ * 2 * 1e3) + const res = ( await httpGet(v2VolumeAPI, { params: { chain, excludeCake: true } }) - ) as { data: ResponseItem[] } - const dailyVolume = data.reduce((p, c) => p + +c.qutoVol, 0); + ) as { data: ResponseItem[], success: boolean } + if (res.data === null && res.success === false) { + console.log(res, v2VolumeAPI, { chain, excludeCake: true }) + return fetchV2Volume(chain) + } + const dailyVolume = (res.data || []).reduce((p, c) => p + +c.qutoVol, 0); return dailyVolume }; @@ -82,7 +93,7 @@ const fetchV1Volume = async () => { const fetchTotalVolumeV1AndV2ForBSC = async () => { const data = ( await httpGet(TotalVolumeV1AndV2ForBscAPI) - ) as TotalVolumeV1AndV2ForBscItem + ) as TotalVolumeV1AndV2ForBscItem return { v1: Number(data.v1TotalVolume), v2: Number(data.v2TotalVolume) } }; @@ -97,7 +108,7 @@ const fetchTotalV2Volume = async (chain: Chain) => { const adapter: SimpleAdapter = { adapter: { [CHAIN.BSC]: { - runAtCurrTime: true, + // runAtCurrTime: true, fetch: async (timestamp) => { const [v1, v2, totalV2Volume, { v1 : totalV1Volume }] = await Promise.all([ fetchV2Volume(CHAIN.BSC), @@ -114,7 +125,7 @@ const adapter: SimpleAdapter = { start: 1682035200, }, [CHAIN.ARBITRUM]: { - runAtCurrTime: true, + // runAtCurrTime: true, fetch: async (timestamp) => { const [v2, totalVolume] = await Promise.all([ fetchV2Volume(CHAIN.ARBITRUM), @@ -129,7 +140,7 @@ const adapter: SimpleAdapter = { start: 1682035200, }, [CHAIN.OP_BNB]: { - runAtCurrTime: true, + // runAtCurrTime: true, fetch: async (timestamp) => { const [v2, totalVolume] = await Promise.all([ fetchV2Volume('opbnb'), @@ -144,7 +155,7 @@ const adapter: SimpleAdapter = { start: 1682035200, }, [CHAIN.BASE]: { - runAtCurrTime: true, + // runAtCurrTime: true, fetch: async (timestamp) => { const [v2, totalVolume] = await Promise.all([ fetchV2Volume(CHAIN.BASE), diff --git a/dexs/baseswap/index.ts b/dexs/baseswap/index.ts index fa6b8f4175..e4b014d39c 100644 --- a/dexs/baseswap/index.ts +++ b/dexs/baseswap/index.ts @@ -15,7 +15,7 @@ const v2Endpoints: ChainEndpoints = { [CHAIN.BASE]: sdk.graph.modifyEndpoint('BWHCfpXMHFDx3u4E14hEwv4ST7SUyN89FKJ2RjzWKgA9'), }; const v3Endpoints = { - [CHAIN.BASE]: sdk.graph.modifyEndpoint('39pzQzH5r3vmovd9fTs7rVDVFCj1xJye3dTMNHcSkSfL'), + [CHAIN.BASE]: 'https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/v3-base/prod/gn' }; // Fetch function to query the subgraphs diff --git a/dexs/bladeswap/index.ts b/dexs/bladeswap/index.ts index d3cdaca01f..f3d0f54b38 100644 --- a/dexs/bladeswap/index.ts +++ b/dexs/bladeswap/index.ts @@ -4,7 +4,7 @@ import { FetchOptions, BreakdownAdapter } from "../../adapters/types"; const adapters = univ2Adapter( { [CHAIN.BLAST]: - "https://graph-node.bladeswap.xyz/subgraphs/name/bladeswap/algebra-mainnet-info", + "https://api.studio.thegraph.com/query/75205/blade-algebra/mainnet-info-1.0.3", }, { factoriesName: "factories", diff --git a/dexs/carbondefi/index.ts b/dexs/carbondefi/index.ts new file mode 100644 index 0000000000..42a51e0272 --- /dev/null +++ b/dexs/carbondefi/index.ts @@ -0,0 +1,81 @@ +import { FetchOptions, IJSON, SimpleAdapter } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import fetchURL from "../../utils/fetchURL"; +import { CarbonAnalyticsResponse } from "./types"; +import { + getEmptyData, + getDimensionsSum, + getDimensionsSumByToken, +} from "./utils"; + +const CARBON_METADATA: { + methodology: IJSON; + hallmarks: [number, string][]; +} = { + hallmarks: [ + [1681986059, "CarbonDeFi Ethereum Launch"], + [1716825673, "CarbonDeFi Sei Launch"], + ], + methodology: { + Volume: + "Volume is calculated as the sum of the targetAmount tokens from TokensTraded events emitted by the CarbonController contract.", + Fees: "Fees are calculated as the sum of the tradingFeeAmount amount for the sourceToken if tradeByTarget is true or the targetToken if tradeByTarget is false, taken from TokensTraded events emitted by the CarbonController contract.", + }, +}; + +const chainInfo: { [key: string]: any } = { + [CHAIN.ETHEREUM]: { + endpoint: "https://api.carbondefi.xyz/v1/analytics/volume", + startBlock: 17087375, + startTimestamp: 1681986059, + getDimensionsByToken: false, + }, + [CHAIN.SEI]: { + endpoint: "https://sei-api.carbondefi.xyz/v1/analytics/volume", + startBlock: 79146720, + startTimestamp: 1716825673, + getDimensionsByToken: true, + }, +}; + +const getData = async (options: FetchOptions) => { + const analyticsEndpoint = chainInfo[options.chain].endpoint; + const getDimensionsByToken = chainInfo[options.chain].getDimensionsByToken; + const startTimestamp = options.fromTimestamp; + const endTimestamp = options.toTimestamp; + + try { + const swapData: CarbonAnalyticsResponse = await fetchURL(analyticsEndpoint); + + if (getDimensionsByToken) { + return getDimensionsSumByToken( + swapData, + startTimestamp, + endTimestamp, + getEmptyData(options) + ); + } + return getDimensionsSum(swapData, startTimestamp, endTimestamp); + } catch (e) { + console.error(e); + // Return empty values + return getEmptyData(options); + } +}; + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.ETHEREUM]: { + fetch: getData, + start: chainInfo[CHAIN.ETHEREUM].startTimestamp, + meta: CARBON_METADATA, + }, + [CHAIN.SEI]: { + fetch: getData, + start: chainInfo[CHAIN.SEI].startTimestamp, + meta: CARBON_METADATA, + }, + }, +}; +export default adapter; diff --git a/dexs/carbondefi/types.ts b/dexs/carbondefi/types.ts new file mode 100644 index 0000000000..cd40d205ee --- /dev/null +++ b/dexs/carbondefi/types.ts @@ -0,0 +1,13 @@ +interface CarbonAnalyticsItem { + timestamp: string; + feesymbol: string; + feeaddress: string; + tradingfeeamount_real: number; + tradingfeeamount_usd: number; + targetsymbol: string; + targetaddress: string; + targetamount_real: number; + targetamount_usd: number; +} + +export interface CarbonAnalyticsResponse extends Array {} diff --git a/dexs/carbondefi/utils.ts b/dexs/carbondefi/utils.ts new file mode 100644 index 0000000000..7140a3cff6 --- /dev/null +++ b/dexs/carbondefi/utils.ts @@ -0,0 +1,115 @@ +import { Balances } from "@defillama/sdk"; +import { CarbonAnalyticsResponse } from "./types"; +import { FetchOptions } from "../../adapters/types"; + +const filterDataByDate = ( + swapData: CarbonAnalyticsResponse, + startTimestampS: number, + endTimestampS: number +) => { + const startTimestampMs = startTimestampS * 1000; + const endTimestampMs = endTimestampS * 1000; + + return swapData.filter((swap) => { + const swapTsMs = Date.parse(swap.timestamp); + return swapTsMs >= startTimestampMs && swapTsMs <= endTimestampMs; + }); +}; + +export const getDimensionsSum = ( + swapData: CarbonAnalyticsResponse, + startTimestamp: number, + endTimestamp: number +) => { + const dailyData = filterDataByDate(swapData, startTimestamp, endTimestamp); + + const { dailyVolume, dailyFees } = dailyData.reduce( + (prev, curr) => { + return { + dailyVolume: prev.dailyVolume + curr.targetamount_usd, + dailyFees: prev.dailyFees + curr.tradingfeeamount_usd, + }; + }, + { + dailyVolume: 0, + dailyFees: 0, + } + ); + const { totalVolume, totalFees } = swapData.reduce( + (prev, curr) => { + return { + totalVolume: prev.totalVolume + curr.targetamount_usd, + totalFees: prev.totalFees + curr.tradingfeeamount_usd, + }; + }, + { + totalVolume: 0, + totalFees: 0, + } + ); + return { + dailyVolume, + totalVolume, + dailyFees, + totalFees, + }; +}; + +const isNativeToken = (address: string) => address.toLowerCase() === "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE".toLowerCase(); + +export const getDimensionsSumByToken = ( + swapData: CarbonAnalyticsResponse, + startTimestamp: number, + endTimestamp: number, + emptyData: { + dailyVolume: Balances; + dailyFees: Balances; + totalVolume: Balances; + totalFees: Balances; + }, +) => { + const dailyData = filterDataByDate(swapData, startTimestamp, endTimestamp); + const { dailyVolume, dailyFees, totalFees, totalVolume } = emptyData; + + swapData.forEach((swap) => { + if (isNativeToken(swap.targetaddress)) { + totalVolume.addGasToken(swap.targetamount_real * 1e18); + } else { + totalVolume.add(swap.targetaddress, swap.targetamount_real); + } + if (isNativeToken(swap.feeaddress)) { + totalFees.addGasToken(swap.tradingfeeamount_real * 1e18); + } else { + totalFees.add(swap.feeaddress, swap.tradingfeeamount_real); + } + }); + + dailyData.forEach((swap) => { + if (isNativeToken(swap.targetaddress)) { + dailyVolume.addGasToken(swap.targetamount_real * 1e18); + } else { + dailyVolume.add(swap.targetaddress, swap.targetamount_real); + } + if (isNativeToken(swap.feeaddress)) { + dailyFees.addGasToken(swap.tradingfeeamount_real * 1e18); + } else { + dailyFees.add(swap.feeaddress, swap.tradingfeeamount_real); + } + }); + + return { + dailyVolume, + dailyFees, + totalVolume, + totalFees, + }; +}; + +export const getEmptyData = (options: FetchOptions) => { + return { + dailyVolume: options.createBalances(), + dailyFees: options.createBalances(), + totalVolume: options.createBalances(), + totalFees: options.createBalances(), + }; +}; diff --git a/dexs/dedust/index.ts b/dexs/dedust/index.ts new file mode 100644 index 0000000000..60b107d34f --- /dev/null +++ b/dexs/dedust/index.ts @@ -0,0 +1,86 @@ +import { postURL } from "../../utils/fetchURL" +import { CHAIN } from "../../helpers/chains"; +import { FetchOptions, SimpleAdapter } from "../../adapters/types"; + +const GRAPHQL_ENDPOINT = 'https://api.dedust.io/v3/graphql'; + +const POOLS_QUERY = ` +query GetPools($filter: PoolsFiltersInput) { + pools(filter: $filter) { + address + totalSupply + type + tradeFee + assets + reserves + fees + volume + } + } +`; + +const ASSETS_QUERY = ` +query GetAssets { + assets { + type + address + symbol + decimals + price + } + } +`; + + +const fetch = async (options: FetchOptions) => { + const assetsList = (await postURL(GRAPHQL_ENDPOINT, { + query: ASSETS_QUERY, + operationName: 'GetAssets' + })).data.assets; + + const assetInfo = {}; + for (const asset of assetsList) { + const address = asset.type == 'native' ? 'native' : 'jetton:' + asset.address; + assetInfo[address] = { + decimals: asset.decimals, + price: Number(asset.price), + symbol: asset.symbol + } + } + + const poolsList = (await postURL(GRAPHQL_ENDPOINT, { + query: POOLS_QUERY, + operationName: 'GetPools' + })).data.pools; + + let dailyVolume = 0; + for (const pool of poolsList) { + const address = pool.address; + const leftAddr = pool.assets[0]; + const rightAddr = pool.assets[1]; + if (!(leftAddr in assetInfo && rightAddr in assetInfo)) { + continue; + } + const left = assetInfo[leftAddr]; + const right = assetInfo[rightAddr]; + + dailyVolume += (left.price * Number(pool.volume[0]) / Math.pow(10, left.decimals) + + right.price * Number(pool.volume[1]) / Math.pow(10, right.decimals)) / 2; + } + + return { + dailyVolume: dailyVolume + }; +}; + + +const adapter: SimpleAdapter = { + adapter: { + [CHAIN.TON]: { + fetch, + start: 1681931480, + }, + }, +}; + +export default adapter; diff --git a/dexs/dexswap/index.ts b/dexs/dexswap/index.ts new file mode 100644 index 0000000000..e11957c30c --- /dev/null +++ b/dexs/dexswap/index.ts @@ -0,0 +1,19 @@ +import { FetchOptions } from "../../adapters/types" +import { exportDexVolumeAndFees } from "../../helpers/dexVolumeLogs"; +import { SimpleAdapter } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; + +const FACTORY_ADDRESS = '0x3e40739d8478c58f9b973266974c58998d4f9e8b'; +const startDate = 1684702800; + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.ARBITRUM]: { + fetch: (options: FetchOptions) => exportDexVolumeAndFees({ chain: CHAIN.ARBITRUM, factory: FACTORY_ADDRESS })(options.endTimestamp, {}, options), + start: startDate, + }, + } +}; + +export default adapter; diff --git a/dexs/flashtrade/index.ts b/dexs/flashtrade/index.ts index acb6c3f06f..0366700507 100644 --- a/dexs/flashtrade/index.ts +++ b/dexs/flashtrade/index.ts @@ -20,8 +20,6 @@ const adapter: BreakdownAdapter = { perp: { [CHAIN.SOLANA]: { fetch: fetchPerpVolume, - runAtCurrTime: true, - customBackfill: undefined, start: 1710028800 // start time llama collect } } diff --git a/dexs/glyph-exchange-v4/index.ts b/dexs/glyph-exchange-v4/index.ts new file mode 100644 index 0000000000..017992e975 --- /dev/null +++ b/dexs/glyph-exchange-v4/index.ts @@ -0,0 +1,71 @@ +import { BreakdownAdapter } from "../../adapters/types"; +import { Chain } from "@defillama/sdk/build/general"; +import { CHAIN } from "../../helpers/chains"; +import { getGraphDimensions } from "../../helpers/getUniSubgraph"; + +const endpointsClassic = { + [CHAIN.CORE]: "https://thegraph.coredao.org/subgraphs/name/glyph/algebra" +}; + +const VOLUME_FIELD = "totalVolumeUSD"; +const DEFAULT_DAILY_VOLUME_FIELD = "volumeUSD"; +const FEES_FIELD = "totalFeesUSD"; +const DEFAULT_DAILY_FEES_FIELD = "feesUSD"; + +const graphsClassic = getGraphDimensions({ + graphUrls: endpointsClassic, + totalVolume: { + factory: "factories", + field: VOLUME_FIELD, + }, + dailyVolume: { + factory: "algebraDayData", + field: DEFAULT_DAILY_VOLUME_FIELD, + }, + totalFees: { + factory: "factories", + field: FEES_FIELD, + }, + dailyFees: { + factory: "algebraDayData", + field: DEFAULT_DAILY_FEES_FIELD, + }, + //dynamic fee + feesPercent: { + type: "fees", + Fees: 100, + UserFees: 100, + Revenue: 15, + ProtocolRevenue: 15, + SupplySideRevenue: 85 + } +}); + +const classic = Object.keys(endpointsClassic).reduce( + (acc, chain) => ({ + ...acc, + [chain]: { + fetch: graphsClassic(chain as Chain), + start: 1710806400, + meta: { + methodology: { + Fees: "GlyphExchange-v4 charges a dynamic fee", + UserFees: "GlyphExchange-v4 charges a dynamic fee", + Revenue: "15% fees goes to treasury", + ProtocolRevenue: "Treasury receives a share of the fees", + SupplySideRevenue: "85% fees goes to liquidity providers" + } + } + }, + }), + {} +) as any; + +const adapter: BreakdownAdapter = { + version: 2, + breakdown: { + classic: classic, + } +} + +export default adapter diff --git a/dexs/gmx-v2/gmx-v2-trade/index.ts b/dexs/gmx-v2/gmx-v2-trade/index.ts index b74ee4da48..2d3c0d96ef 100644 --- a/dexs/gmx-v2/gmx-v2-trade/index.ts +++ b/dexs/gmx-v2/gmx-v2-trade/index.ts @@ -8,14 +8,8 @@ interface ILog { topics: string[]; } -const topic0_ins = '0x137a44067c8961cd7e1d876f4754a5a3a75989b4552f1843fc69c3b372def160'; -const topic1_ins = '0xf94196ccb31f81a3e67df18f2a62cbfb50009c80a7d3c728a3f542e3abc5cb63'; - -const topic0_des = '0x137a44067c8961cd7e1d876f4754a5a3a75989b4552f1843fc69c3b372def160'; -const topic1_des = '0x07d51b51b408d7c62dcc47cc558da5ce6a6e0fd129a427ebce150f52b0e5171a'; - -const topic0_fees = '0x137a44067c8961cd7e1d876f4754a5a3a75989b4552f1843fc69c3b372def160'; -const topic1_fees = '0xe096982abd597114bdaa4a60612f87fabfcc7206aa12d61c50e7ba1e6c291100'; +const topic0_trades = '0x137a44067c8961cd7e1d876f4754a5a3a75989b4552f1843fc69c3b372def160'; +const topic1_trades = '0xe096982abd597114bdaa4a60612f87fabfcc7206aa12d61c50e7ba1e6c291100'; type TChain = { [s: Chain | string]: string; @@ -27,34 +21,19 @@ const contract: TChain = { } const fetch = async (options: FetchOptions): Promise => { - const posistion_logs = await options.getLogs({ - target: contract[options.chain], - topics: [topic0_ins, topic1_ins] - }); - - const decress_logs = await options.getLogs({ + const trade_logs = await options.getLogs({ target: contract[options.chain], - topics: [topic0_des, topic1_des] + topics: [topic0_trades, topic1_trades] }); - + let hash: string[] = []; - const raw_des = decress_logs.map((e: ILog) => { - const data = e.data.replace('0x', ''); - const volume = data.slice(102 * 64, (102 * 64) + 64); - const key = Number('0x' + data.slice(118 * 64, (118 * 64) + 64)); - if (key === 7) return 0; - hash.push(e.transactionHash); - // 156 - return Number('0x' + volume) / 1e30; - }) - - const raw_in = posistion_logs.filter(e => !hash.includes(e.transactionHash)).map((e: ILog) => { + const raw_trades = trade_logs.map((e: ILog) => { const data = e.data.replace('0x', ''); - const volume = data.slice(100 * 64, (100 * 64) + 64); + const volume = data.slice(81 * 64, (81 * 64) + 64); return Number('0x' + volume) / 1e30; }) - const dailyVolume: number = [...raw_des, ...raw_in] + const dailyVolume: number = [...raw_trades] .reduce((a: number, b: number) => a + b, 0); return { diff --git a/dexs/hyperliquid/index.ts b/dexs/hyperliquid/index.ts index ae19b88d21..1a1cdd80ee 100644 --- a/dexs/hyperliquid/index.ts +++ b/dexs/hyperliquid/index.ts @@ -26,7 +26,6 @@ const adapter: SimpleAdapter = { "hyperliquid": { fetch, start: 1677283200, - runAtCurrTime: true, }, } }; diff --git a/dexs/intent-x/index.tsx b/dexs/intent-x/index.tsx index 030070c964..08119f1edb 100644 --- a/dexs/intent-x/index.tsx +++ b/dexs/intent-x/index.tsx @@ -7,9 +7,9 @@ import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume const ONE_DAY_IN_SECONDS = 60 * 60 * 24; const endpoint_0_8_0 = - "https://api.thegraph.com/subgraphs/name/intent-x/perpetuals-analytics_base"; + "https://api.studio.thegraph.com/query/62472/perpetuals-analytics_base/version/latest"; const endpoint = - "https://api.studio.thegraph.com/query/62472/intentx-analytics_082/version/latest"; + "https://api.0xgraph.xyz/subgraphs/name/intentx-base-analytcs-082"; const endpoint_blast = "https://api.studio.thegraph.com/query/62472/intentx-analytics_082_blast/version/latest"; const endpoint_mantle = @@ -201,8 +201,8 @@ const fetchVolumeBlast = async ( totalVolume = totalVolume.plus(new BigNumber(data.tradeVolume)); }); - dailyVolume = dailyVolume.dividedBy(new BigNumber(1e18)); - totalVolume = totalVolume.dividedBy(new BigNumber(1e18)); + dailyVolume = dailyVolume.dividedBy(new BigNumber(1e18)).multipliedBy(2); + totalVolume = totalVolume.dividedBy(new BigNumber(1e18)).multipliedBy(2); const _dailyVolume = toString(dailyVolume); const _totalVolume = toString(totalVolume); diff --git a/dexs/iziswap/index.ts b/dexs/iziswap/index.ts index 2f82a1ed08..02b4acf279 100644 --- a/dexs/iziswap/index.ts +++ b/dexs/iziswap/index.ts @@ -34,6 +34,7 @@ const chains: TChains = { [CHAIN.SCROLL]: 534352, [CHAIN.BASE]: 8453, [CHAIN.MANTA]: 169, + [CHAIN.ZETA]: 7000 }; const fetch = (chain: Chain) => { diff --git a/dexs/kriya-clmm/index.ts b/dexs/kriya-clmm/index.ts new file mode 100644 index 0000000000..f8633517e9 --- /dev/null +++ b/dexs/kriya-clmm/index.ts @@ -0,0 +1,46 @@ +import fetchURL from "../../utils/fetchURL" +import { Chain } from "@defillama/sdk/build/general"; +import { FetchResultV2, SimpleAdapter } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; + +type IUrl = { + [s: string]: string; +} + +const url: IUrl = { + [CHAIN.SUI]: `https://tkmw8dmcp8.execute-api.ap-southeast-1.amazonaws.com/prod/volume/clmm/` +} + +interface IVolume { + totalVolume: number, + dailyVolume: number, + weeklyVolume: number, + monthlyVolume: number, +} + +const fetch = (chain: Chain) => { + return async ({ endTimestamp }): Promise => { + const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(endTimestamp * 1000)); + // fetch for the passed timestamp. + const volumeUrl = url[chain] + String(endTimestamp); + const volume: IVolume = (await fetchURL(volumeUrl)); + return { + totalVolume: `${volume?.totalVolume || undefined}`, + dailyVolume: `${volume?.dailyVolume || undefined}`, + timestamp: dayTimestamp, + }; + }; +} + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.SUI]: { + fetch: fetch(CHAIN.SUI), + start: 1683604174, + } + }, +}; + +export default adapter; \ No newline at end of file diff --git a/dexs/lynex/index.ts b/dexs/lynex/index.ts index aebddd92b1..e196e1a0d3 100644 --- a/dexs/lynex/index.ts +++ b/dexs/lynex/index.ts @@ -2,7 +2,7 @@ import { CHAIN } from "../../helpers/chains"; import { univ2Adapter } from "../../helpers/getUniSubgraphVolume"; const adapters = univ2Adapter({ - [CHAIN.LINEA]: "https://graph-query.linea.build/subgraphs/name/cryptoalgebra/analytics" + [CHAIN.LINEA]: "https://api.studio.thegraph.com/query/59052/lynex-cl/v1.0.1" }, { factoriesName: "factories", dayData: "algebraDayData", diff --git a/dexs/openbook/index.ts b/dexs/openbook/index.ts index 869de687fd..32012c1083 100644 --- a/dexs/openbook/index.ts +++ b/dexs/openbook/index.ts @@ -1,18 +1,22 @@ import { SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; -import fetchURL from "../../utils/fetchURL"; +import fetchURL, { httpGet } from "../../utils/fetchURL"; interface IVolume { - volume_24h: number; + notionalVolume24hour: number; } const fetch = async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)); - const url = `https://dry-ravine-67635.herokuapp.com/pairs`; - const historicalVolume: IVolume[] = (await fetchURL(url)); - const dailyVolume = historicalVolume.reduce((a: number, b: IVolume) => a + b.volume_24h, 0); + const url = `https://prod.arcana.markets/api/openbookv2/markets`; + const historicalVolume: IVolume[] = (await httpGet(url, { headers: { + "origin": "https://www.openbook.ag", + "Referer": "https://www.openbook.ag", + "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" } + })); + const dailyVolume = historicalVolume.reduce((a: number, b: IVolume) => a + b.notionalVolume24hour, 0); return { timestamp: dayTimestamp, diff --git a/dexs/perennial-v2/index.ts b/dexs/perennial-v2/index.ts index 290f0a2e23..0878884ec3 100644 --- a/dexs/perennial-v2/index.ts +++ b/dexs/perennial-v2/index.ts @@ -6,28 +6,21 @@ import { getEnv } from '../../helpers/env' const apiKey = getEnv('PERENNIAL_V2_SUBGRAPH_API_KEY') const graphUrls: { [key: string]: string } = { - [CHAIN.ARBITRUM]: `https://subgraph.satsuma-prod.com/${apiKey}/equilibria/perennial-v2-arbitrum/api`, + [CHAIN.ARBITRUM]: `https://subgraph.satsuma-prod.com/${apiKey}/equilibria/perennial-v2-arbitrum-new/api`, } const volumeDataQuery = gql` query PNLVolume($period: BigInt!, $periodEnd: BigInt!) { - daily: bucketedVolumes( - where: { - bucket: daily - periodStartTimestamp_gte: $period - periodStartTimestamp_lt: $periodEnd - } + daily: protocolAccumulations( + where: { bucket: daily, timestamp_gte: $period, timestamp_lt: $periodEnd } first: 1000 - orderBy: periodStartTimestamp + orderBy: timestamp orderDirection: desc ) { - market longNotional shortNotional } - - total: bucketedVolumes(where: { bucket: all }, first: 1000) { - market + total: protocolAccumulations(where: { bucket: all }) { longNotional shortNotional } diff --git a/dexs/raydium/index.ts b/dexs/raydium/index.ts index 5c422b5c70..b3e893f70a 100644 --- a/dexs/raydium/index.ts +++ b/dexs/raydium/index.ts @@ -8,12 +8,13 @@ const graphs = async (timestamp: number): Promise Number(i.tvl) > 100_000) .reduce((a: number, b) => a + b.day.volume, 0) let ammFee = 0 let clmmFee = 0 let cpmmFee = 0 - for (const item of ammPoolStandard) { + for (const item of ammPoolStandard.filter((i: any) => Number(i.tvl) > 100_000)){ if (item.programId === 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK') clmmFee += item.day.volumeFee else if (item.programId === 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C') cpmmFee += item.day.volumeFee else ammFee += item.day.volumeFee @@ -56,7 +57,7 @@ const graphs = async (timestamp: number): Promise sum + (pool?.stats?.volume_24h || 0), 0); + const dailyVolume = await httpGet('https://api.stabble.org/stats/volume?type=daily'); return { - dailyVolume: vol24h, + dailyVolume: dailyVolume, timestamp: timestamp } } diff --git a/dexs/tlx-finance/index.ts b/dexs/tlx-finance/index.ts index 359fd15d97..7cbf27a947 100644 --- a/dexs/tlx-finance/index.ts +++ b/dexs/tlx-finance/index.ts @@ -38,13 +38,13 @@ const fetchLeveragedTokenVolume = async ( const mint_valume = mints_logs.map((logs, i) => { return logs.map((log: any) => { - return new BigNumber(log.baseAssetAmount).times(targetLeverages[i]).div(1e18) + return new BigNumber(log.leveragedTokenAmount).times(targetLeverages[i]).div(1e18) }) }).flat().reduce((acc: any, log: any) => acc.plus(log), new BigNumber(0)); const redeem_valume = redeems_logs.map((logs, i) => { return logs.map((log: any) => { - return new BigNumber(log.baseAssetAmount).times(targetLeverages[i]).div(1e18) + return new BigNumber(log.leveragedTokenAmount).times(targetLeverages[i]).div(1e18) }) }).flat().reduce((acc: any, log: any) => acc.plus(log), new BigNumber(0)); diff --git a/dexs/vela/index.ts b/dexs/vela/index.ts index 158818fc72..79eebf2c6d 100644 --- a/dexs/vela/index.ts +++ b/dexs/vela/index.ts @@ -8,9 +8,9 @@ import { getTimestampAtStartOfDayUTC } from "../../utils/date"; const endpoints = { [CHAIN.ARBITRUM]: - sdk.graph.modifyEndpoint('6H9PEiNPZgwXfpbijjesZh96LFBzUvkHmEutMoYQ9fvp'), + sdk.graph.modifyEndpoint('https://api.goldsky.com/api/public/project_clu01p4nr68r301pze2tj4sh7/subgraphs/vela-arbitrum/mainnet/gn'), [CHAIN.BASE]: - sdk.graph.modifyEndpoint('2qsbZ4X5TJM7NupC2eRJv167kBDFCDBd37KnK7PQtdga') + sdk.graph.modifyEndpoint('https://api.goldsky.com/api/public/project_clu01p4nr68r301pze2tj4sh7/subgraphs/vela-base/mainnet/gn') }; const graphs = (graphUrls: ChainEndpoints) => { diff --git a/dexs/velodrome-slipstream/index.ts b/dexs/velodrome-slipstream/index.ts index d5ebee94bf..ad5671e241 100644 --- a/dexs/velodrome-slipstream/index.ts +++ b/dexs/velodrome-slipstream/index.ts @@ -26,7 +26,7 @@ const fetch = async (options: FetchOptions): Promise => { const dailyVolume = options.createBalances() const dailyFees = options.createBalances() let chunkSize = 400; - let currentOffset = 630; // Slipstream launched after ~650 v2 pools were already created + let currentOffset = 0; const allForSwaps: IForSwap[] = []; let unfinished = true; let sugarContract = sugar; @@ -34,37 +34,54 @@ const fetch = async (options: FetchOptions): Promise => { // before the new Sugar is deployed, we must use the old Sugar contract, and make one large Sugar call if (options.startOfDay < 1715160600) { chunkSize = 1800; - currentOffset = 0; sugarContract = sugarOld; } while (unfinished) { - const forSwaps: IForSwap[] = (await options.api.call({ + const forSwapsUnfiltered: IForSwap[] = (await options.api.call({ target: sugarContract, - params: [chunkSize, currentOffset], // Slipstream launched after ~650 v2 pools were already created + params: [chunkSize, currentOffset], abi: abis.forSwaps, chain: CHAIN.OPTIMISM, - })).filter(t => Number(t.type) > 0).map((e: any) => { + })); + + const forSwaps: IForSwap[] = forSwapsUnfiltered.filter(t => Number(t.type) > 0).map((e: any) => { return { lp: e.lp, token0: e.token0, token1: e.token1, pool_fee: e.pool_fee, } - }) + }); - unfinished = forSwaps.length !== 0; + unfinished = forSwapsUnfiltered.length !== 0; currentOffset += chunkSize; allForSwaps.push(...forSwaps); } - const targets: string[] = [...new Set(allForSwaps.map((forSwap: IForSwap) => forSwap.lp))] + const targets = allForSwaps.map((forSwap: IForSwap) => forSwap.lp) - const logs: ILog[][] = await options.getLogs({ - targets, - eventAbi: event_swap, - flatten: false, - }) + let logs: ILog[][] = []; + const targetChunkSize = 5; + let currentTargetOffset = 0; + unfinished = true; + + while (unfinished) { + let endOffset = currentTargetOffset + targetChunkSize; + if (endOffset >= targets.length) { + unfinished = false; + endOffset = targets.length; + } + + let currentLogs: ILog[][] = await options.getLogs({ + targets: targets.slice(currentTargetOffset, endOffset), + eventAbi: event_swap, + flatten: false, + }) + + logs.push(...currentLogs); + currentTargetOffset += targetChunkSize; + } logs.forEach((logs: ILog[], idx: number) => { const { token1, pool_fee } = allForSwaps[idx] diff --git a/dexs/woofi/index.ts b/dexs/woofi/index.ts index 615283d2de..3af651b47a 100644 --- a/dexs/woofi/index.ts +++ b/dexs/woofi/index.ts @@ -1,9 +1,9 @@ import * as sdk from "@defillama/sdk"; import { Chain } from "@defillama/sdk/build/general"; -import { ChainBlocks, SimpleAdapter } from "../../adapters/types"; +import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; +import { getChainVolume } from "../../helpers/getUniSubgraphVolume"; -const { getChainVolume } = require("../../helpers/getUniSubgraphVolume"); const endpoints = { [CHAIN.AVAX]: sdk.graph.modifyEndpoint('BL45YVVLVkCRGaAtyTjvuRt1yHnUt4QbZg8bWcZtLvLm'), @@ -55,15 +55,18 @@ const graphs = getChainVolume({ }, }); -const fetch = (chain: string) => { - return async (timestamp: number, chainBlocks: ChainBlocks) => { - const result = await graphs(chain)(timestamp, chainBlocks); +const fetch = async (options: FetchOptions) => { + try { + const result = await graphs(options.chain)(options); if (!result) return {}; return { ...result, - totalVolume: `${result.totalVolume / 10 ** 18}`, - dailyVolume: `${result.dailyVolume / 10 ** 18}` + totalVolume: `${(result?.totalVolume || 0) / 10 ** 18}`, + dailyVolume: `${(result?.dailyVolume || 0) / 10 ** 18}` }; + } catch (error) { + console.error(error); + return {}; } } @@ -71,7 +74,7 @@ const volume = Object.keys(endpoints).reduce( (acc, chain) => ({ ...acc, [chain]: { - fetch: fetch(chain), + fetch: fetch, start: startTime[chain], }, }), diff --git a/dexs/yfx-v4/index.ts b/dexs/yfx-v4/index.ts index bcfa216b98..81d8ee70b3 100644 --- a/dexs/yfx-v4/index.ts +++ b/dexs/yfx-v4/index.ts @@ -3,10 +3,11 @@ import { Fetch, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; -const chains = [CHAIN.ARBITRUM] +const chains = [CHAIN.ARBITRUM, CHAIN.BASE] const endpoints: { [key: string]: string } = { - [CHAIN.ARBITRUM]: "https://graph-v4.yfx.com/yfx_v4" + [CHAIN.ARBITRUM]: "https://graph-v4.yfx.com/yfx_v4", + [CHAIN.BASE]: "https://graph-v4.yfx.com/yfx_v4_base", } const historicalDailyData = gql` @@ -68,6 +69,7 @@ const getFetch = (chain: string): Fetch => async (timestamp: any) => { const getStartTimestamp = async (chain: string) => { const startTimestamps: { [chain: string]: number } = { [CHAIN.ARBITRUM]: 1713916800, + [CHAIN.BASE]: 1721001600, } return startTimestamps[chain] } diff --git a/fees/across.ts b/fees/across.ts index 2af53f89fd..16b1a30e4a 100644 --- a/fees/across.ts +++ b/fees/across.ts @@ -41,7 +41,7 @@ const graph = (chain: Chain) => { target: address[chain], eventAbi: abis.FundsDeposited, topic: topic0_fund_disposit_v2, - fromBlock, + fromBlock, toBlock }) ).filter((a: any) => Number(a!.destinationChainId) === 288); @@ -51,7 +51,7 @@ const graph = (chain: Chain) => { target: address[chain], eventAbi: abis.V3FundsDeposited, topic: topic0_fund_disposit_v3, - fromBlock, + fromBlock, toBlock }) ).filter((a: any) => Number(a!.destinationChainId) === 288); @@ -68,7 +68,7 @@ const graph = (chain: Chain) => { target: address[chain], eventAbi: abis.FilledV3Relay, topic: topic0_filled_replay_v3, - fromBlock, + fromBlock, toBlock }); @@ -110,10 +110,10 @@ const adapter: SimpleAdapter = { fetch: graph(CHAIN.ARBITRUM), start: 1682840443, }, - [CHAIN.OPTIMISM]: { - fetch: graph(CHAIN.OPTIMISM), - start: 1682840443, - }, + // [CHAIN.OPTIMISM]: { + // fetch: graph(CHAIN.OPTIMISM), + // start: 1682840443, + // }, [CHAIN.POLYGON]: { fetch: graph(CHAIN.POLYGON), start: 1682840443, diff --git a/fees/apollox/index.ts b/fees/apollox/index.ts index cedd0e4e60..641078930b 100644 --- a/fees/apollox/index.ts +++ b/fees/apollox/index.ts @@ -8,7 +8,8 @@ const FeesAndRevenueURL = "https://www.apollox.finance/bapi/futures/v1/public/f const request = () => { return (chain: Chain) => { return async () => { - const { data } = await httpGet(FeesAndRevenueURL, { params: { chain } }) + const url = `${FeesAndRevenueURL}?chain=${chain}` + const { data } = await httpGet(url) const { alpFeeVOFor24Hour, allAlpFeeVO } = data return { dailyFees: alpFeeVOFor24Hour.fee || 0, @@ -26,7 +27,7 @@ const adapter: Adapter = { runAtCurrTime: true, fetch: request()(CHAIN.BSC), start: 1689609600, - }, + }, [CHAIN.ARBITRUM]: { runAtCurrTime: true, fetch: request()(CHAIN.ARBITRUM), diff --git a/fees/betmode.ts b/fees/betmode.ts new file mode 100644 index 0000000000..ae179e5afd --- /dev/null +++ b/fees/betmode.ts @@ -0,0 +1,24 @@ +import { FetchOptions, SimpleAdapter } from "../adapters/types"; +import { CHAIN } from "../helpers/chains"; + +const address = '0xeb5D5af6a0ac3B64243858094d6b3b379B8772Aa' +const fetch = async (options: FetchOptions) => { + const dailyFees = options.createBalances(); + const feesStart = await options.fromApi.call({ target: address, abi: "uint:GGR" }) + const feesEnd = await options.toApi.call({ target: address, abi: "uint:GGR" }) + dailyFees.add("0xd988097fb8612cc24eeC14542bC03424c656005f", feesEnd - feesStart) + dailyFees.resizeBy(0.065) + return { dailyFees, dailyRevenue: dailyFees } +} + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.MODE]: { + fetch: fetch, + start: 0, + } + } +} + +export default adapter; diff --git a/fees/buffer/index.ts b/fees/buffer/index.ts index a41ec83207..d2da616c39 100644 --- a/fees/buffer/index.ts +++ b/fees/buffer/index.ts @@ -1,60 +1,46 @@ import { CHAIN } from "../../helpers/chains"; import { request, gql } from "graphql-request"; -import type { ChainEndpoints } from "../../adapters/types" -import { Chain } from '@defillama/sdk/build/general'; +import type { ChainEndpoints } from "../../adapters/types"; +import { Chain } from "@defillama/sdk/build/general"; import BigNumber from "bignumber.js"; -import { Adapter } from "../../adapters/types" +import { Adapter } from "../../adapters/types"; const endpoints = { - [CHAIN.ARBITRUM]: "https://subgraph.satsuma-prod.com/e66b06ce96d2/bufferfinance/v2.5-arbitrum-mainnet/api" -} + [CHAIN.ARBITRUM]: "https://satsuma-dump.buffer.finance/", +}; export function _getDayId(timestamp: number): string { let dayTimestamp = Math.floor((timestamp - 16 * 3600) / 86400); return dayTimestamp.toString(); } -const graphs = (graphUrls: ChainEndpoints) => { +const graphs = (baseUrls: ChainEndpoints) => { return (chain: Chain) => { return async (timestamp: number) => { const dateId = _getDayId(timestamp); - const graphQuery = gql - `{ - defillamaFeeStat(id: ${dateId}) { - fee - } - }`; - - const graphRes = await request(graphUrls[chain], graphQuery); - - const dailyFee = new BigNumber(graphRes.defillamaFeeStat.fee).div(1000000); - // const protocolRev = new BigNumber(graphRes.dailyRevenueAndFee.settlementFee).div(1000000).times(0.05); - // const userHolderRev = new BigNumber(graphRes.dailyRevenueAndFee.settlementFee).div(1000000).times(0.4); - // const supplySideRev = new BigNumber(graphRes.dailyRevenueAndFee.settlementFee).div(1000000).times(0.55); - const dailyRev = new BigNumber(graphRes.defillamaFeeStat.fee).div(1000000); + const url = new URL(baseUrls[chain]); + url.searchParams.append("day", dateId); + const response = await fetch(url); + const dailyFee = (await response.json()).fee / 1000000; return { timestamp, dailyFees: dailyFee.toString(), - // dailyProtocolRevenue: protocolRev.toString(), - // dailyUserHolderRevenue: userHolderRev.toString(), - // dailySupplySideRevenue: supplySideRev.toString(), - dailyRevenue: dailyRev.toString() + dailyRevenue: dailyFee.toString(), }; }; }; }; - const adapter: Adapter = { adapter: { [CHAIN.ARBITRUM]: { - fetch: graphs(endpoints)(CHAIN.ARBITRUM), - start: 1674950400 , + fetch: graphs(endpoints)(CHAIN.ARBITRUM), + start: 1674950400, }, }, - version: 1 -} + version: 1, +}; export default adapter; diff --git a/fees/d2finance/index.ts b/fees/d2finance/index.ts new file mode 100644 index 0000000000..b9061ecfe8 --- /dev/null +++ b/fees/d2finance/index.ts @@ -0,0 +1,117 @@ +import BigNumber from "bignumber.js"; +import { FetchV2 } from "../../adapters/types"; +import { ARBITRUM } from "../../helpers/chains"; +import { getPrices } from "../../utils/prices"; +import { gql, GraphQLClient } from "graphql-request"; +import { + getTimestampAtStartOfMonth, + getTimestampAtStartOfNextMonth, +} from "../../utils/date"; + +interface Token { + ticker: string; + geckoId: string; + decimals: number; +} + +interface DataItem { + blockTimestamp: number; + contract: string; + token: string; + amount: string; +} + +const tokens = [ + { + ticker: "ARB", + geckoId: "coingecko:arbitrum", + decimals: 18, + }, + { + ticker: "ETH", + geckoId: "coingecko:ethereum", + decimals: 18, + }, + { + ticker: "USDC", + geckoId: "coingecko:usd-coin", + decimals: 6, + }, +]; + +const fetchFeeData = async (timestamp: number) => { + const client = new GraphQLClient("https://d2.finance/subgraphs/name/d2"); + const req = gql` + query Query { + feesWithdrawns(where: { blockTimestamp_lte: ${timestamp} }) { + blockTimestamp + contract + token + amount + } + } + `; + const response = await client.request(req); + const feesWithdrawns: DataItem[] = response.feesWithdrawns; + return feesWithdrawns; +}; + +const fetchTokenPrices = async (timestamp: number) => { + const prices = await getPrices( + tokens.map((token: Token) => token.geckoId), + timestamp + ); + + return prices; +}; + +const fetch: FetchV2 = async ({ startTimestamp }) => { + const monthStartTimeStamp = getTimestampAtStartOfMonth(startTimestamp); + const monthEndTimestamp = getTimestampAtStartOfNextMonth(startTimestamp); + + const result = await fetchFeeData(startTimestamp); + const tokenPrices = await fetchTokenPrices(startTimestamp); + + let totalAmount = 0; + let monthlyAmount = 0; + for (let data of result) { + const token = tokens.find((token) => token.ticker === data.token); + if (token) { + const price = tokenPrices[token.geckoId].price; + const amountInDollar = Number( + BigNumber(data.amount) + .times(price) + .dividedBy(BigNumber(10).pow(token.decimals)) + ); + totalAmount += amountInDollar; + if ( + data.blockTimestamp >= monthStartTimeStamp && + data.blockTimestamp < monthEndTimestamp + ) { + monthlyAmount += amountInDollar; + } + } + } + + const monthFee = monthlyAmount / 30; + + return { + dailyFees: monthFee, + dailyRevenue: monthFee, + dailyProtocolRevenue: monthFee, + totalFees: totalAmount, + totalRevenue: totalAmount, + totalProtocolRevenue: totalAmount, + }; +}; + +export default { + version: 2, + adapter: { + [ARBITRUM]: { + fetch, + start: 1705715264, + runAtCurrTime: true, + }, + }, +}; diff --git a/fees/extra/index.ts b/fees/extra/index.ts index bf41605ec3..2a24c9a85a 100644 --- a/fees/extra/index.ts +++ b/fees/extra/index.ts @@ -7,8 +7,8 @@ type TEndpoint = { [s: CHAIN | string]: string; } const endpoints: TEndpoint = { - [CHAIN.OPTIMISM]: `https://api.thegraph.com/subgraphs/name/extrafi/extrasubgraph`, - [CHAIN.BASE]: `https://api.thegraph.com/subgraphs/name/extrafi/extrafionbase` + [CHAIN.OPTIMISM]: `https://gateway-arbitrum.network.thegraph.com/api/a4998f968b8ad324eb3e47ed20c00220/subgraphs/id/3Htp5TKs6BHCcwAYRCoBD6R4X62ThLRv2JiBBikyYze`, + [CHAIN.BASE]: `https://api.studio.thegraph.com/query/46015/extrafionbase/version/latest` } interface IFeePaid { diff --git a/fees/fluid/index.ts b/fees/fluid/index.ts index afe9f70909..1c681d31b9 100644 --- a/fees/fluid/index.ts +++ b/fees/fluid/index.ts @@ -4,49 +4,224 @@ import BigNumber from "bignumber.js"; import { Adapter, FetchV2 } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; -const fluidLiquidity = "0x52aa899454998be5b000ad077a46bbe360f4e497"; - -const fluidRevenueResolverExistAfterBlock = 19784319; -const fluidRevenueResolver = "0x0F683159f14857D61544650607549Cdc21abE774"; -const fluidRevenueResolverAbi = { - calcRevenueSimulatedTime: - "function calcRevenueSimulatedTime(uint256 totalAmounts_,uint256 exchangePricesAndConfig_,uint256 liquidityTokenBalance_,uint256 simulatedTimestamp_) public view returns (uint256 revenueAmount_)", - getRevenue: - "function getRevenue(address token_) public view returns (uint256 revenueAmount_)", +const abis = { + revenueResolver: { + calcRevenueSimulatedTime: + "function calcRevenueSimulatedTime(uint256 totalAmounts_,uint256 exchangePricesAndConfig_,uint256 liquidityTokenBalance_,uint256 simulatedTimestamp_) public view returns (uint256 revenueAmount_)", + getRevenue: + "function getRevenue(address token_) public view returns (uint256 revenueAmount_)", + }, + liquidityResolver: { + listedTokens: + "function listedTokens() public view returns (address[] listedTokens_)", + getExchangePricesAndConfig: + "function getExchangePricesAndConfig(address token_) public view returns (uint256)", + getTotalAmounts: + "function getTotalAmounts(address token_) public view returns (uint256)", + }, + vaultResolver_before_19992222: { + getAllVaultsAddresses: + "function getAllVaultsAddresses() external view returns (address[] vaults_)", + getVaultEntireData: + "function getVaultEntireData(address vault_) view returns ((address vault, (address liquidity, address factory, address adminImplementation, address secondaryImplementation, address supplyToken, address borrowToken, uint8 supplyDecimals, uint8 borrowDecimals, uint256 vaultId, bytes32 liquiditySupplyExchangePriceSlot, bytes32 liquidityBorrowExchangePriceSlot, bytes32 liquidityUserSupplySlot, bytes32 liquidityUserBorrowSlot) constantVariables, (uint16 supplyRateMagnifier, uint16 borrowRateMagnifier, uint16 collateralFactor, uint16 liquidationThreshold, uint16 liquidationMaxLimit, uint16 withdrawalGap, uint16 liquidationPenalty, uint16 borrowFee, address oracle, uint256 oraclePrice, address rebalancer) configs, (uint256 lastStoredLiquiditySupplyExchangePrice, uint256 lastStoredLiquidityBorrowExchangePrice, uint256 lastStoredVaultSupplyExchangePrice, uint256 lastStoredVaultBorrowExchangePrice, uint256 liquiditySupplyExchangePrice, uint256 liquidityBorrowExchangePrice, uint256 vaultSupplyExchangePrice, uint256 vaultBorrowExchangePrice, uint256 supplyRateVault, uint256 borrowRateVault, uint256 supplyRateLiquidity, uint256 borrowRateLiquidity, uint256 rewardsRate) exchangePricesAndRates, (uint256 totalSupplyVault, uint256 totalBorrowVault, uint256 totalSupplyLiquidity, uint256 totalBorrowLiquidity, uint256 absorbedSupply, uint256 absorbedBorrow) totalSupplyAndBorrow, (uint256 withdrawLimit, uint256 withdrawableUntilLimit, uint256 withdrawable, uint256 borrowLimit, uint256 borrowableUntilLimit, uint256 borrowable, uint256 minimumBorrowing) limitsAndAvailability, (uint256 totalPositions, int256 topTick, uint256 currentBranch, uint256 totalBranch, uint256 totalBorrow, uint256 totalSupply, (uint256 status, int256 minimaTick, uint256 debtFactor, uint256 partials, uint256 debtLiquidity, uint256 baseBranchId, int256 baseBranchMinima) currentBranchState) vaultState, (bool modeWithInterest, uint256 supply, uint256 withdrawalLimit, uint256 lastUpdateTimestamp, uint256 expandPercent, uint256 expandDuration, uint256 baseWithdrawalLimit, uint256 withdrawableUntilLimit, uint256 withdrawable) liquidityUserSupplyData, (bool modeWithInterest, uint256 borrow, uint256 borrowLimit, uint256 lastUpdateTimestamp, uint256 expandPercent, uint256 expandDuration, uint256 baseBorrowLimit, uint256 maxBorrowLimit, uint256 borrowableUntilLimit, uint256 borrowable) liquidityUserBorrowData) vaultData_)", + }, + vaultResolver_after_19992222: { + getAllVaultsAddresses: + "function getAllVaultsAddresses() external view returns (address[] vaults_)", + getVaultEntireData: + "function getVaultEntireData(address vault_) view returns ((address vault, (address liquidity, address factory, address adminImplementation, address secondaryImplementation, address supplyToken, address borrowToken, uint8 supplyDecimals, uint8 borrowDecimals, uint256 vaultId, bytes32 liquiditySupplyExchangePriceSlot, bytes32 liquidityBorrowExchangePriceSlot, bytes32 liquidityUserSupplySlot, bytes32 liquidityUserBorrowSlot) constantVariables, (uint16 supplyRateMagnifier, uint16 borrowRateMagnifier, uint16 collateralFactor, uint16 liquidationThreshold, uint16 liquidationMaxLimit, uint16 withdrawalGap, uint16 liquidationPenalty, uint16 borrowFee, address oracle, uint256 oraclePriceOperate, uint256 oraclePriceLiquidate, address rebalancer) configs, (uint256 lastStoredLiquiditySupplyExchangePrice, uint256 lastStoredLiquidityBorrowExchangePrice, uint256 lastStoredVaultSupplyExchangePrice, uint256 lastStoredVaultBorrowExchangePrice, uint256 liquiditySupplyExchangePrice, uint256 liquidityBorrowExchangePrice, uint256 vaultSupplyExchangePrice, uint256 vaultBorrowExchangePrice, uint256 supplyRateVault, uint256 borrowRateVault, uint256 supplyRateLiquidity, uint256 borrowRateLiquidity, uint256 rewardsRate) exchangePricesAndRates, (uint256 totalSupplyVault, uint256 totalBorrowVault, uint256 totalSupplyLiquidity, uint256 totalBorrowLiquidity, uint256 absorbedSupply, uint256 absorbedBorrow) totalSupplyAndBorrow, (uint256 withdrawLimit, uint256 withdrawableUntilLimit, uint256 withdrawable, uint256 borrowLimit, uint256 borrowableUntilLimit, uint256 borrowable, uint256 borrowLimitUtilization, uint256 minimumBorrowing) limitsAndAvailability, (uint256 totalPositions, int256 topTick, uint256 currentBranch, uint256 totalBranch, uint256 totalBorrow, uint256 totalSupply, (uint256 status, int256 minimaTick, uint256 debtFactor, uint256 partials, uint256 debtLiquidity, uint256 baseBranchId, int256 baseBranchMinima) currentBranchState) vaultState, (bool modeWithInterest, uint256 supply, uint256 withdrawalLimit, uint256 lastUpdateTimestamp, uint256 expandPercent, uint256 expandDuration, uint256 baseWithdrawalLimit, uint256 withdrawableUntilLimit, uint256 withdrawable) liquidityUserSupplyData, (bool modeWithInterest, uint256 borrow, uint256 borrowLimit, uint256 lastUpdateTimestamp, uint256 expandPercent, uint256 expandDuration, uint256 baseBorrowLimit, uint256 maxBorrowLimit, uint256 borrowableUntilLimit, uint256 borrowable, uint256 borrowLimitUtilization) liquidityUserBorrowData) vaultData_)", + }, + vault: { + constantsView: + "function constantsView() public view returns((address liquidity,address factory,address adminImplementation,address secondaryImplementation,address supplyToken,address borrowToken,uint8 supplyDecimals,uint8 borrowDecimals,uint vaultId,bytes32 liquiditySupplyExchangePriceSlot,bytes32 liquidityBorrowExchangePriceSlot,bytes32 liquidityUserSupplySlot,bytes32 liquidityUserBorrowSlot))", + }, }; -const fluidLiquidityResolver = "0x741c2Cd25f053a55fd94afF1afAEf146523E1249"; -const fluidLiquidityResolverAbi = { - listedTokens: - "function listedTokens() public view returns (address[] listedTokens_)", - getExchangePricesAndConfig: - "function getExchangePricesAndConfig(address token_) public view returns (uint256)", - getTotalAmounts: - "function getTotalAmounts(address token_) public view returns (uint256)", +const revenueResolver = async (api: sdk.ChainApi) => { + const block = await api.getBlock(); + + let address; + let abi = abis.revenueResolver; + switch (api.chain) { + case CHAIN.ETHEREUM: + if (block < 19784319) { + break; // fluid RevenueResolver Exist After Block 19784319 + } + if (block < 20138676) { + address = "0x0F683159f14857D61544650607549Cdc21abE774"; + break; + } + address = "0xFe4affaD55c7AeC012346195654634F7C786fA2c"; + break; + case CHAIN.ARBITRUM: + address = "0xFe4affaD55c7AeC012346195654634F7C786fA2c"; + break; + } + + return { + calcRevenueSimulatedTime: async ( + totalAmounts: string, + exchangePricesAndConfig: string, + liquidityTokenBalance: string | BigNumber, + timestamp: string | number + ) => { + if (!address) { + return 0; + } + + return await api.call({ + target: address, + abi: abi.calcRevenueSimulatedTime, + params: [ + totalAmounts, + exchangePricesAndConfig, + liquidityTokenBalance as string, + timestamp, + ], + }); + }, + getRevenue: async (token: string) => { + if (!address) { + return 0; + } + + return await api.call({ + target: address, + abi: abi.getRevenue, + params: [token], + }); + }, + }; }; -// up until block 19662786, must use historical resolver as new one had not been deployed yet -const vaultResolverExistAfterTimestamp = 1708931052; // vault resolver related revenue only exists after this timestamp. revenue / fees before are negligible -const vaultResolverExistAfterBlock = 19313700; // vault resolver related revenue only exists after this timestamp. revenue / fees before are negligible -const vaultResolverHistoricalBlock = 19662786; -const fluidVaultResolverHistorical = - "0x8DD65DaDb217f73A94Efb903EB2dc7B49D97ECca"; -const fluidVaultResolver = "0x93CAB6529aD849b2583EBAe32D13817A2F38cEb4"; -const fluidVaultResolverAbi = { - getAllVaultsAddresses: - "function getAllVaultsAddresses() external view returns (address[] vaults_)", - getVaultEntireData: - "function getVaultEntireData(address vault_) view returns ((address vault, (address liquidity, address factory, address adminImplementation, address secondaryImplementation, address supplyToken, address borrowToken, uint8 supplyDecimals, uint8 borrowDecimals, uint256 vaultId, bytes32 liquiditySupplyExchangePriceSlot, bytes32 liquidityBorrowExchangePriceSlot, bytes32 liquidityUserSupplySlot, bytes32 liquidityUserBorrowSlot) constantVariables, (uint16 supplyRateMagnifier, uint16 borrowRateMagnifier, uint16 collateralFactor, uint16 liquidationThreshold, uint16 liquidationMaxLimit, uint16 withdrawalGap, uint16 liquidationPenalty, uint16 borrowFee, address oracle, uint256 oraclePrice, address rebalancer) configs, (uint256 lastStoredLiquiditySupplyExchangePrice, uint256 lastStoredLiquidityBorrowExchangePrice, uint256 lastStoredVaultSupplyExchangePrice, uint256 lastStoredVaultBorrowExchangePrice, uint256 liquiditySupplyExchangePrice, uint256 liquidityBorrowExchangePrice, uint256 vaultSupplyExchangePrice, uint256 vaultBorrowExchangePrice, uint256 supplyRateVault, uint256 borrowRateVault, uint256 supplyRateLiquidity, uint256 borrowRateLiquidity, uint256 rewardsRate) exchangePricesAndRates, (uint256 totalSupplyVault, uint256 totalBorrowVault, uint256 totalSupplyLiquidity, uint256 totalBorrowLiquidity, uint256 absorbedSupply, uint256 absorbedBorrow) totalSupplyAndBorrow, (uint256 withdrawLimit, uint256 withdrawableUntilLimit, uint256 withdrawable, uint256 borrowLimit, uint256 borrowableUntilLimit, uint256 borrowable, uint256 minimumBorrowing) limitsAndAvailability, (uint256 totalPositions, int256 topTick, uint256 currentBranch, uint256 totalBranch, uint256 totalBorrow, uint256 totalSupply, (uint256 status, int256 minimaTick, uint256 debtFactor, uint256 partials, uint256 debtLiquidity, uint256 baseBranchId, int256 baseBranchMinima) currentBranchState) vaultState, (bool modeWithInterest, uint256 supply, uint256 withdrawalLimit, uint256 lastUpdateTimestamp, uint256 expandPercent, uint256 expandDuration, uint256 baseWithdrawalLimit, uint256 withdrawableUntilLimit, uint256 withdrawable) liquidityUserSupplyData, (bool modeWithInterest, uint256 borrow, uint256 borrowLimit, uint256 lastUpdateTimestamp, uint256 expandPercent, uint256 expandDuration, uint256 baseBorrowLimit, uint256 maxBorrowLimit, uint256 borrowableUntilLimit, uint256 borrowable) liquidityUserBorrowData) vaultData_)", +const liquidityResolver = async (api: sdk.ChainApi) => { + const block = await api.getBlock(); + + let address; + let abi = abis.liquidityResolver; + switch (api.chain) { + case CHAIN.ETHEREUM: + if (block < 19992056) { + address = "0x741c2Cd25f053a55fd94afF1afAEf146523E1249"; + break; + } + address = "0xD7588F6c99605Ab274C211a0AFeC60947668A8Cb"; + break; + case CHAIN.ARBITRUM: + address = "0x46859d33E662d4bF18eEED88f74C36256E606e44"; + break; + } + + return { + listedTokens: async () => { + if (!address) { + return []; + } + + return await api.call({ + target: address, + abi: abi.listedTokens, + params: undefined, + }); + }, + getExchangePricesAndConfig: async (token: string) => { + if (!address) { + return 0; + } + + return await api.call({ + target: address, + abi: abi.getExchangePricesAndConfig, + params: [token], + }); + }, + getTotalAmounts: async (token: string) => { + if (!address) { + return 0; + } + + return await api.call({ + target: address, + abi: abi.getTotalAmounts, + params: [token], + }); + }, + }; }; -const fluidVaultResolverTarget = async (api: sdk.ChainApi) => { - return (await api.getBlock()) > vaultResolverHistoricalBlock - ? fluidVaultResolver - : fluidVaultResolverHistorical; + +const vaultResolver = async (api: sdk.ChainApi) => { + const block = await api.getBlock(); + + let address; + let abi = abis.vaultResolver_after_19992222; + switch (api.chain) { + case CHAIN.ETHEREUM: + if (block < 19313700) { + // vault resolver related revenue only exists after this block. revenue / fees before are negligible + break; + } + + if (block < 19662786) { + address = "0x8DD65DaDb217f73A94Efb903EB2dc7B49D97ECca"; + abi = abis.vaultResolver_before_19992222; + break; + } + if (block < 19992222) { + address = "0x93CAB6529aD849b2583EBAe32D13817A2F38cEb4"; + abi = abis.vaultResolver_before_19992222; + break; + } + address = "0x56ddF84B2c94BF3361862FcEdB704C382dc4cd32"; + break; + case CHAIN.ARBITRUM: + address = "0x77648D39be25a1422467060e11E5b979463bEA3d"; + break; + } + + return { + getAllVaultsAddresses: async () => { + if (!address) { + return []; + } + + return await api.call({ + target: address, + abi: abi.getAllVaultsAddresses, + params: undefined, + }); + }, + getVaultEntireData: async (vault: string) => { + if (!address) { + return null; + } + + return await api.call({ + target: address, + abi: abi.getVaultEntireData, + params: [vault], + }); + }, + }; }; -const fluidVaultAbi = { - constantsView: - "function constantsView() public view returns((address liquidity,address factory,address adminImplementation,address secondaryImplementation,address supplyToken,address borrowToken,uint8 supplyDecimals,uint8 borrowDecimals,uint vaultId,bytes32 liquiditySupplyExchangePriceSlot,bytes32 liquidityBorrowExchangePriceSlot,bytes32 liquidityUserSupplySlot,bytes32 liquidityUserBorrowSlot))", +const config = { + liquidity: "0x52aa899454998be5b000ad077a46bbe360f4e497", + ethereum: { + dataStartTimestamp: 1708246655, // ~ when liquidity resolver was deployed + + revenueResolverExistAfterBlock: 19959852, + // vault resolver related revenue only exists after this timestamp. revenue / fees before are negligible + vaultResolverExistAfterTimestamp: 1708931052, + vaultResolverExistAfterBlock: 19313700, + }, + arbitrum: { + dataStartTimestamp: 1720018638, // ~ before any activity started (block 228361633) + + revenueResolverExistAfterBlock: 228361632, + // vault resolver related revenue only exists after this timestamp. revenue / fees before are negligible + vaultResolverExistAfterTimestamp: 1720018637, + vaultResolverExistAfterBlock: 228361632, + }, }; const methodologyFluid = { @@ -54,13 +229,19 @@ const methodologyFluid = { Revenue: "Percentage of interest going to treasury", }; -const dataStartTimestamp = 1708246655; // ~ when liquidity resolver was deployed - const fetch: FetchV2 = async ({ api, fromTimestamp, toTimestamp }) => { return { - // totalFees: await getFeesFromTo(api, dataStartTimestamp, toTimestamp), + // totalFees: await getFeesFromTo( + // api, + // config[api.chain].dataStartTimestamp, + // toTimestamp + // ), dailyFees: await getFeesFromTo(api, fromTimestamp, toTimestamp), - // totalRevenue: await getRevenueFromTo(api, dataStartTimestamp, toTimestamp), + // totalRevenue: await getRevenueFromTo( + // api, + // config[api.chain].dataStartTimestamp, + // toTimestamp + // ), dailyRevenue: await getRevenueFromTo(api, fromTimestamp, toTimestamp), }; }; @@ -69,7 +250,14 @@ const adapter: Adapter = { adapter: { [CHAIN.ETHEREUM]: { fetch, - start: dataStartTimestamp, + start: config.ethereum.dataStartTimestamp, + meta: { + methodology: methodologyFluid, + }, + }, + [CHAIN.ARBITRUM]: { + fetch, + start: config.arbitrum.dataStartTimestamp, meta: { methodology: methodologyFluid, }, @@ -87,16 +275,16 @@ const getFeesFromTo = async ( let fromBlock = (await getBlock(api.chain, fromTimestamp)).number; const toBlock = (await getBlock(api.chain, toTimestamp)).number; - if (fromTimestamp < vaultResolverExistAfterTimestamp) { - fromTimestamp = vaultResolverExistAfterTimestamp; - fromBlock = vaultResolverExistAfterBlock; + if (fromTimestamp < config[api.chain].vaultResolverExistAfterTimestamp) { + fromTimestamp = config[api.chain].vaultResolverExistAfterTimestamp; + fromBlock = config[api.chain].vaultResolverExistAfterBlock; } if (fromTimestamp >= toTimestamp) { return 0; } const liquidityOperateLogs = (await sdk.getEventLogs({ - target: fluidLiquidity, + target: config.liquidity, fromBlock, toBlock, chain: api.chain, @@ -113,20 +301,17 @@ const getFeesFromTo = async ( chain: api.chain, block: toBlock, }); - const vaults: string[] = await toApi.call({ - target: await fluidVaultResolverTarget(toApi), - abi: fluidVaultResolverAbi.getAllVaultsAddresses, - }); + const vaults: string[] = await ( + await vaultResolver(toApi) + ).getAllVaultsAddresses(); for await (const vault of vaults) { let borrowBalance = new BigNumber(0); let borrowToken = ""; try { - const { constantVariables, totalSupplyAndBorrow } = await fromApi.call({ - target: await fluidVaultResolverTarget(fromApi), - abi: fluidVaultResolverAbi.getVaultEntireData, - params: [vault], - }); + const { constantVariables, totalSupplyAndBorrow } = await ( + await vaultResolver(fromApi) + ).getVaultEntireData(vault); borrowToken = constantVariables.borrowToken; borrowBalance = new BigNumber(totalSupplyAndBorrow.totalBorrowVault); @@ -137,7 +322,8 @@ const getFeesFromTo = async ( if (!borrowToken) { const { borrowToken: vaultBorrowToken } = await toApi.call({ target: vault, - abi: fluidVaultAbi.constantsView, + abi: abis.vault.constantsView, + chain: toApi.chain, }); borrowToken = vaultBorrowToken; } @@ -154,13 +340,9 @@ const getFeesFromTo = async ( } try { - const { totalSupplyAndBorrow: totalSupplyAndBorrowTo } = await toApi.call( - { - target: await fluidVaultResolverTarget(toApi), - abi: fluidVaultResolverAbi.getVaultEntireData, - params: [vault], - } - ); + const { totalSupplyAndBorrow: totalSupplyAndBorrowTo } = await ( + await vaultResolver(toApi) + ).getVaultEntireData(vault); toApi.addToken( borrowToken, @@ -193,13 +375,10 @@ const getLiquidityRevenueFromTo = async ( fromTimestamp: number, toTimestamp: number ) => { - const tokens: string[] = await api.call({ - target: fluidLiquidityResolver, - abi: fluidLiquidityResolverAbi.listedTokens, - }); + const tokens: string[] = await (await liquidityResolver(api)).listedTokens(); const collectRevenueLogs: [string, BigNumber][] = (await sdk.getEventLogs({ - target: fluidLiquidity, + target: config.liquidity, fromBlock: (await getBlock(api.chain, fromTimestamp)).number, toBlock: (await getBlock(api.chain, toTimestamp)).number, chain: api.chain, @@ -260,58 +439,56 @@ const getLiquidityUncollectedRevenueAt = async ( // check if token was listed at that timestamp at Liquidity, if not, revenue is 0 if ( !( - (await timestampedApi.call({ - target: fluidLiquidityResolver, - abi: fluidLiquidityResolverAbi.listedTokens, - })) as string[] + (await ( + await liquidityResolver(timestampedApi) + ).listedTokens()) as string[] ).includes(token) ) { return new BigNumber(0); } // get liquidity packed storage slots data at timestamped Api block number - const totalAmounts = await timestampedApi.call({ - target: fluidLiquidityResolver, - abi: fluidLiquidityResolverAbi.getTotalAmounts, - params: [token], - }); - const exchangePricesAndConfig = await timestampedApi.call({ - target: fluidLiquidityResolver, - abi: fluidLiquidityResolverAbi.getExchangePricesAndConfig, - params: [token], - }); + const totalAmounts = await ( + await liquidityResolver(timestampedApi) + ).getTotalAmounts(token); + + const exchangePricesAndConfig = await ( + await liquidityResolver(timestampedApi) + ).getExchangePricesAndConfig(token); + let liquidityTokenBalance: BigNumber | string; if (token.toLowerCase() == "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") { liquidityTokenBalance = ( await sdk.api.eth.getBalance({ - target: fluidLiquidity, + target: config.liquidity, + chain: timestampedApi.chain, block: await timestampedApi.getBlock(), }) ).output; } else { liquidityTokenBalance = await timestampedApi.call({ target: token, + chain: timestampedApi.chain, abi: "erc20:balanceOf", - params: [fluidLiquidity], + params: [config.liquidity], }); } // pass data into revenue resolver, available at current api block, which calculates revenue at the // simulated timestamp based on storage slots data - - const uncollectedRevenue = await new sdk.ChainApi({ - chain: api.chain, - block: fluidRevenueResolverExistAfterBlock, - }).call({ - target: fluidRevenueResolver, - abi: fluidRevenueResolverAbi.calcRevenueSimulatedTime, - params: [ - totalAmounts, - exchangePricesAndConfig, - liquidityTokenBalance, - timestamp, - ], - }); + const uncollectedRevenue = await ( + await revenueResolver( + new sdk.ChainApi({ + chain: api.chain, + block: config[api.chain].revenueResolverExistAfterBlock, + }) + ) + )?.calcRevenueSimulatedTime( + totalAmounts, + exchangePricesAndConfig, + liquidityTokenBalance, + timestamp + ); return new BigNumber(uncollectedRevenue); }; @@ -321,7 +498,7 @@ const getVaultsMagnifierRevenueFromTo = async ( fromTimestamp: number, toTimestamp: number ) => { - if (toTimestamp < vaultResolverExistAfterTimestamp) { + if (toTimestamp < config[api.chain].vaultResolverExistAfterTimestamp) { return 0; } @@ -335,10 +512,9 @@ const getVaultsMagnifierRevenueFromTo = async ( chain: api.chain, }); - const vaults: string[] = await toBalancesApi.call({ - target: await fluidVaultResolverTarget(toBalancesApi), - abi: fluidVaultResolverAbi.getAllVaultsAddresses, - }); + const vaults: string[] = await ( + await vaultResolver(toBalancesApi) + ).getAllVaultsAddresses(); for await (const vault of vaults) { fromBalancesApi = await getVaultMagnifierUncollectedRevenueAt( @@ -405,7 +581,8 @@ const getVaultMagnifierCollectedRevenueFromTo = async ( // get collateral and borrow token of the vault const { supplyToken, borrowToken } = await api.call({ target: vault, - abi: fluidVaultAbi.constantsView, + abi: abis.vault.constantsView, + chain: api.chain, }); for await (const log of rebalanceEventLogs) { @@ -428,7 +605,7 @@ const getVaultMagnifierUncollectedRevenueAt = async ( vault: string, balancesApi: sdk.ChainApi ) => { - if (timestamp < vaultResolverExistAfterTimestamp) { + if (timestamp < config[api.chain].vaultResolverExistAfterTimestamp) { // vault resolver related revenue only exists after this timestamp. before this there has been no such revenue. return balancesApi; } @@ -441,12 +618,9 @@ const getVaultMagnifierUncollectedRevenueAt = async ( }); try { - const { totalSupplyAndBorrow, constantVariables } = - await timestampedApi.call({ - target: await fluidVaultResolverTarget(timestampedApi), - abi: fluidVaultResolverAbi.getVaultEntireData, - params: [vault], - }); + const { totalSupplyAndBorrow, constantVariables } = await ( + await vaultResolver(timestampedApi) + ).getVaultEntireData(vault); const totalSupplyVault = new BigNumber( totalSupplyAndBorrow.totalSupplyVault @@ -478,3 +652,4 @@ const getVaultMagnifierUncollectedRevenueAt = async ( return balancesApi; }; +// yarn test fees fluid diff --git a/fees/gamma.ts b/fees/gamma.ts index f75c83a64a..3d3a253ad9 100644 --- a/fees/gamma.ts +++ b/fees/gamma.ts @@ -58,23 +58,23 @@ const fetchFees = (chain: string) => { const adapter: SimpleAdapter = { adapter: { [CHAIN.ETHEREUM]: { - fetch: fetchFees(CHAIN.ETHEREUM), - start: 1682121600, - }, - [CHAIN.ARBITRUM]: { - fetch: fetchFees(CHAIN.ARBITRUM), + fetch: fetchFees("ethereum"), start: 1682121600, }, [CHAIN.POLYGON]: { - fetch: fetchFees(CHAIN.POLYGON), + fetch: fetchFees("polygon"), start: 1682121600, }, [CHAIN.POLYGON_ZKEVM]: { - fetch: fetchFees(CHAIN.POLYGON_ZKEVM), + fetch: fetchFees("polygon_zkevm"), start: 1682121600, }, [CHAIN.OPTIMISM]: { - fetch: fetchFees(CHAIN.OPTIMISM), + fetch: fetchFees("optimism"), + start: 1682121600, + }, + [CHAIN.ARBITRUM]: { + fetch: fetchFees("arbitrum"), start: 1682121600, }, [CHAIN.BSC]: { @@ -85,50 +85,94 @@ const adapter: SimpleAdapter = { fetch: fetchFees("moonbeam"), start: 1682121600, }, + [CHAIN.CELO]: { + fetch: fetchFees("celo"), + start: 1682121600, + }, + [CHAIN.AVAX]: { + fetch: fetchFees("avalanche"), + start: 1682121600, + }, + [CHAIN.FANTOM]: { + fetch: fetchFees("fantom"), + start: 1682121600, + }, + [CHAIN.MANTLE]: { + fetch: fetchFees("mantle"), + start: 1682121600, + }, [CHAIN.ROLLUX]: { - fetch: fetchFees(CHAIN.ROLLUX), + fetch: fetchFees("rollux"), start: 1682121600, }, [CHAIN.LINEA]: { - fetch: fetchFees(CHAIN.LINEA), + fetch: fetchFees("linea"), start: 1682121600, }, - [CHAIN.MANTA]: { - fetch: fetchFees("manta"), + [CHAIN.BASE]: { + fetch: fetchFees("base"), start: 1682121600, }, - [CHAIN.AVAX]: { - fetch: fetchFees("avalanche"), + [CHAIN.KAVA]: { + fetch: fetchFees("kava"), start: 1682121600, }, - [CHAIN.XDAI]: { - fetch: fetchFees("gnosis"), + [CHAIN.OP_BNB]: { + fetch: fetchFees("op_bnb"), start: 1682121600, }, - [CHAIN.MANTLE]: { - fetch: fetchFees("mantle"), + [CHAIN.MANTA]: { + fetch: fetchFees("manta"), start: 1682121600, }, - [CHAIN.CELO]: { - fetch: fetchFees("celo"), + [CHAIN.METIS]: { + fetch: fetchFees("metis"), start: 1682121600, }, - [CHAIN.METIS]: { - fetch: fetchFees("metis"), + [CHAIN.XDAI]: { + fetch: fetchFees("gnosis"), + start: 1682121600, + }, + [CHAIN.ASTRZK]: { + fetch: fetchFees("astar_zkevm"), start: 1682121600, }, [CHAIN.IMX]: { fetch: fetchFees("immutable_zkevm"), start: 1682121600, }, - [CHAIN.ASTRZK]: { - fetch: fetchFees("astar_zkevm"), + [CHAIN.SCROLL]: { + fetch: fetchFees("scroll"), start: 1682121600, }, - [CHAIN.BLAST]: { + [CHAIN.BLAST]: { fetch: fetchFees("blast"), start: 1682121600, }, + [CHAIN.XLAYER]: { + fetch: fetchFees("xlayer"), + start: 1682121600, + }, + [CHAIN.MODE]: { + fetch: fetchFees("mode"), + start: 1682121600, + }, + [CHAIN.TAIKO]: { + fetch: fetchFees("taiko"), + start: 1682121600, + }, + [CHAIN.ROOTSTOCK]: { + fetch: fetchFees("rootstock"), + start: 1682121600, + }, + [CHAIN.SEI]: { + fetch: fetchFees("sei"), + start: 1682121600, + }, + [CHAIN.IOTAEVM]: { + fetch: fetchFees("iota_evm"), + start: 1682121600, + }, } } diff --git a/fees/intent-x/index.tsx b/fees/intent-x/index.tsx index 004a098b1e..554a05374f 100644 --- a/fees/intent-x/index.tsx +++ b/fees/intent-x/index.tsx @@ -4,9 +4,9 @@ import { FetchOptions, SimpleAdapter } from "../../adapters/types"; import { CHAIN } from "../../helpers/chains"; const endpoint_0_8_0 = - "https://api.thegraph.com/subgraphs/name/intent-x/perpetuals-analytics_base"; + "https://api.studio.thegraph.com/query/62472/perpetuals-analytics_base/version/latest"; const endpoint = - "https://api.studio.thegraph.com/query/62472/intentx-analytics_082/version/latest"; + "https://api.0xgraph.xyz/subgraphs/name/intentx-base-analytcs-082"; const endpoint_blast = "https://api.studio.thegraph.com/query/62472/intentx-analytics_082_blast/version/latest"; const endpoint_mantle = diff --git a/fees/juice-finance/index.ts b/fees/juice-finance/index.ts new file mode 100644 index 0000000000..77fe024a79 --- /dev/null +++ b/fees/juice-finance/index.ts @@ -0,0 +1,86 @@ +// https://juice-finance.gitbook.io/juice-finance/juice-protocol/fees#protocol-fees +import { Adapter, FetchOptions, FetchResultV2 } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import ADDRESSES from "../../helpers/coreAssets.json"; + +const event = "event DepositFeeTaken(uint256 amount)"; +const WETH = ADDRESSES.blast.WETH; +const USDB = ADDRESSES.blast.USDB; + +const WETH_WETH_stategies: string[] = [ + "0x78E6265a11a41E5Dcd1431448d00f3524943fD11", + "0x3FeC7f626923445F587C4881a80D00a7104782d1", + "0x6F3Bc2f9034C151326A80F5ca1Ee0F1eA1E6f002", + "0xEA42f500A92E4CAa02b2F10E323EadEE1F00fbF7", + "0x40214EDef589149b9cebb7BE7025197d885D6CB1", + "0x9Dfd4094b3e88f3b9E79b04514B1669D6779AeC9", + "0x741011f52B7499ca951f8b8Ee547DD3Cdd813Fda", + "0x576314F851732b208d807260FE19FeC7Dba3E40C", + "0x15e44C3f3F9B34fC49cc15A18a597bf80F144bC9", + "0x98546CdD046219b25B2E617A55563A5e4a3b9Adc", + "0x3e1B017D21ad613c58F8eE2f78987b3c9F14f643", + "0xC2eB02621e74E294B73B9fab0A94081393F31978", +]; + +const WETH_USDB_stategies: string[] = [ + "0xbc0b332d88DCF65a4CD6905eF939213f485FE1A3", + "0xc1B1aE2502D2cDEF4772FB4A4a6fcBf4fd9c1b80", + "0x542A672B1DEa78EFd83B9D7D8CAe76cEa59964a1", + "0x8034b01555487C26D4e21F4E33b7A30fbc90d181", + "0x4A355D57fc1A5eEB33C0a19539744A2144220027", + "0x0CA56aa647E83A8F0a5f7a81a2fdcA393bC68D78", + "0xfEc64ae675CC4B1AacF8F9C0ABeaD585c5496382", + "0x72E4ce9b7cC5d9C017F64ad58e512C253a11d30a", +]; + +const USDB_USDB_stategies: string[] = [ + "0xbc0b332d88DCF65a4CD6905eF939213f485FE1A3", + "0xc1B1aE2502D2cDEF4772FB4A4a6fcBf4fd9c1b80", + "0xd04c891876675f8c02160ee33466315ac13afc38", + "0x542A672B1DEa78EFd83B9D7D8CAe76cEa59964a1", + "0x0CA56aa647E83A8F0a5f7a81a2fdcA393bC68D78", +]; + +const getAndSumFees = async ( + options: FetchOptions, + targets: string[], + event: string +) => { + const logsFees = await options.getLogs({ + targets, + eventAbi: event, + flatten: true, + }); + return logsFees.reduce((acc, fee) => acc + Number(fee), 0); +}; + +const fetch = async (options: FetchOptions): Promise => { + const dailyFees = options.createBalances(); + + const [wethwethFees, wethusdbFees, usdbusdbFees] = await Promise.all([ + getAndSumFees(options, WETH_WETH_stategies, event), + getAndSumFees(options, WETH_USDB_stategies, event), + getAndSumFees(options, USDB_USDB_stategies, event), + ]); + + dailyFees.add(WETH, wethwethFees); + dailyFees.add(USDB, wethusdbFees + usdbusdbFees); + + return { dailyFees, dailyRevenue: dailyFees }; +}; + +const adapter: Adapter = { + adapter: { + [CHAIN.BLAST]: { + fetch, + start: 1709247600, + meta: { + methodology: + "Applied to strategies at the team's discretion and always noted on the vault page. It is charged upon entering the strategy, typically ranging from 0.5% to 2%.", + }, + }, + }, + version: 2, +}; + +export default adapter; diff --git a/fees/liquid-collective/index.ts b/fees/liquid-collective/index.ts new file mode 100644 index 0000000000..fc5a584f13 --- /dev/null +++ b/fees/liquid-collective/index.ts @@ -0,0 +1,35 @@ +// https://docs.liquidcollective.io/v1/faqs#what-is-the-protocol-service-fee +import { Adapter, FetchOptions, FetchResultV2 } from "../../adapters/types"; +import { ETHEREUM } from "../../helpers/chains"; +import ADDRESSES from "../../helpers/coreAssets.json"; + +const lsETH = "0x8c1BEd5b9a0928467c9B1341Da1D7BD5e10b6549"; +const event = "event PulledELFees(uint256 amount)"; +const WETH = ADDRESSES.ethereum.WETH; + +const fetch = async (options: FetchOptions): Promise => { + const dailyFees = options.createBalances(); + const fees = await options.getLogs({ + target: lsETH, + eventAbi: event, + }); + + dailyFees.add(WETH, fees); + return { dailyFees }; +}; + +const adapter: Adapter = { + adapter: { + [ETHEREUM]: { + fetch, + start: 1668812400, + meta: { + methodology: + "The Liquid Collective protocol charges a service fee set at 15.0% of network rewards, split amongst Node Operators, Platforms, Wallet & Custody Providers, Service Providers, the protocol's Slashing Coverage Treasury, and the Liquid Collective DAO, which comprises a broad and dispersed community of protocol participants", + }, + }, + }, + version: 2, +}; + +export default adapter; diff --git a/fees/lynex-v1.ts b/fees/lynex-v1.ts index f5515e117d..5d201f128e 100644 --- a/fees/lynex-v1.ts +++ b/fees/lynex-v1.ts @@ -1,10 +1,8 @@ import { Chain } from "@defillama/sdk/build/general"; import BigNumber from "bignumber.js"; import request, { gql } from "graphql-request"; -import { Adapter, FetchOptions, FetchResultFees, FetchResultV2 } from "../adapters/types"; +import { Adapter, FetchOptions, FetchResultV2 } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; -import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; -import { getTimestampAtStartOfDayUTC } from "../utils/date"; interface IPairDayData { id: string; diff --git a/fees/lynex.ts b/fees/lynex.ts index d13fba111c..082a0c9b38 100644 --- a/fees/lynex.ts +++ b/fees/lynex.ts @@ -1,3 +1,4 @@ +import * as sdk from "@defillama/sdk"; import { Chain } from "@defillama/sdk/build/general"; import BigNumber from "bignumber.js"; import request, { gql } from "graphql-request"; @@ -5,7 +6,10 @@ import { Adapter, FetchResultFees } from "../adapters/types"; import { CHAIN } from "../helpers/chains"; import { getUniqStartOfTodayTimestamp } from "../helpers/getUniSubgraphVolume"; import { getTimestampAtStartOfDayUTC } from "../utils/date"; +import { FetchOptions } from "../adapters/types"; +const LYNX = '0x1a51b19ce03dbe0cb44c1528e34a7edd7771e9af'; +const bveLYNX = '0xe8a4c9b6a2b79fd844c9e3adbc8dc841eece557b'; interface IPoolData { id: number; feesUSD: string; @@ -16,26 +20,58 @@ type IURL = { } const endpoints: IURL = { - [CHAIN.LINEA]: "https://graph-query.linea.build/subgraphs/name/cryptoalgebra/analytics" + [CHAIN.LINEA]: "https://api.studio.thegraph.com/query/59052/lynex-cl/v1.0.1" } -const fetch = (chain: Chain) => { - return async (timestamp: number): Promise => { +const event_reward_added = 'event RewardAdded(address indexed rewardToken,uint256 reward,uint256 startTimestamp)'; +const event_gauge_created = 'event GaugeCreated(address indexed gauge, address creator,address internal_bribe,address indexed external_bribe,address indexed pool)' + +export const fees_bribes = async ({ getLogs, createBalances, getToBlock }: FetchOptions): Promise => { + const voter = '0x0B2c83B6e39E32f694a86633B4d1Fe69d13b63c5'; + const dailyFees = createBalances() + const logs_geuge_created = (await getLogs({ + target: voter, + fromBlock: 2207763, + toBlock: await getToBlock(), + eventAbi: event_gauge_created, + cacheInCloud: true, + })) + const bribes_contract: string[] = logs_geuge_created.map((e: any) => e.external_bribe.toLowerCase()); + + const logs = await getLogs({ + targets: bribes_contract, + eventAbi: event_reward_added, + }) + logs.map((e: any) => { + // NOTE: bveLYNX is a derivative token 1:1 to LYNX and should be counted as LYNX as it is not tracked in coingecko + if (e.rewardToken.toLowerCase() === bveLYNX) + dailyFees.add(LYNX, e.reward) + else + dailyFees.add(e.rewardToken, e.reward) + }) + return dailyFees; +} + + +const fetch = async (fetchOptions: FetchOptions): Promise => { + const chain = fetchOptions.chain; + const timestamp = fetchOptions.startOfDay; const todayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)); const dateId = Math.floor(getTimestampAtStartOfDayUTC(todayTimestamp) / 86400) const graphQuery = gql ` - { - algebraDayData(id: ${dateId}) { - id - feesUSD - } - } - `; + { + algebraDayData(id: ${dateId}) { + id + feesUSD + } + } + `; const graphRes: IPoolData = (await request(endpoints[chain], graphQuery)).algebraDayData; const dailyFeeUSD = graphRes; const dailyFee = dailyFeeUSD?.feesUSD ? new BigNumber(dailyFeeUSD.feesUSD) : undefined + const dailyBribesRevenue = await fees_bribes(fetchOptions) if (dailyFee === undefined) return { timestamp } return { @@ -44,14 +80,15 @@ const fetch = (chain: Chain) => { dailyUserFees: dailyFee.toString(), dailyRevenue: dailyFee.toString(), dailyHoldersRevenue: dailyFee.toString(), + dailyBribesRevenue }; - }; } const adapter: Adapter = { + version: 2, adapter: { [CHAIN.LINEA]: { - fetch: fetch(CHAIN.LINEA), + fetch: fetch, start: 1691394680, }, }, diff --git a/fees/origin-dollar/index.ts b/fees/origin-dollar/index.ts new file mode 100644 index 0000000000..ec0dc70a32 --- /dev/null +++ b/fees/origin-dollar/index.ts @@ -0,0 +1,64 @@ +// https://docs.originprotocol.com/ogn/staking#staking-rewards +import axios from "axios"; +import { Adapter, FetchOptions, FetchResultV2 } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import ADDRESSES from "../../helpers/coreAssets.json"; + +const apiUrl: string = "https://api.originprotocol.com/api/v2/protocol-fees"; +const USDT: string = ADDRESSES.ethereum.USDT; +const decimals: number = 1e6; + +interface DayData { + date: number; + revenue: number; +} + +interface ApiResponse { + revenue: { + now: number; + oneDayAgo: number; + twoDaysAgo: number; + oneWeekAgo: number; + twoWeeksAgo: number; + thirtyDaysAgo: number; + sixtyDaysAgo: number; + ninetyDaysAgo: number; + }; + days: DayData[]; +} + +const fetch = async (options: FetchOptions): Promise => { + const { startOfDay, createBalances } = options; + const dailyRevenue = createBalances(); + const totalRevenue = createBalances(); + + const { data } = await axios.get(apiUrl); + + const dailyData = data.days.find((day) => day.date === startOfDay); + if (dailyData) dailyRevenue.add(USDT, dailyData.revenue * decimals); + totalRevenue.add(USDT, data.revenue.now * decimals); + + return { + dailyRevenue, + dailyFees: dailyRevenue, + totalRevenue, + totalFees: totalRevenue, + }; +}; + +const adapter: Adapter = { + adapter: { + [CHAIN.ETHEREUM]: { + fetch, + start: 1635811200, + runAtCurrTime: false, + meta: { + methodology: + "20% of all yield generated by OUSD and OETH is collected as a protocol fee.", + }, + }, + }, + version: 2, +}; + +export default adapter; diff --git a/fees/scallop/index.ts b/fees/scallop/index.ts new file mode 100644 index 0000000000..69ffb3b17a --- /dev/null +++ b/fees/scallop/index.ts @@ -0,0 +1,68 @@ +import { + Adapter, + FetchResultFees, + FetchResultV2, + FetchV2, +} from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; +import fetchURL from "../../utils/fetchURL"; + +const scallopApiURL = 'https://sui.apis.scallop.io/statistic/daily-fees'; + +interface DailyStats { + borrowingInterestFee: number, + liquidationFee: number, + borrowingFee: number, + flashloanFee: number, + liquidityProviderInterest: number, + dateHistory: string; +} + +const methodology = { + Fees: 'Interest and fees paid by borrowers and the liquidated', + UserFees: 'Interest and fees paid by borrowers and the liquidated', + ProtocolRevenue: 'The portion of the total fees going to the Scallop treasury', + SupplySideRevenue: '80% of all collected borrowing interest fees go to liquidity providers.' +} + +const fetchScallopStats: FetchV2 = async ({ startTimestamp, endTimestamp }): Promise => { + const url = `${scallopApiURL}?fromTimestamp=${startTimestamp}&toTimestamp=${endTimestamp}` + const stats: DailyStats = await fetchURL(url); + + const dailyFees = stats.borrowingInterestFee + + stats.liquidationFee + + stats.borrowingFee + + stats.flashloanFee + + stats.liquidityProviderInterest; + + const dailyRevenue = stats.liquidationFee + + stats.borrowingFee + + stats.flashloanFee + + stats.borrowingInterestFee; + + return { + dailyFees: dailyFees.toString(), + dailyUserFees: dailyFees.toString(), + dailyRevenue: dailyRevenue.toString(), + dailyProtocolRevenue: dailyRevenue.toString(), + dailySupplySideRevenue: stats.liquidityProviderInterest.toString(), + }; +}; + + +const adapter: Adapter = { + version: 2, + adapter: { + [CHAIN.SUI]: { + runAtCurrTime: false, + customBackfill: undefined, + fetch: fetchScallopStats, + start: 1703980799, + meta: { + methodology, + }, + }, + }, +}; + +export default adapter; diff --git a/fees/silo-finance/index.ts b/fees/silo-finance/index.ts new file mode 100644 index 0000000000..6e8aed81ed --- /dev/null +++ b/fees/silo-finance/index.ts @@ -0,0 +1,230 @@ +import { Chain } from "@defillama/sdk/build/general"; +import { Adapter, FetchOptions, FetchResultV2 } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; + +type FeeResult = { + asset: string; + fee: bigint; +}; + +type IFactory = { + address: string; + block: number; +}; + +type ISilo = { + lens: string; + factory: IFactory | IFactory[]; + silos?: { silo: string; assets: string[] }[]; +}; + +type IAddress = { + [s: string | Chain]: ISilo[]; +}; + +const silo: IAddress = { + [CHAIN.ETHEREUM]: [ + { + lens: "0x0e466FC22386997daC23D1f89A43ecb2CB1e76E9", + factory: [ + { + address: "0x4D919CEcfD4793c0D47866C8d0a02a0950737589", + block: 15307294, + }, + { + address: "0x6d4A256695586F61b77B09bc3D28333A91114d5a", + block: 17391885, + }, + ], + }, + { + lens: "0x32a4Bcd8DEa5E18a12a50584682f8E4B77fFF2DF", + factory: { + address: "0x2c0fA05281730EFd3ef71172d8992500B36b56eA", + block: 17782576, + }, + }, + ], + [CHAIN.ARBITRUM]: [ + { + lens: "0xBDb843c7a7e48Dc543424474d7Aa63b61B5D9536", + factory: { + address: "0x4166487056A922D784b073d4d928a516B074b719", + block: 51894508, + }, + }, + ], + [CHAIN.OPTIMISM]: [ + { + lens: "0xd3De080436b9d38DC315944c16d89C050C414Fed", + factory: { + address: "0x6B14c4450a29Dd9562c20259eBFF67a577b540b9", + block: 120480601, + }, + }, + ], + [CHAIN.BASE]: [ + { + lens: "0x196D312fd81412B6443620Ca81B41103b4E123FD", + factory: { + address: "0x408822E4E8682413666809b0655161093cd36f2b", + block: 16262586, + }, + }, + ], +}; + +async function getSilos( + silos: ISilo[], + { getLogs }: FetchOptions +): Promise { + const logs: any = []; + + const fetchLogsFromFactory = async (address: string, block: number) => { + const logChunk = await getLogs({ + target: address, + fromBlock: block, + eventAbi: + "event NewSiloCreated(address indexed silo, address indexed asset, uint128 version)", + }); + + logs.push(logChunk.map((result) => result[0])); + }; + + for (const { factory } of silos) { + if (Array.isArray(factory)) { + for (const { address, block } of factory) { + await fetchLogsFromFactory(address, block); + } + } else { + const { address, block } = factory; + await fetchLogsFromFactory(address, block); + } + } + + return silos.map((silo, index) => ({ + ...silo, + silos: logs[index]?.map((siloAddress: string) => ({ + silo: siloAddress, + assets: [], + })), + })); +} + +async function getSilosAssets( + silos: ISilo[], + { api }: FetchOptions +): Promise { + const siloAddresses = silos.flatMap((silo) => + (silo.silos || []).map((s) => ({ target: s.silo })) + ); + + const assetsInSilosRes = await api.multiCall({ + calls: siloAddresses, + abi: "function getAssets() view returns (address[] assets)", + }); + + const assetsMap: { [key: string]: string[] } = {}; + siloAddresses.forEach((call, index) => { + assetsMap[call.target] = assetsInSilosRes[index]; + }); + + return silos.map((silo) => ({ + ...silo, + silos: (silo.silos || []).map((s) => ({ + silo: s.silo, + assets: assetsMap[s.silo] || [], + })), + })); +} + +async function getSilosFeesStorage( + rawSilos: ISilo[], + { fromApi, toApi }: FetchOptions +): Promise<{ totalFeesResults: FeeResult[]; dailyFeesResults: FeeResult[] }> { + const totalFeesResults: FeeResult[] = []; + const dailyFeesResults: FeeResult[] = []; + + const calls = rawSilos.flatMap((silo) => + (silo.silos || []).flatMap(({ silo: siloAddress, assets }) => + assets.map((asset) => ({ + target: silo.lens, + params: [siloAddress, asset], + })) + ) + ); + + const [prevFeesInSilosRes, currFeesInSilosRes] = await Promise.all([ + fromApi.multiCall({ + calls: calls, + abi: "function protocolFees(address _silo, address _asset) view returns (uint256)", + permitFailure: true, + }), + toApi.multiCall({ + calls: calls, + abi: "function protocolFees(address _silo, address _asset) view returns (uint256)", + permitFailure: true, + }), + ]); + + calls.forEach((call, index) => { + const [_siloAddress, asset] = call.params; + const prevFee = prevFeesInSilosRes[index]; + const currFee = currFeesInSilosRes[index]; + + if (!prevFee || !currFee) return; + totalFeesResults.push({ asset, fee: currFee }); + dailyFeesResults.push({ asset, fee: BigInt(currFee - prevFee) }); + }); + + return { totalFeesResults, dailyFeesResults }; +} + +async function fetch( + options: FetchOptions, + rawSilos: ISilo[] +): Promise { + const totalFees = options.createBalances(); + const dailyFees = options.createBalances(); + + const rawSiloWithAddresses = await getSilos(rawSilos, options); + const siloWithAssets = await getSilosAssets(rawSiloWithAddresses, options); + const { totalFeesResults, dailyFeesResults } = await getSilosFeesStorage( + siloWithAssets, + options + ); + + totalFeesResults.forEach(({ asset, fee }) => { + totalFees.add(asset, fee); + }); + + dailyFeesResults.forEach(({ asset, fee }) => { + dailyFees.add(asset, fee); + }); + + return { totalFees, dailyFees }; +} + +const adapter: Adapter = { + adapter: { + [CHAIN.ETHEREUM]: { + fetch: (options: FetchOptions) => fetch(options, silo[CHAIN.ETHEREUM]), + start: 1660150409, + }, + [CHAIN.ARBITRUM]: { + fetch: (options: FetchOptions) => fetch(options, silo[CHAIN.ARBITRUM]), + start: 1683046409, + }, + [CHAIN.OPTIMISM]: { + fetch: (options: FetchOptions) => fetch(options, silo[CHAIN.OPTIMISM]), + start: 1716656009, + }, + [CHAIN.BASE]: { + fetch: (options: FetchOptions) => fetch(options, silo[CHAIN.BASE]), + start: 1719420809, + }, + }, + version: 2, +}; + +export default adapter; diff --git a/fees/size-credit.ts b/fees/size-credit.ts new file mode 100644 index 0000000000..dbe94b9394 --- /dev/null +++ b/fees/size-credit.ts @@ -0,0 +1,70 @@ +import ADDRESSES from '../helpers/coreAssets.json'; +import { Adapter, FetchOptions } from "../adapters/types"; +import { CHAIN } from "../helpers/chains"; + +const SZWETH_CONTRACT = '0x974583f05de1fd18c59c77c4a8803cf0c7db5333'; +const SZAUSDC_CONTRACT = '0x38978038a06a21602a4202dfa66968e7f525bf3e'; +const AUSDC_CONTRACT = '0x4e65fe4dba92790696d040ac24aa414708f5c0ab'; +const SIZE_PROXY_CONTRACT = '0xC2a429681CAd7C1ce36442fbf7A4a68B11eFF940'; + +const fetch: any = async ({ createBalances, getLogs, api, getFromBlock, getToBlock }: FetchOptions) => { + const fees = createBalances() + const [fromBlock, toBlock] = await Promise.all([getFromBlock(), getToBlock()]) + const FEE_MAPPING = [ + ADDRESSES.base.WETH, + AUSDC_CONTRACT + ] + const logsArray = await Promise.all([ + getLogs({ + target: SZWETH_CONTRACT, + eventAbi: "event Transfer(address indexed from, address indexed to, uint256 value)", + fromBlock, + toBlock + }), + getLogs({ + target: SZAUSDC_CONTRACT, + eventAbi: "event TransferUnscaled(address indexed from, address indexed to, uint256 value)", + fromBlock, + toBlock + }) + ]) + const feeConfig = await api.call({ + target: SIZE_PROXY_CONTRACT, + abi: "function feeConfig() view returns (uint256 swapFeeAPR, uint256 fragmentationFee, uint256 liquidationRewardPercent, uint256 overdueCollateralProtocolPercent, uint256 collateralProtocolPercent, address feeRecipient)", + params: [], + }); + const feeRecipient = feeConfig.feeRecipient; + logsArray.forEach((logs, i) => { + logs.forEach((log) => { + if (log.to.toLowerCase() === feeRecipient.toLowerCase()) { + fees.add(FEE_MAPPING[i], Number(log.value)); + } + }) + }) + console.log(await fees.getUSDJSONs()) + + return { + dailyFees: fees, + dailyRevenue: fees, + dailyProtocolRevenue: fees + }; +}; + +const methodology = "Swap fees are applied on every cash-for-credit trade, and fragmentation fees are charged on every credit split" + +const adapter: Adapter = { + version: 2, + adapter: { + [CHAIN.BASE]: { + fetch, + start: 1721083903, + meta: { + methodology: { + Fees: methodology, + ProtocolRevenue: methodology + } + } + }, + } +} +export default adapter; diff --git a/fees/stargate.ts b/fees/stargate.ts index 02ee411e13..fe6685da78 100644 --- a/fees/stargate.ts +++ b/fees/stargate.ts @@ -1,68 +1,143 @@ -import ADDRESSES from '../helpers/coreAssets.json' -import { Adapter, ChainBlocks, FetchOptions, FetchResultFees } from "../adapters/types"; -import { CHAIN } from "../helpers/chains"; import { Chain } from "@defillama/sdk/build/general"; +import { + Adapter, + ChainBlocks, + FetchOptions, + FetchResultFees, +} from "../adapters/types"; +import { CHAIN } from "../helpers/chains"; +import ADDRESSES from "../helpers/coreAssets.json"; -const event0_swap = 'event Swap(uint16 chainId,uint256 dstPoolId,address from,uint256 amountSD,uint256 eqReward,uint256 eqFee,uint256 protocolFee,uint256 lpFee)' -const event0_swap_remote = 'event SwapRemote( address to,uint256 amountSD,uint256 protocolFee,uint256 dstFee)' +const event0_swap = + "event Swap(uint16 chainId,uint256 dstPoolId,address from,uint256 amountSD,uint256 eqReward,uint256 eqFee,uint256 protocolFee,uint256 lpFee)"; +const event0_swap_remote = + "event SwapRemote( address to,uint256 amountSD,uint256 protocolFee,uint256 dstFee)"; type IAddress = { [s: string | Chain]: string[]; -} +}; const contract_address: IAddress = { [CHAIN.ETHEREUM]: [ - '0xdf0770dF86a8034b3EFEf0A1Bb3c889B8332FF56', - '0x38EA452219524Bb87e18dE1C24D3bB59510BD783', - '0x101816545F6bd2b1076434B54383a1E633390A2E', + "0x101816545f6bd2b1076434b54383a1e633390a2e", + "0x101816545F6bd2b1076434B54383a1E633390A2E", + "0xdf0770dF86a8034b3EFEf0A1Bb3c889B8332FF56", + "0x38ea452219524bb87e18de1c24d3bb59510bd783", + "0x692953e758c3669290cb1677180c64183cEe374e", + "0x0Faf1d2d3CED330824de3B8200fc8dc6E397850d", + "0xfA0F307783AC21C39E939ACFF795e27b650F6e68", + "0x590d4f8A68583639f215f675F3a259Ed84790580", + "0xE8F55368C82D38bbbbDb5533e7F56AfC2E978CC2", + "0x9cef9a0b1be0d289ac9f4a98ff317c33eaa84eb8", + "0xd8772edBF88bBa2667ed011542343b0eDDaCDa47", + "0x430Ebff5E3E80A6C58E7e6ADA1d90F5c28AA116d", + "0xa572d137666dcbadfa47c3fc41f15e90134c618c", ], [CHAIN.ARBITRUM]: [ - '0x892785f33CdeE22A30AEF750F285E18c18040c3e', - '0xB6CfcF89a7B22988bfC96632aC2A9D6daB60d641', - '0x915A55e36A01285A14f05dE6e81ED9cE89772f8e', + "0x915A55e36A01285A14f05dE6e81ED9cE89772f8e", + "0x892785f33CdeE22A30AEF750F285E18c18040c3e", + "0xB6CfcF89a7B22988bfC96632aC2A9D6daB60d641", + "0xaa4BF442F024820B2C28Cd0FD72b82c63e66F56C", + "0xF39B7Be294cB36dE8c510e267B82bb588705d977", + "0x600E576F9d853c95d58029093A16EE49646F3ca5", ], [CHAIN.AVAX]: [ - '0x1205f31718499dBf1fCa446663B532Ef87481fe1', - '0x29e38769f23701A2e4A8Ef0492e19dA4604Be62c', + "0x1205f31718499dBf1fCa446663B532Ef87481fe1", + "0x29e38769f23701A2e4A8Ef0492e19dA4604Be62c", + "0x1c272232Df0bb6225dA87f4dEcD9d37c32f63Eea", + "0x8736f92646B2542B3e5F3c63590cA7Fe313e283B", + "0xEAe5c2F6B25933deB62f754f239111413A0A25ef", ], [CHAIN.BSC]: [ - '0x9aA83081AA06AF7208Dcc7A4cB72C94d057D2cda', - '0x98a5737749490856b401DB5Dc27F522fC314A4e1', - ], - [CHAIN.FANTOM]: [ - '0x12edeA9cd262006cC3C4E77c90d2CD2DD4b1eb97' + "0x9aA83081AA06AF7208Dcc7A4cB72C94d057D2cda", + "0x98a5737749490856b401DB5Dc27F522fC314A4e1", + "0x4e145a589e4c03cBe3d28520e4BF3089834289Df", + "0x7BfD7f2498C4796f10b6C611D9db393D3052510C", + "0x68C6c27fB0e02285829e69240BE16f32C5f8bEFe", ], + [CHAIN.FANTOM]: ["0x12edeA9cd262006cC3C4E77c90d2CD2DD4b1eb97"], [CHAIN.OPTIMISM]: [ - '0xDecC0c09c3B5f6e92EF4184125D5648a66E35298', - '0xd22363e3762cA7339569F3d33EADe20127D5F98C', + "0xd22363e3762cA7339569F3d33EADe20127D5F98C", + "0x165137624F1f692e69659f944BF69DE02874ee27", + "0x368605D9C6243A80903b9e326f1Cddde088B8924", + "0x2F8bC9081c7FCFeC25b9f41a50d97EaA592058ae", + "0x3533F5e279bDBf550272a199a223dA798D9eff78", + "0x5421FA1A48f9FF81e4580557E86C7C0D24C18036", ], [CHAIN.POLYGON]: [ - '0x1205f31718499dBf1fCa446663B532Ef87481fe1', - '0x29e38769f23701A2e4A8Ef0492e19dA4604Be62c', - ] -} + "0x1205f31718499dBf1fCa446663B532Ef87481fe1", + "0x29e38769f23701A2e4A8Ef0492e19dA4604Be62c", + "0x1c272232Df0bb6225dA87f4dEcD9d37c32f63Eea", + "0x8736f92646B2542B3e5F3c63590cA7Fe313e283B", + ], + [CHAIN.METIS]: [ + "0xAad094F6A75A14417d39f04E690fC216f080A41a", + "0x2b60473a7C41Deb80EDdaafD5560e963440eb632", + ], + [CHAIN.BASE]: [ + "0x28fc411f9e1c480AD312b3d9C60c22b965015c6B", + "0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca", + ], + [CHAIN.LINEA]: ["0xAad094F6A75A14417d39f04E690fC216f080A41a"], + [CHAIN.KAVA]: ["0xAad094F6A75A14417d39f04E690fC216f080A41a"], + [CHAIN.MANTLE]: [ + "0xAad094F6A75A14417d39f04E690fC216f080A41a", + "0x2b60473a7C41Deb80EDdaafD5560e963440eb632", + "0xf52b354FFDB323E0667E87a0136040e3e4D9dF33", + ], +}; type IMap = { [s: string]: string; -} +}; const mapTokenPrice: IMap = { - ['0x101816545f6bd2b1076434b54383a1e633390a2e'.toLowerCase()]: ADDRESSES.null, - ['0x915a55e36a01285a14f05de6e81ed9ce89772f8e'.toLowerCase()]: ADDRESSES.null, - ['0xd22363e3762ca7339569f3d33eade20127d5f98c'.toLowerCase()]: ADDRESSES.null, -} + ["0x101816545f6bd2b1076434b54383a1e633390a2e".toLowerCase()]: ADDRESSES.null, + ["0xa572d137666dcbadfa47c3fc41f15e90134c618c".toLowerCase()]: ADDRESSES.null, + ["0x915a55e36a01285a14f05de6e81ed9ce89772f8e".toLowerCase()]: ADDRESSES.null, + ["0xd22363e3762ca7339569f3d33eade20127d5f98c".toLowerCase()]: ADDRESSES.null, + ["0x28fc411f9e1c480AD312b3d9C60c22b965015c6B".toLowerCase()]: ADDRESSES.null, + ["0xAad094F6A75A14417d39f04E690fC216f080A41a".toLowerCase()]: ADDRESSES.null, + ["0xf52b354FFDB323E0667E87a0136040e3e4D9dF33".toLowerCase()]: ADDRESSES.null, +}; const fetch = (chain: Chain) => { - return async (timestamp: number, _: ChainBlocks, { createBalances, getLogs }: FetchOptions): Promise => { - const dailyFees = createBalances() - const transform = (a: string) => mapTokenPrice[a.toLowerCase()] ?? a - const logs = await getLogs({ targets: contract_address[chain], eventAbi: event0_swap, flatten: false, }) - const logs_swap_remote = await getLogs({ targets: contract_address[chain], eventAbi: event0_swap_remote, flatten: false }) - logs.forEach((_: any, index: number) => _.forEach((log: any) => dailyFees.add(transform(contract_address[chain][index]), log.protocolFee))) - logs_swap_remote.forEach((_: any, index: number) => _.forEach((log: any) => dailyFees.add(transform(contract_address[chain][index]), log.protocolFee))) - return { dailyFees, dailyRevenue: dailyFees, timestamp, } - } -} + return async ( + timestamp: number, + _: ChainBlocks, + { createBalances, getLogs }: FetchOptions + ): Promise => { + const dailyFees = createBalances(); + const transform = (a: string) => mapTokenPrice[a.toLowerCase()] ?? a; + const logs = await getLogs({ + targets: contract_address[chain], + eventAbi: event0_swap, + flatten: false, + }); + const logs_swap_remote = await getLogs({ + targets: contract_address[chain], + eventAbi: event0_swap_remote, + flatten: false, + }); + logs.forEach((_: any, index: number) => + _.forEach((log: any) => + dailyFees.add( + transform(contract_address[chain][index]), + log.protocolFee + ) + ) + ); + logs_swap_remote.forEach((_: any, index: number) => + _.forEach((log: any) => + dailyFees.add( + transform(contract_address[chain][index]), + log.protocolFee + ) + ) + ); + return { dailyFees, dailyRevenue: dailyFees, timestamp }; + }; +}; const adapter: Adapter = { adapter: { @@ -94,7 +169,27 @@ const adapter: Adapter = { fetch: fetch(CHAIN.POLYGON), start: 1661990400, }, - } -} + [CHAIN.METIS]: { + fetch: fetch(CHAIN.METIS), + start: 1661990400, + }, + [CHAIN.BASE]: { + fetch: fetch(CHAIN.BASE), + start: 1661990400, + }, + [CHAIN.LINEA]: { + fetch: fetch(CHAIN.LINEA), + start: 1661990400, + }, + [CHAIN.MANTLE]: { + fetch: fetch(CHAIN.MANTLE), + start: 1661990400, + }, + [CHAIN.KAVA]: { + fetch: fetch(CHAIN.KAVA), + start: 1661990400, + }, + }, +}; export default adapter; diff --git a/fees/stbot.ts b/fees/stbot.ts new file mode 100644 index 0000000000..55b49fdb8b --- /dev/null +++ b/fees/stbot.ts @@ -0,0 +1,27 @@ +import { FetchOptions, SimpleAdapter } from "../adapters/types"; +import { CHAIN } from "../helpers/chains"; +import { queryDune } from "../helpers/dune"; + +const fetch: any = async (options: FetchOptions) => { + const dailyFees = options.createBalances(); + const value = (await queryDune("3929011", { + start: options.startTimestamp, + end: options.endTimestamp, + })); + dailyFees.add('So11111111111111111111111111111111111111112', value[0].fee_token_amount); + + return { dailyFees, dailyRevenue: dailyFees } +} + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.SOLANA]: { + fetch: fetch, + start: 0, + }, + }, + isExpensiveAdapter: true +}; + +export default adapter; \ No newline at end of file diff --git a/fees/surfone/index.ts b/fees/surfone/index.ts index 365fff81e4..1c2fb1a101 100644 --- a/fees/surfone/index.ts +++ b/fees/surfone/index.ts @@ -1,4 +1,4 @@ -import { SimpleAdapter } from "../../adapters/types"; +import {FetchOptions, SimpleAdapter} from "../../adapters/types"; import { getUniqStartOfTodayTimestamp } from "../../helpers/getUniSubgraphVolume"; import { httpGet } from "../../utils/fetchURL"; @@ -10,24 +10,25 @@ const headers = { "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" }; -interface IVolume { +interface IFee { + daily_fee: number, total_fee: number, } const fetch = () => { return async (timestamp: number) => { const dayTimestamp = getUniqStartOfTodayTimestamp(new Date(timestamp * 1000)) - const response = (await httpGet(volumeEndpointV2, { headers })); + const response = (await httpGet(volumeEndpointV2, {headers})); - const volume: IVolume = response.data; + const fee: IFee = response.data; return { - dailyFees: `${volume?.total_fee || undefined}`, + dailyFees: `${fee?.daily_fee || undefined}`, + totalFees: `${fee?.total_fee || undefined}`, timestamp: dayTimestamp, }; }; } - const adapter: SimpleAdapter = { version: 1, adapter: { diff --git a/fees/vela/index.ts b/fees/vela/index.ts index 9a45bd692b..3c6a0497c2 100644 --- a/fees/vela/index.ts +++ b/fees/vela/index.ts @@ -1,14 +1,16 @@ import * as sdk from "@defillama/sdk"; import { Adapter } from "../../adapters/types"; -import { ARBITRUM, AVAX } from "../../helpers/chains"; +import { CHAIN } from "../../helpers/chains"; import { request, gql } from "graphql-request"; import type { ChainEndpoints } from "../../adapters/types"; import { Chain } from "@defillama/sdk/build/general"; import { getTimestampAtStartOfDayUTC } from "../../utils/date"; const endpoints = { - [ARBITRUM]: - sdk.graph.modifyEndpoint('6H9PEiNPZgwXfpbijjesZh96LFBzUvkHmEutMoYQ9fvp'), + [CHAIN.ARBITRUM]: + sdk.graph.modifyEndpoint('https://api.goldsky.com/api/public/project_clu01p4nr68r301pze2tj4sh7/subgraphs/vela-arbitrum/mainnet/gn'), + [CHAIN.BASE]: + sdk.graph.modifyEndpoint('https://api.goldsky.com/api/public/project_clu01p4nr68r301pze2tj4sh7/subgraphs/vela-base/mainnet/gn') }; const methodology = { @@ -39,13 +41,20 @@ const graphs = (graphUrls: ChainEndpoints) => { const adapter: Adapter = { version: 1, adapter: { - [ARBITRUM]: { - fetch: graphs(endpoints)(ARBITRUM), + [CHAIN.ARBITRUM]: { + fetch: graphs(endpoints)(CHAIN.ARBITRUM), start: 1687806000, meta: { methodology, }, }, + [CHAIN.BASE]: { + fetch: graphs(endpoints)(CHAIN.BASE), + start: 1693785600, + meta: { + methodology, + }, + } }, }; diff --git a/fees/yfx-v4.ts b/fees/yfx-v4.ts index cb7bf618a4..94fc63fd02 100644 --- a/fees/yfx-v4.ts +++ b/fees/yfx-v4.ts @@ -6,7 +6,8 @@ import { Chain } from '@defillama/sdk/build/general'; import { getTimestampAtStartOfDayUTC } from "../utils/date"; const endpoints: { [key: string]: string } = { - [CHAIN.ARBITRUM]: "https://graph-v4.yfx.com/yfx_v4" + [CHAIN.ARBITRUM]: "https://graph-v4.yfx.com/yfx_v4", + [CHAIN.BASE]: "https://graph-v4.yfx.com/yfx_v4_base", } const methodology = { @@ -70,6 +71,13 @@ const adapter: Adapter = { methodology } }, + [CHAIN.BASE]: { + fetch: graphs(endpoints)(CHAIN.BASE), + start: async () => 1721001600, + meta: { + methodology + } + }, } } diff --git a/fees/zns/index.ts b/fees/zns/index.ts new file mode 100644 index 0000000000..4426cb0ee4 --- /dev/null +++ b/fees/zns/index.ts @@ -0,0 +1,174 @@ +import type { Balances } from "@defillama/sdk"; +import { Adapter, FetchOptions } from "../../adapters/types"; +import { CHAIN } from "../../helpers/chains"; + +const abi_event = { + mintedDomain: "event MintedDomain(string domainName,uint256 indexed tokenId,address indexed owner,uint256 indexed expiry)", + renewedDomain: "event RenewedDomain(uint256 indexed tokenId,uint256 indexed expiry,string domainName)", +}; + +type TAddress = { + [s: string]: string; +}; +const addresses: TAddress = { + [CHAIN.BSC]: "0x7e2cf06f092c9f5cf5972ef021635b6c8e1c5bb2", + [CHAIN.SCROLL]: "0xB00910Bac7DA44c0D440798809dbF8d51FDBb635", + [CHAIN.BLAST]: "0x59B9Ac688e39A14b938AC8C3269db66D8aDB9aF6", + [CHAIN.POLYGON]: "0x8ccD9c0A9C084412416A85Fd748c7f1E9b86442D", + [CHAIN.TAIKO]: "0xFb2Cd41a8aeC89EFBb19575C6c48d872cE97A0A5", + [CHAIN.XLAYER]: "0x71709a5f1831ba48c414375fb6a58662a40c01b5", + [CHAIN.ZORA]: "0xf180136DdC9e4F8c9b5A9FE59e2b1f07265C5D4D", + [CHAIN.BOBA]: "0xf1D09DA87c50820eD3b924aFf3C37058eD6eA40e", + [CHAIN.ZKLINK]: "0xe0971a2B6E34bd060866081aE879630e83C4A0BD", +}; + +const methodology = { + Fees: "registration and renew cost", + Revenue: "registration and renew cost", +}; + +const ABI = { + priceToRegister: { + inputs: [{ internalType: "uint16", name: "len", type: "uint16" }], + name: "priceToRegister", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + priceToRenew: { + inputs: [{ internalType: "uint16", name: "len", type: "uint16" }], + name: "priceToRenew", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +} + +const fetchLogsAndCalculateFees = async ( + options: FetchOptions, +): Promise<{ dailyFees: Balances; dailyRevenue: Balances }> => { + const address = addresses[options.chain]; + const dailyFees = options.createBalances(); + + const mintedLogs = await options.getLogs({ + target: address, + eventAbi: abi_event.mintedDomain, + }); + + const renewedLogs = await options.getLogs({ + target: address, + eventAbi: abi_event.renewedDomain, + }); + const lens = [1,2,3,4,5] + + const znsPriceRegistor = await options.api.multiCall({ + abi: ABI.priceToRegister, + calls: lens.map(len=>({ + params: [len], + target: address + })) + }); + + const znsPriceRenew = await options.api.multiCall({ + abi: ABI.priceToRenew, + calls: lens.map(len=>({ + params: [len], + target: address + })), + }); + + mintedLogs.forEach((log) => { + const domainName = log.domainName; + let domainPrice = 0; + if (domainName.length === 1) domainPrice = znsPriceRegistor[0]; + else if (domainName.length === 2) domainPrice = znsPriceRegistor[1]; + else if (domainName.length === 3) domainPrice = znsPriceRegistor[2]; + else if (domainName.length === 4) domainPrice = znsPriceRegistor[3]; + else domainPrice = znsPriceRegistor[4]; + dailyFees.addGasToken(domainPrice); + }); + + renewedLogs.forEach((log) => { + const domainName = log.domainName; + let domainPrice = 0; + if (domainName.length === 1) domainPrice = znsPriceRenew[0]; + else if (domainName.length === 2) domainPrice = znsPriceRenew[1]; + else if (domainName.length === 3) domainPrice = znsPriceRenew[2]; + else if (domainName.length === 4) domainPrice = znsPriceRenew[3]; + else domainPrice = znsPriceRenew[4]; + dailyFees.addGasToken(domainPrice); + }); + + return { dailyFees, dailyRevenue: dailyFees }; +}; + +const adapter: Adapter = { + version: 2, + adapter: { + [CHAIN.BSC]: { + fetch: fetchLogsAndCalculateFees, + start: 1714506194, + meta: { + methodology, + }, + }, + [CHAIN.SCROLL]: { + fetch: fetchLogsAndCalculateFees, + start: 1714773760, + meta: { + methodology, + }, + }, + [CHAIN.BLAST]: { + fetch: fetchLogsAndCalculateFees, + start: 1717180581, + meta: { + methodology, + }, + }, + [CHAIN.POLYGON]: { + fetch: fetchLogsAndCalculateFees, + start: 1717195742, + meta: { + methodology, + }, + }, + [CHAIN.TAIKO]: { + fetch: fetchLogsAndCalculateFees, + start: 1717048139, + meta: { + methodology, + }, + }, + [CHAIN.XLAYER]: { + fetch: fetchLogsAndCalculateFees, + start: 1713379405, + meta: { + methodology, + }, + }, + [CHAIN.ZORA]: { + fetch: fetchLogsAndCalculateFees, + start: 1719239283, + meta: { + methodology, + }, + }, + [CHAIN.BOBA]: { + fetch: fetchLogsAndCalculateFees, + start: 1719631449, + meta: { + methodology, + }, + }, + [CHAIN.ZKLINK]: { + fetch: fetchLogsAndCalculateFees, + start: 1719631449, + meta: { + methodology, + }, + }, + }, +}; + +export default adapter; diff --git a/helpers/chains.ts b/helpers/chains.ts index 424fcd0187..38e1556ee2 100644 --- a/helpers/chains.ts +++ b/helpers/chains.ts @@ -157,7 +157,9 @@ export enum CHAIN { PLANQ = "planq", BOB = "bob", TAIKO = "taiko", - SKALE_EUROPA = "skale_europa" + SKALE_EUROPA = "skale_europa", + IOTAEVM = "iotaevm", + ZKLINK = "zklink", } // DonĀ“t use @@ -184,25 +186,25 @@ const ZKSYNC = "zksync"; const MANTLE = "mantle"; // Don't use export { - ZKSYNC, ARBITRUM, + AURORA, AVAX, + BITCOIN, BOBA, BSC, CELO, + DOGE, ETHEREUM, FANTOM, HARMONY, HECO, + LITECOIN, + MANTLE, + MOONRIVER, OKEXCHAIN, OPTIMISM, POLYGON, RONIN, XDAI, - AURORA, - MOONRIVER, - BITCOIN, - LITECOIN, - DOGE, - MANTLE + ZKSYNC, }; diff --git a/protocols/blasterswap-v3.ts b/protocols/blasterswap-v3.ts new file mode 100644 index 0000000000..33a62fd19f --- /dev/null +++ b/protocols/blasterswap-v3.ts @@ -0,0 +1,7 @@ +import { uniV3Exports } from "../helpers/uniswap"; + +export default uniV3Exports({ + blast: { + factory: '0x1A8027625C830aAC43aD82a3f7cD6D5fdCE89d78', + } +}) diff --git a/protocols/eddyfinance-v2.ts b/protocols/eddyfinance-v2.ts new file mode 100644 index 0000000000..419127fca9 --- /dev/null +++ b/protocols/eddyfinance-v2.ts @@ -0,0 +1,7 @@ +import { uniV2Exports } from "../helpers/uniswap"; + +export default uniV2Exports({ + zeta: { + factory: '0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c', + } +}) \ No newline at end of file diff --git a/protocols/uniswap/index.ts b/protocols/uniswap/index.ts index 5e16e7ac4b..1312f71932 100644 --- a/protocols/uniswap/index.ts +++ b/protocols/uniswap/index.ts @@ -307,7 +307,7 @@ interface ISeiResponse { } const fetchSei = async (options: FetchOptions) => { try { - const url = `https://omni.icarus.tools/${options.chain}/cush/analyticsProtocolHistoric`; + const url = `https://omni.icarus.tools/${mappingChain(options.chain)}/cush/analyticsProtocolHistoric`; const body = { "params": [ options.startTimestamp * 1000, //start @@ -327,6 +327,11 @@ const fetchSei = async (options: FetchOptions) => { return {} } } +const mappingChain = (chain: string) => { + if (chain === CHAIN.ERA) return "zksync" + if (chain === CHAIN.ROOTSTOCK) return "rootstock" + return chain +} adapter.breakdown.v3[CHAIN.SEI] = { fetch: fetchSei, @@ -335,5 +340,84 @@ adapter.breakdown.v3[CHAIN.SEI] = { methodology } } +adapter.breakdown.v3[CHAIN.ERA] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.TAIKO] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.SCROLL] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.ROOTSTOCK] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.FILECOIN] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.BOBA] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.MOONBEAM] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.MANTA] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.MANTLE] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} + +adapter.breakdown.v3[CHAIN.LINEA] = { + fetch: fetchSei, + start: 0, + meta: { + methodology + } +} export default adapter; diff --git a/users/routers/routerAddresses.ts b/users/routers/routerAddresses.ts index 0eed04ee78..e3de6e6d92 100644 --- a/users/routers/routerAddresses.ts +++ b/users/routers/routerAddresses.ts @@ -4,6 +4,19 @@ import { ProtocolAddresses } from "../utils/types"; export default ( [ + { + "id":"4674", + "name":"YFX V4", + "addresses":{ + "arbitrum":[ + "0x5aCf0eBC782c9845b7E74367B14D3B867360efD2", // router + "0xA1dBE14b978541b24C4E88489b8e463094F88dEB" // rewardRouter + ], + "base": [ + "0xbb1ACaA188337Fb662aE0631B2C537f29D4F9C85", // router + ] + } + }, { id: "3429", name: "YFX",