|
1 | | - |
2 | | -import { CHAIN } from "../helpers/chains"; |
3 | 1 | import { Adapter, FetchOptions } from "../adapters/types"; |
| 2 | +import { CHAIN } from "../helpers/chains"; |
4 | 3 |
|
5 | | -const TREASURY = "0x21ad6eF3979638d8e73747f22B92C4AadE145D82"; |
| 4 | +const TREASURY = "0x21ad6ef3979638d8e73747f22b92c4aade145d82".toLowerCase(); |
6 | 5 |
|
7 | 6 | const CHAINS: Array<string> = [ |
8 | 7 | CHAIN.ETHEREUM, CHAIN.BASE, CHAIN.OPTIMISM, CHAIN.ARBITRUM, CHAIN.POLYGON, CHAIN.BSC, |
9 | | - CHAIN.SCROLL, CHAIN.MANTLE, CHAIN.LINEA, CHAIN.ERA, CHAIN.TAIKO, CHAIN.BLAST, CHAIN.MODE, CHAIN.ZORA, CHAIN.METIS, |
10 | | - CHAIN.CRONOS, CHAIN.CELO, CHAIN.CONFLUX, CHAIN.RONIN, CHAIN.LISK, CHAIN.BERACHAIN, CHAIN.CORE, CHAIN.BOB, |
11 | | - CHAIN.ABSTRACT, CHAIN.SONEIUM, CHAIN.INK, CHAIN.UNICHAIN, CHAIN.PLUME, CHAIN.SONIC, |
| 8 | + CHAIN.SCROLL, CHAIN.MANTLE, CHAIN.LINEA, CHAIN.ERA, CHAIN.TAIKO, CHAIN.BLAST, CHAIN.MODE, |
| 9 | + CHAIN.ZORA, CHAIN.METIS, CHAIN.REDSTONE, CHAIN.XDAI, CHAIN.APECHAIN, CHAIN.XLAYER, CHAIN.BOTANIX, |
| 10 | + CHAIN.CRONOS, CHAIN.CELO, CHAIN.CONFLUX, CHAIN.RONIN, CHAIN.LISK, CHAIN.BERACHAIN, CHAIN.CORE, |
| 11 | + CHAIN.BOB, CHAIN.ZIRCUIT, CHAIN.MORPH, CHAIN.MANTA, CHAIN.ANCIENT8, CHAIN.TAIKO, |
| 12 | + CHAIN.POLYGON_ZKEVM, CHAIN.WC, CHAIN.KLAYTN, CHAIN.ABSTRACT, CHAIN.SONEIUM, CHAIN.INK, |
| 13 | + CHAIN.UNICHAIN, CHAIN.PLUME, CHAIN.SONIC |
12 | 14 | ] |
13 | 15 |
|
14 | | -async function fetch(options: FetchOptions) { |
15 | | - const dailyFees = options.createBalances(); |
| 16 | +const COUNTERS: Record<string, string[]> = { |
| 17 | + [CHAIN.BASE]: [ |
| 18 | + "0x8fc7aa44971a7b111017fc435ef6daf10bf1b887", |
| 19 | + "0x8ccd9c0a9c084412416a85fd748c7f1e9b86442d", |
| 20 | + ], |
| 21 | + [CHAIN.LINEA]: [ |
| 22 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 23 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 24 | + ], |
| 25 | + [CHAIN.SCROLL]: [ |
| 26 | + "0x064dacc2f126f036d77cd4b8887efedb2f5201fe", |
| 27 | + "0x53092f84ef2460d8517f011f7722125758de5aa2", |
| 28 | + ], |
| 29 | + [CHAIN.MANTLE]: [ |
| 30 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 31 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 32 | + ], |
| 33 | + [CHAIN.CRONOS]: [ |
| 34 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 35 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 36 | + ], |
| 37 | + [CHAIN.CELO]: [ |
| 38 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 39 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 40 | + ], |
| 41 | + [CHAIN.BSC]: [ |
| 42 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 43 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 44 | + ], |
| 45 | + [CHAIN.ABSTRACT]: [ |
| 46 | + "0xe94158b16cd46b190f74a2ccbff7fdecf0da8bf4", |
| 47 | + "0xefb45cd4cff4d11d4b029659e618daacd8d18f3", |
| 48 | + ], |
| 49 | + [CHAIN.KLAYTN]: [ |
| 50 | + "0x5fcea004bc26308bc91d8599dba4a271c57cba85", |
| 51 | + "0x72fe6c968d0da46f45e65923330a262a1f75963c", |
| 52 | + ], |
| 53 | + [CHAIN.BERACHAIN]: [ |
| 54 | + "0x2522bfee6451f7a1f64e3ab287d8cf46c173601f", |
| 55 | + "0x9cad0d6a8927cb0757f435b8e5ecb6b095862596", |
| 56 | + ], |
| 57 | + [CHAIN.OPTIMISM]: [ |
| 58 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 59 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 60 | + ], |
| 61 | + [CHAIN.UNICHAIN]: [ |
| 62 | + "0x30efc910a135d73016a788fdd9a9e8b022dea208", |
| 63 | + "0xff4e5275f5b1b69e94773fa4134be4c752c42705", |
| 64 | + ], |
| 65 | + [CHAIN.INK]: [ |
| 66 | + "0x3033d7ded400547d6442c55159da5c61f2721633", |
| 67 | + "0x63c489d31a2c3de0638360931f47ff066282473f", |
| 68 | + ], |
| 69 | + [CHAIN.SONEIUM]: [ |
| 70 | + "0x6baaa0653e53f92e11316973bfc1fc8291fc6f58", |
| 71 | + "0xdefe1db2713ba0c51334343dca576bd5f4e793b2", |
| 72 | + ], |
| 73 | + [CHAIN.BOB]: [ |
| 74 | + "0xc11ee6c94a86e18481d9206c29ecdd3b40c59898", |
| 75 | + "0x0246d65ba41da3db6db55e489146eb25ca3634e5", |
| 76 | + ], |
| 77 | + [CHAIN.PLUME]: [ |
| 78 | + "0x86683f28df33adcd1cadc815855102c1685731fc", |
| 79 | + "0x6e126d13a5451780401804f55cec3686192d29f7", |
| 80 | + ], |
| 81 | + [CHAIN.CONFLUX]: [ |
| 82 | + "0x649617c710776c6ac41be36eda94929654a685a7", |
| 83 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 84 | + ], |
| 85 | + [CHAIN.LISK]: [ |
| 86 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 87 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 88 | + ], |
| 89 | + [CHAIN.ZIRCUIT]: [ |
| 90 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 91 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 92 | + ], |
| 93 | + [CHAIN.METIS]: [ |
| 94 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 95 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 96 | + ], |
| 97 | + [CHAIN.ARBITRUM]: [ |
| 98 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 99 | + "0x6c8de6c102a844b885291d1ce1cafdacf0a553d8", |
| 100 | + ], |
| 101 | + [CHAIN.AVAX]: [ |
| 102 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 103 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 104 | + ], |
| 105 | + [CHAIN.SONIC]: [ |
| 106 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 107 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 108 | + ], |
| 109 | + [CHAIN.XDAI]: [ |
| 110 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 111 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 112 | + ], |
| 113 | + [CHAIN.TAIKO]: [ |
| 114 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 115 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 116 | + ], |
| 117 | + [CHAIN.APECHAIN]: [ |
| 118 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 119 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 120 | + ], |
| 121 | + [CHAIN.BLAST]: [ |
| 122 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 123 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 124 | + ], |
| 125 | + [CHAIN.ANCIENT8]: [ |
| 126 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 127 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 128 | + ], |
| 129 | + [CHAIN.BOTANIX]: [ |
| 130 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 131 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 132 | + ], |
| 133 | + [CHAIN.ZORA]: [ |
| 134 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 135 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 136 | + ], |
| 137 | + [CHAIN.XLAYER]: [ |
| 138 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 139 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 140 | + ], |
| 141 | + [CHAIN.MORPH]: [ |
| 142 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 143 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 144 | + ], |
| 145 | + [CHAIN.MANTA]: [ |
| 146 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 147 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 148 | + ], |
| 149 | + [CHAIN.CORE]: [ |
| 150 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 151 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 152 | + ], |
| 153 | + [CHAIN.REDSTONE]: [ |
| 154 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 155 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 156 | + ], |
| 157 | + // [CHAIN.XAI]: [ |
| 158 | + // "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 159 | + // "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 160 | + // ], |
| 161 | + [CHAIN.POLYGON_ZKEVM]: [ |
| 162 | + "0xf617d89a811a39f06f5271f89db346a0ae297f71", |
| 163 | + "0x2f96d7dd813b8e17071188791b78ea3fab5c109c", |
| 164 | + ], |
| 165 | +}; |
| 166 | + |
| 167 | +const abis = { |
| 168 | + GMSent: "event GMSent(address indexed sender, address indexed referral)", |
| 169 | + fee: "function fee() view returns (uint256)", |
| 170 | + referralFees: "function referralFees() view returns (uint256)", |
| 171 | +}; |
| 172 | + |
| 173 | +function toBig(v: any): bigint { |
| 174 | + try { |
| 175 | + if (v == null) return 0n; |
| 176 | + if (typeof v === "bigint") return v; |
| 177 | + if (typeof v === "number") return BigInt(Math.trunc(v)); |
| 178 | + if (typeof v === "string") return v.startsWith("0x") ? BigInt(v) : BigInt(v); |
| 179 | + } catch { } |
| 180 | + return 0n; |
| 181 | +} |
| 182 | + |
| 183 | +async function computeGrossByLogs(opts: FetchOptions, chainSlug: string): Promise<bigint> { |
| 184 | + const counters = COUNTERS[chainSlug]; |
| 185 | + if (!counters?.length) return 0n; |
| 186 | + |
| 187 | + const from_block = (opts as any).fromBlock; |
| 188 | + const to_block = (opts as any).toBlock; |
| 189 | + const BASIS = 10000n; |
| 190 | + let total = 0n; |
16 | 191 |
|
17 | | - const balanceStart = await options.fromApi.provider.getBalance(TREASURY); |
18 | | - const balanceEnd = await options.toApi.provider.getBalance(TREASURY); |
| 192 | + for (const counter of counters) { |
| 193 | + const logs = (await opts.getLogs({ |
| 194 | + target: counter, |
| 195 | + fromBlock: from_block, |
| 196 | + toBlock: to_block, |
| 197 | + eventAbi: abis.GMSent, |
| 198 | + entireLog: true, |
| 199 | + }).catch(() => [])) as any[]; |
19 | 200 |
|
20 | | - dailyFees.addGasToken(balanceEnd - balanceStart) |
| 201 | + if (!logs.length) continue; |
21 | 202 |
|
22 | | - return { |
23 | | - dailyFees, |
24 | | - dailyRevenue: dailyFees, |
| 203 | + const [feeWei, refBpRaw] = await Promise.all([ |
| 204 | + (opts as any).api.call({ target: counter, abi: abis.fee, block: to_block }).catch(() => 0), |
| 205 | + (opts as any).api.call({ target: counter, abi: abis.referralFees, block: to_block }).catch(() => 0), |
| 206 | + ]); |
| 207 | + const fee = toBig(feeWei); |
| 208 | + const refBP = toBig(refBpRaw); |
| 209 | + |
| 210 | + let withRef = 0n, noRef = 0n; |
| 211 | + for (const e of logs) { |
| 212 | + const ref = e?.args?.referral ?? e?.args?.[1] ?? "0x0000000000000000000000000000000000000000"; |
| 213 | + const isZero = typeof ref === "string" ? /^0x0{40}$/i.test(ref) : (!ref); |
| 214 | + if (isZero) noRef += 1n; else withRef += 1n; |
| 215 | + } |
| 216 | + const perWithRef = fee * (BASIS - refBP) / BASIS; |
| 217 | + total += fee * noRef + perWithRef * withRef; |
25 | 218 | } |
| 219 | + return total > 0n ? total : 0n; |
| 220 | +} |
| 221 | + |
| 222 | + |
| 223 | +async function computeNetByBalance(options: FetchOptions): Promise<bigint> { |
| 224 | + try { |
| 225 | + const [balStart, balEnd] = await Promise.all([ |
| 226 | + options.fromApi.provider.getBalance(TREASURY), |
| 227 | + options.toApi.provider.getBalance(TREASURY) |
| 228 | + ]); |
| 229 | + const delta = toBig(balEnd) - toBig(balStart); |
| 230 | + return delta > 0n ? delta : 0n; |
| 231 | + } catch { return 0n; } |
26 | 232 | } |
27 | 233 |
|
| 234 | + |
| 235 | +const fetch = async (options: FetchOptions) => { |
| 236 | + const dailyFees = options.createBalances(); |
| 237 | + |
| 238 | + let gross = 0n; |
| 239 | + try { gross = await computeGrossByLogs(options, options.chain); } catch { } |
| 240 | + if (gross > 0n) { |
| 241 | + dailyFees.addGasToken(gross); |
| 242 | + return { dailyFees, dailyRevenue: dailyFees }; |
| 243 | + } |
| 244 | + |
| 245 | + const net = await computeNetByBalance(options); |
| 246 | + if (net > 0n) dailyFees.addGasToken(net); |
| 247 | + return { dailyFees, dailyRevenue: dailyFees }; |
| 248 | +}; |
| 249 | + |
28 | 250 | const adapter: Adapter = { |
29 | 251 | version: 2, |
30 | 252 | fetch, |
| 253 | + start: "2025-08-11", |
31 | 254 | chains: CHAINS, |
32 | 255 | methodology: { |
33 | | - Fees: "Daily net increase in treasury address balance in each chain's native token (net inflow)", |
34 | | - Revenue: "All fees are revenue.", |
| 256 | + Fees: "fees from GMCounter logs: if referral is set, fee x (1 - referralFees/BPS), otherwise full fee.", |
| 257 | + Revenue: "fees accrue to protocol treasury. If no GMCounter address provided for a chain, fallback is treasury net inflow for that chain/day.", |
35 | 258 | }, |
36 | 259 | }; |
37 | 260 |
|
|
0 commit comments