-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
128 lines (124 loc) · 3.55 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const { ethers, BigNumber } = require("ethers");
const abi = require("./abi.json");
const fs = require("fs");
module.exports = async function getBalance(
contract,
rpc,
startBlock,
endBlock,
data,
paginateLimit,
logProgress
) {
if (!contract) {
throw new Error("Contract address is required");
}
if (!rpc) {
console.warn(
"No rpc provided, using default rpc - this might be very slow"
);
}
if (!startBlock) {
console.warn(
"No start block provided, using default start block - this may or may not be slow"
);
}
if (!endBlock) {
console.warn(
"No end block provided, using default end block - this may or may not be slow"
);
}
if (!data) {
console.warn("No data provided, calculating from scratch");
}
if (!paginateLimit) {
console.warn(
"No paginate limit provided, searching all blocks at once - this may cause an error if there are too many blocks"
);
paginateLimit = 0;
}
const provider = ethers.getDefaultProvider(rpc);
const tokenContract = new ethers.Contract(contract, abi, provider);
const lastBlock = endBlock || (await provider.getBlockNumber());
let balances = data || {};
if (!startBlock) {
startBlock = 0;
}
if (logProgress) {
fs.writeFileSync("get-erc20-balances.log", "");
}
if (paginateLimit > 0 && lastBlock - startBlock > paginateLimit) {
currentBlock = startBlock;
while (currentBlock < lastBlock) {
if (logProgress) {
fs.appendFileSync(
"get-erc20-balances.log",
`${Date.now()}: fetching blocks ${currentBlock} to ${
currentBlock + paginateLimit
}\n`
);
}
const events = await getEvents(
tokenContract,
currentBlock,
currentBlock + paginateLimit
);
if (logProgress) {
fs.appendFileSync(
"get-erc20-balances.log",
`${Date.now()}: found ${events.length} events\n`
);
}
balances = await fillData(balances, events, logProgress);
currentBlock += paginateLimit;
}
} else {
if (logProgress) {
fs.appendFileSync(
"get-erc20-balances.log",
`${Date.now()}: fetching blocks ${startBlock} to ${lastBlock}\n`
);
}
const events = await getEvents(tokenContract, startBlock, lastBlock);
balances = await fillData(balances, events, logProgress);
}
Object.keys(balances).forEach((key) => {
balances[key] = balances[key].toNumber();
});
delete balances["0x0000000000000000000000000000000000000000"];
return balances;
};
async function getEvents(tokenContract, startBlock, endBlock) {
return await tokenContract
.queryFilter("*", startBlock + 1, endBlock)
.then((events) =>
events.filter((y) =>
y.topics.includes(
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
)
)
);
}
async function fillData(balances, events, logProgress) {
const txns = events.map((x) => x.args);
await txns.forEach((item) => {
const from = item.from;
const to = item.to;
const amount = item.value;
if (logProgress) {
fs.appendFileSync(
"get-erc20-balances.log",
`${Date.now()}: ${from} sent ${amount} -> ${to}\n`
);
}
if (!Object.keys(balances).includes(from)) {
balances[from] = BigNumber.from(0);
}
if (!Object.keys(balances).includes(to)) {
balances[to] = BigNumber.from(0);
}
balances[from] = BigNumber.from(balances[from]).sub(amount);
balances[to] = BigNumber.from(balances[to]).add(amount);
});
return balances;
}