diff --git a/fees/frankencoin/index.ts b/fees/frankencoin/index.ts new file mode 100644 index 0000000000..39b145c078 --- /dev/null +++ b/fees/frankencoin/index.ts @@ -0,0 +1,103 @@ +import { FetchOptions, SimpleAdapter } from '../../adapters/types'; +import { CHAIN } from '../../helpers/chains'; +import { request, gql } from 'graphql-request'; + +// GraphQL endpoint for Frankencoin +const FRANKENCOIN_GRAPH_URL = 'https://ponder.frankencoin.com'; + +// ZCHF token address on Ethereum +const ZCHF_ADDRESS = '0xB58E61C3098d85632Df34EecfB899A1Ed80921cB'; + +// query type +type RevenueQuery = { + chainId: number; + count: number; + created: number; + kind: string; + amount: bigint; + profits: bigint; + losses: bigint; +}; + +// fetch function +const fetch = async (options: FetchOptions) => { + const dailyFees = options.createBalances(); + const dailyRevenue = options.createBalances(); + const dailyProtocolRevenue = options.createBalances(); + const dailySupplySideRevenue = options.createBalances(); + + const PROFIT_LOSS_QUERY = gql` + query { + frankencoinProfitLosss( + where: { + created_gt: "${options.startTimestamp}", + created_lte: "${options.endTimestamp}", + } + orderBy: "count", + orderDirection: "desc", + limit: 1000, + ) { + items { + created + kind + amount + } + } + } + `; + + const { frankencoinProfitLosss } = await request( + FRANKENCOIN_GRAPH_URL, + PROFIT_LOSS_QUERY + ); + + const entries: RevenueQuery[] = frankencoinProfitLosss.items; + + const profits = entries.filter((e) => e.kind == 'Profit'); + const losses = entries.filter((e) => e.kind == 'Loss'); + + // accumulate + const accumProfits = profits.reduce((a, b) => { + return a + BigInt(b.amount); + }, 0n); + + const accumLosses = losses.reduce((a, b) => { + return a + BigInt(b.amount); + }, 0n); + + // Fees are the total profits in ZCHF + dailyFees.add(ZCHF_ADDRESS, accumProfits); + dailyRevenue.add(ZCHF_ADDRESS, accumProfits); + dailyProtocolRevenue.add(ZCHF_ADDRESS, accumProfits); + + // Interest paid by the protocol + dailySupplySideRevenue.add(ZCHF_ADDRESS, accumLosses); + + return { + dailyFees, + dailyRevenue, + dailyProtocolRevenue, + dailySupplySideRevenue, + }; +}; + +const adapter: SimpleAdapter = { + version: 2, + adapter: { + [CHAIN.ETHEREUM]: { + fetch, + start: '2023-10-28', + meta: { + methodology: { + Fees: 'Profits generated by the Frankencoin protocol (Frankencoin Pool Shares)', + Revenue: 'Net revenue is retained by the protocol', + ProtocolRevenue: 'Net revenue is retained by the protocol', + SupplySideRevenue: + 'Losses absorbed by the protocol, such as interest paid to lenders, auction shortfalls, and similar costs', + }, + }, + }, + }, +}; + +export default adapter;