"""Konfigurasi proyek dari env / `.env`. Bacaan tipe via `os.getenv`; nilai default = konstanta lama. Muat `.env` sekali di sini supaya semua modul (get_voters, dashboard) berbagi sumber yang sama. """ import os from decimal import Decimal from dotenv import load_dotenv load_dotenv() # BP target TARGET_BP = os.getenv('VEX_TARGET_BP', 'databisnisid') # Node RPC publik Vexanium API_NODE = os.getenv('VEX_API_NODE', 'https://v2.vexascan.com:2096') # Lokasi basis data SQLite (dipakai fetcher & dashboard) DB_PATH = os.getenv('VEX_DB_PATH', 'voters.db') # Backend basis data: 'sqlite' (default) atau 'mysql' (MariaDB/MySQL via PyMySQL) DB_BACKEND = os.getenv('VEX_DB_BACKEND', 'sqlite') # Koneksi MariaDB/MySQL (dipakai saat DB_BACKEND='mysql') DB_HOST = os.getenv('VEX_DB_HOST', '127.0.0.1') DB_PORT = int(os.getenv('VEX_DB_PORT', '3306')) DB_USER = os.getenv('VEX_DB_USER', '') DB_PASS = os.getenv('VEX_DB_PASS', '') DB_NAME = os.getenv('VEX_DB_NAME', '') # Syarat minimum stake (dalam VEX) untuk disimpan MIN_STAKED_VEX = float(os.getenv('VEX_MIN_STAKED_VEX', '1000')) # Dashboard: ukuran halaman list PAGE_SIZE = int(os.getenv('DASH_PAGE_SIZE', '50')) # Dashboard: host & port server Flask DASH_HOST = os.getenv('DASH_HOST', '127.0.0.1') DASH_PORT = int(os.getenv('DASH_PORT', '5000')) # Dashboard: jumlah worker gunicorn (produksi) DASH_WORKERS = int(os.getenv('DASH_WORKERS', '2')) # Ambang batas vote "basi" (hari tanpa revote). Sejak V40 pemilih lewat batas # ini TETAP disimpan di scan (basi dibuang hanya saat tampil/bayar): band # kadaluarsa 28..31 hari tetap tampil (sorot VOTE ULANG), >31 hari disembunyikan. VEX_STALE_DAYS = int(os.getenv('VEX_STALE_DAYS', '28')) # Masa matang (hari): pemilih baru (revote < VEX_MATURITY_DAYS lalu) BELUM # berhak reward (⊥ dibayar distribusi) hingga votenya berumur ≥ ambang ini. VEX_MATURITY_DAYS = int(os.getenv('VEX_MATURITY_DAYS', '3')) # Jendela "kadaluarsa" (hari SETELAH VEX_STALE_DAYS) yang masih tampil di # dashboard (band sorot VOTE ULANG). Lewat 28+3 = 31 hari → disembunyikan. VEX_EXPIRED_DAYS = int(os.getenv('VEX_EXPIRED_DAYS', '3')) # Tag REVOTE (mint) bertahan (hari) sejak revote terakhir: hanya pemilih lama # yang revote dalam `VEX_REVOTE_TAG_DAYS` terakhir diberi tag; setelah itu # tampil sbg VALID biasa (tetap dibayar langsung — V42, ⊥ tunggu matang). VEX_REVOTE_TAG_DAYS = int(os.getenv('VEX_REVOTE_TAG_DAYS', '1')) # Jendela peringatan (hari SEBELUM VEX_STALE_DAYS): pemilih VALID yang # `now − STALE < last_vote ≤ now − (STALE − WARN)` diberi badge `VOTE ULANG # SEGERA` (segera kadaluarsa, masih dibayar). VEX_WARN_DAYS = int(os.getenv('VEX_WARN_DAYS', '3')) # API databisnis untuk saldo liquid akun (balance BP, disajikan dashboard) DATABISNIS_API = os.getenv('DATABISNIS_API', 'https://api.databisnis.id') # Dashboard: TTL cache (detik) untuk saldo liquid — gagal fetch juga di-cooldown DASH_LIQUID_TTL = int(os.getenv('DASH_LIQUID_TTL', '60')) # ————————————————— Distribusi profit-share (V19..V27) ————————————————— # Jam (lokal, TZ) run harian distribusi; key aktif BP via swarm secret/env. # ⊥ env-able: konstanta chain Vexanium (token + chain_id untuk signing). BP_PRIVATE_KEY = os.getenv('VEX_BP_PRIVATE_KEY', '') DISTRIBUTE_HOUR = int(os.getenv('DISTRIBUTE_HOUR', '10')) DISTRIBUTE_MAX_ATTEMPTS = int(os.getenv('DISTRIBUTE_MAX_ATTEMPTS', '3')) # Kill-switch distribusi (V35): default OFF — payout hanya jalan saat diset # `true`. `--dry-run` tetap boleh jalan (read-only, ⊥ tanda tangan/tulis). DISTRIBUTE_ENABLED = os.getenv( 'DISTRIBUTE_ENABLED', 'false').lower() in ('1', 'true', 'yes') # Jadwal mingguan (V37): hari `DISTRIBUTE_WEEKDAY` (nama `sat`/`mon`.. atau # 0-6, default `sat`) jam `DISTRIBUTE_HOUR`; plus satu one-off # `DISTRIBUTE_FIRST_RUN` (`YYYY-MM-DD`). Dipakai distribute_loop (via config, # konsisten dgn dashboard V38). Default baked = launch pertama 2026-08-17 # (Senin) 10:00; env tetap override. Setelah tanggal lewat → otomatis hanya # mingguan (batas skip event masa lalu). DISTRIBUTE_WEEKDAY = os.getenv('DISTRIBUTE_WEEKDAY', 'sat') DISTRIBUTE_FIRST_RUN = os.getenv('DISTRIBUTE_FIRST_RUN', '2026-08-17') # ————————————————— Notifikasi Telegram (V30/V36) ————————————————— # Bot token tunggal; dua daftar chat id (CSV): KOMUNITAS (`..._COMMUNITY_...`) # hanya brief mulai/selesai distribusi, INTERNAL (`..._INTERNAL_...`) detail # distribusi + semua kegagalan + klaim reward (⊥ komunitas). Kosong → kanal # itu senyap. TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', '') TELEGRAM_COMMUNITY_CHAT_IDS = [ c.strip() for c in os.getenv('TELEGRAM_COMMUNITY_CHAT_IDS', '').split(',') if c.strip() ] TELEGRAM_INTERNAL_CHAT_IDS = [ c.strip() for c in os.getenv('TELEGRAM_INTERNAL_CHAT_IDS', '').split(',') if c.strip() ] # ————————————————— Klaim reward BP (V32..V34) ————————————————— # Poll interval (detik) saat mendekati jendela klaim; fee wallet + persentase # 10% dari reward yang baru diklaim (floor 4 desimal). CLAIM_RETRY_SECONDS = int(os.getenv('CLAIM_RETRY_SECONDS', '60')) BP_FEE_WALLET = os.getenv('VEX_BP_FEE_WALLET', 'bpdbsjasprod') BP_FEE_PERCENT = Decimal(os.getenv('VEX_BP_FEE_PERCENT', '0.10')) # Kontrak token VEX = vex.token (⊥ eosio.token — tak ada di chain) TOKEN_CONTRACT = 'vex.token' VEX_SYMBOL = 'VEX' VEX_PRECISION = 4 VEX_CHAIN_ID = 'f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f'