|
| 1 | +/** |
| 2 | + * Echo Protocol Fee Adapter |
| 3 | + * |
| 4 | + * Note on duplicate transactions: |
| 5 | + * In v1/v2 factory contracts, deals often sent both deal funds and platform fees |
| 6 | + * to the fee receiver address in the same transaction. This created duplicate logs |
| 7 | + * that would artificially inflate fee calculations. To handle this, we track unique |
| 8 | + * transactions by combining address, transaction hash, and token as a key, and for |
| 9 | + * any duplicates we only count the transaction with the smallest amount (which |
| 10 | + * represents the actual platform fee, not the deal funds). |
| 11 | + * |
| 12 | + */ |
| 13 | + |
| 14 | +import { ethers } from "ethers" |
| 15 | +import { FetchOptions, SimpleAdapter } from "../../adapters/types" |
| 16 | +import { CHAIN } from "../../helpers/chains" |
| 17 | + |
| 18 | +// Echo protocol contract addresses |
| 19 | +const ECHO_v1_DEAL_FACTORY = '0x32885c0174FBd53A3BDf418408415c7bEF679810' |
| 20 | +const ECHO_v2_DEAL_FACTORY = '0x31a85750a7fd18b598e1bc6dc5561ad1ef694fc4' |
| 21 | +const ECHO_v3_DEAL_FACTORY = '0xB6D2c5dc2d181E0E1D031F2b3B76Ea8b678EAA46' |
| 22 | + |
| 23 | +const ECHO_FEE_RECEIVER = '0x395426cE9081aE5ceA3f9fBA3078B00f16E7aE21' |
| 24 | +const DEAL_FUNDS_WITHDRAWN_TOPIC = "0x7e63be7447cb592fc5a80b0ca7ceb813b777d8aa50ec5c00b89578b892b4b8e9" |
| 25 | + |
| 26 | +const fetchFees = async (options: FetchOptions) => { |
| 27 | + const fromBlock = await options.getBlock(options.fromTimestamp, options.chain, {}) |
| 28 | + const toBlock = await options.getBlock(options.toTimestamp, options.chain, {}) |
| 29 | + // const fromBlock = 15111743 |
| 30 | + // const toBlock = 28654931 |
| 31 | + |
| 32 | + const logs = await options.getLogs({ |
| 33 | + eventAbi: "event DealFundsWithdrawn (address indexed token, address indexed to, uint256 amount)", |
| 34 | + topics: [DEAL_FUNDS_WITHDRAWN_TOPIC, null as any, ethers.zeroPadValue(ECHO_FEE_RECEIVER, 32)], |
| 35 | + fromBlock, |
| 36 | + toBlock, |
| 37 | + entireLog: true, |
| 38 | + skipIndexer: true, |
| 39 | + noTarget: true, |
| 40 | + }) |
| 41 | + |
| 42 | + const uniqueFees = new Map<string, { token: string, amount: bigint }>(); |
| 43 | + |
| 44 | + // Process each log, keeping only the platform fee portion |
| 45 | + for (const log of logs) { |
| 46 | + const token = '0x' + log.topics[1].slice(26); |
| 47 | + const amount = BigInt(log.data); |
| 48 | + const key = `${log.address.toLowerCase()}_${log.transactionHash.toLowerCase()}_${token}`; |
| 49 | + if (!uniqueFees.has(key) || amount < uniqueFees.get(key)!.amount) { |
| 50 | + uniqueFees.set(key, { token, amount }); |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + const dailyFees = options.createBalances(); |
| 55 | + for (const { token, amount } of uniqueFees.values()) { |
| 56 | + dailyFees.add(token, amount); |
| 57 | + } |
| 58 | + |
| 59 | + return { |
| 60 | + dailyFees, |
| 61 | + dailyRevenue: dailyFees, |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +const adapter: SimpleAdapter = { |
| 66 | + version: 2, |
| 67 | + adapter: { |
| 68 | + [CHAIN.BASE]: { |
| 69 | + fetch: fetchFees, |
| 70 | + start: '2024-03-27', |
| 71 | + meta: { |
| 72 | + methodology: { |
| 73 | + Fees: "Platform fees collected by Echo protocol from each deal" |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +export default adapter |
0 commit comments