@gooddollar/goodprotocol
Version:
GoodDollar Protocol
131 lines (119 loc) • 4.97 kB
text/typescript
import { get, groupBy, mapValues, range, sortBy, toPairs } from "lodash";
import PromisePool from "async-promise-pool";
import fs from "fs";
import { ethers } from "hardhat";
import { JsonRpcProvider } from "@ethersproject/providers";
function arrayToCsv(data) {
return data
.map(
row =>
row
.map(String) // convert every value to String
.map(v => v.replaceAll('"', '""')) // escape double colons
.map(v => `"${v}"`) // quote it
.join(",") // comma-separated
)
.join("\r\n"); // rows starting on new lines
}
const celoStats = async () => {};
const main = async (isCelo = true) => {
const archive = new JsonRpcProvider(
isCelo ? "https://celo-mainnet-archive.allthatnode.com" : "https://explorer-node.fuse.io"
);
const faucetAddr = isCelo
? "0x4F93Fa058b03953C851eFaA2e4FC5C34afDFAb84"
: "0x01ab5966C1d742Ae0CFF7f14cC0F4D85156e83d9";
const adminAddr = "0x7119CD89D4792aF90277d84cDffa3F2Ab22a0022";
const blockStep = 10000;
const pool = new PromisePool({ concurrency: 5 });
let faucet = (await ethers.getContractAt("Faucet", faucetAddr)).connect(archive);
const endBlock = Number(await archive.getBlockNumber());
const daysBack = 1;
const dayBlocks = 12 * 60 * 24;
const startBlock = endBlock - dayBlocks * daysBack;
const days = range(startBlock, endBlock, dayBlocks);
days.push(endBlock);
console.log({ startBlock, endBlock });
const dailyBalance = [];
const dailyAdminBalance = [];
for (let day of days) {
dailyBalance.push(
await Promise.all([
archive.getBalance(faucetAddr, day).then(_ => _.div(1e10).toNumber() / 1e8),
archive.getBalance("0x7119CD89D4792aF90277d84cDffa3F2Ab22a0022", day).then(_ => _.div(1e10).toNumber() / 1e8)
])
);
console.log({ day });
}
let curBlock = startBlock;
const toppingsByAddress = {};
const toppingsByAmount = {};
const toppingsByRelayer = {};
const toppingsPerDay = {};
const toppingsOfWhitelisted = {};
let totalToppings = 0;
let totalWhitelistedToppings = 0;
let totalAmount = 0;
const dailyUsage = dailyBalance.map((v, i) => (i < dailyBalance.length - 1 ? v[0] - dailyBalance[i + 1][0] : 0));
const dailyAdminUsage = dailyBalance.map((v, i) => (i < dailyBalance.length - 1 ? v[1] - dailyBalance[i + 1][1] : 0));
console.log({ dailyUsage, dailyAdminUsage });
fs.writeFileSync("celospend.csv", arrayToCsv(dailyBalance));
console.log(arrayToCsv(dailyBalance));
// return;
console.log({ startBlock, endBlock });
while (curBlock <= endBlock) {
const fromBlock = curBlock;
const toBlock = Math.min(fromBlock + blockStep, endBlock);
pool.add(async () => {
const f = faucet.filters.WalletTopped();
const events = await faucet.queryFilter(f, fromBlock, toBlock).catch(e => {
console.log("failed", { fromBlock, toBlock });
return [];
});
events.forEach(e => {
const day = (e.blockNumber / dayBlocks).toFixed(0);
toppingsPerDay[day] = get(toppingsPerDay, day, 0) + 1;
totalToppings += 1;
totalAmount += Number(e.args.amount);
toppingsByAddress[e.args.account] = (toppingsByAddress[e.args.account] || 0) + 1;
if (e.args.whitelistedRoot != ethers.constants.AddressZero) {
toppingsOfWhitelisted[e.args.whitelistedRoot] = (toppingsOfWhitelisted[e.args.whitelistedRoot] || 0) + 1;
totalWhitelistedToppings += 1;
}
if (e.args.account !== e.args.relayerOrWhitelisted)
toppingsByRelayer[e.args.relayerOrWhitelisted] = (toppingsByRelayer[e.args.relayerOrWhitelisted] || 0) + 1;
toppingsByAmount[e.args.amount] = (toppingsByAmount[e.args.amount] || 0) + 1;
});
console.log("fetched events", {
fromBlock,
toBlock,
events: events.length
});
});
curBlock += blockStep;
}
await pool.all();
const topToppers = sortBy(toPairs(toppingsByAddress), "1").reverse();
const topAmounts = sortBy(toPairs(toppingsByAmount), "1").reverse();
const topRelayers = sortBy(toPairs(toppingsByRelayer), "1").reverse();
const topWhitelisted = sortBy(toPairs(toppingsOfWhitelisted), "1").reverse();
const totalWallets = topToppers.length;
const avgToppingsPerWallet = totalToppings / totalWallets;
const avgToppingAmount = totalAmount / totalToppings;
console.log(topRelayers.slice(0, 50));
console.log(topToppers.slice(0, 50));
const byNumberOfToppings = mapValues(groupBy(topToppers, "1"), v => v.length);
console.log({ byNumberOfToppings });
console.log(toppingsPerDay);
// fs.writeFileSync("topToppers.csv", arrayToCsv(topToppers));
// fs.writeFileSync("topAmounts.csv", arrayToCsv(topAmounts));
// fs.writeFileSync("topRelayers.csv", arrayToCsv(topRelayers));
console.log({
totalWhitelistedToppings,
totalAmount,
totalToppings,
avgToppingsPerWallet,
avgToppingAmount
});
};
main(true).catch(e => console.log(e));