// Ganti dengan nama akun Block Producer Anda di Vexanium const TARGET_BP = 'databisnisid'; // Menggunakan API dari v2.vexascan.com const API_NODE = 'https://v2.vexascan.com:2096'; // Fungsi pembantu untuk fetch dengan mekanisme retry (karena node ini kadang timeout) async function fetchWithRetry(url, options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(url, options); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); return response; } catch (error) { if (i === maxRetries - 1) throw error; console.log(`[Warning] Gagal menghubungi node, mencoba lagi... (${i + 1}/${maxRetries})`); await new Promise(res => setTimeout(res, 2000)); // tunggu 2 detik sebelum retry } } } async function getVotersForMyBP() { let myVoters = []; let lowerBound = ''; let hasMore = true; let totalScanned = 0; console.log(`Mulai memindai voters untuk BP: "${TARGET_BP}"...`); while (hasMore) { try { // Menggunakan fetchWithRetry yang sudah kita buat const response = await fetchWithRetry(`${API_NODE}/v1/chain/get_table_rows`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ json: true, // PENTING: Di Vexanium, kontrak sistem (untuk tabel voters) adalah vexcore, bukan vexio code: 'vexcore', scope: 'vexcore', table: 'voters', lower_bound: lowerBound, limit: 500 }) }); const data = await response.json(); const rows = data.rows || []; if (rows.length === 0) break; // Hindari duplikasi elemen pertama saat pagination if (lowerBound !== '') { rows.shift(); } totalScanned += rows.length; // Saring hanya pemilih yang HANYA mem-vote BP ini (eksklusif 1 vote) const filtered = rows.filter(voter => Array.isArray(voter.producers) && voter.producers.length === 1 && voter.producers[0] === TARGET_BP ); myVoters = myVoters.concat(filtered); hasMore = data.more; if (hasMore && rows.length > 0) { lowerBound = rows[rows.length - 1].owner; } } catch (error) { console.error('\nError saat mengambil data:', error.message); break; } } console.log(`\n=== HASIL AKHIR ===`); console.log(`Total akun dipindai di jaringan: ${totalScanned}`); console.log(`Total voters untuk BP [${TARGET_BP}]: ${myVoters.length}`); // Menampilkan daftar pemilih beserta VEX staked-nya console.log('\nDaftar Pemilih:'); if (myVoters.length === 0) { console.log('(Tidak ada pemilih ditemukan untuk BP ini atau scan terhenti di tengah jalan)'); } else { myVoters.forEach((v, index) => { // VEX stake disimpan dalam pecahan 1/10000 (4 desimal) const vexStaked = (v.staked / 10000).toLocaleString('id-ID'); console.log(`${index + 1}. ${v.owner} - Stake: ${vexStaked} VEX`); }); } return myVoters; } getVotersForMyBP();