-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
138 lines (106 loc) · 3.68 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
129
130
131
132
133
134
135
136
137
138
import axios from 'axios';
import { config } from 'dotenv';
config();
const addressesString = process.env.ADDRESSES;
let ADDRESSES;
try {
ADDRESSES = JSON.parse(addressesString);
} catch (e) {
console.error('Failed to parse ADDRESSES:', e);
ADDRESSES = [];
}
const rewardCyclesString = process.env.REWARD_CYCLES;
let REWARD_CYCLES;
try {
REWARD_CYCLES = JSON.parse(rewardCyclesString);
} catch (e) {
console.error('Failed to parse REWARD_CYCLES:', e);
REWARD_CYCLES = [];
}
const network =
process.env.NETWORK === "mainnet" ?
"mainnet" :
process.env.NETWORK === "testnet" ?
"testnet" :
process.env.NETWORK === "nakamoto-testnet" ?
"nakamoto.testnet" :
"mainnet"
const START = 666050 + (REWARD_CYCLES[0] * 2100);
const END = 666050 + (REWARD_CYCLES[REWARD_CYCLES.length - 1] * 2100) + 2000;
const LIMIT = 250;
async function fetchRewardSlots(address) {
let offset = 0;
let burnHeights = [];
while (true) {
const url = `https://api.${network}.hiro.so/extended/v1/burnchain/reward_slot_holders/${address}?limit=${LIMIT}&offset=${offset}`;
const response = await axios.get(url);
const results = response.data.results;
if (results.length === 0) break;
results.forEach(entry => {
const burnBlockHeight = entry.burn_block_height;
if (burnBlockHeight >= START && burnBlockHeight <= END) {
burnHeights.push(burnBlockHeight);
}
});
offset += LIMIT;
}
return burnHeights;
}
async function fetchRewards(address) {
let offset = 0;
let rewards = [];
while (true) {
const url = `https://api.${network}.hiro.so/extended/v1/burnchain/rewards/${address}?limit=${LIMIT}&offset=${offset}`;
const response = await axios.get(url);
const results = response.data.results;
if (results.length === 0) break;
results.forEach(entry => {
const burnBlockHeight = entry.burn_block_height;
const rewardAmount = parseInt(entry.reward_amount, 10);
if (burnBlockHeight >= START && burnBlockHeight <= END) {
rewards.push({ burnBlockHeight, rewardAmount });
}
});
offset += LIMIT;
}
return rewards;
}
async function main() {
for (const address of ADDRESSES) {
let emptyRow = false;
console.log(`Processing address: ${address}`);
console.log();
const rewardSlots = await fetchRewardSlots(address);
const rewards = await fetchRewards(address);
let totalRewards = 0;
rewards.forEach(reward => {
totalRewards += reward.rewardAmount;
});
const burnHeightsInRewards = new Set(rewards.map(r => r.burnBlockHeight));
for (const burnBlockHeight of rewardSlots) {
if (!burnHeightsInRewards.has(burnBlockHeight)) {
try {
const response = await axios.get(`https://api.${network}.hiro.so/extended/v2/burn-blocks/${burnBlockHeight}`);
if (response.data.stacks_blocks) {
console.log(`At block ${burnBlockHeight} there were no rewards received, but there was a stacks block anchored!`);
}
} catch (error) {
if (error.response && error.response.status === 404) {
console.log(`At block ${burnBlockHeight} there were no rewards received. No STX block anchored at this block.`);
} else {
console.log(`At block ${burnBlockHeight} there were no rewards received. Couldn't check for anchored STX blocks.`);
}
}
emptyRow = true;
}
}
if (emptyRow) {
console.log()
}
console.log(`Total reward slots: ${rewardSlots.length}`);
console.log(`Won reward slots: ${rewards.length}`);
console.log(`Total rewards won: ${totalRewards / 100000000} BTC`);
console.log()
}
}
main().catch(console.error);