Naciśnij ESC, aby zamknąć

Shadow Governance i Bribes w DeFi: Analiza On-Chain

Przejmowanie kontroli nad DAO dawno już przeniosło się z publicznych wątków na Discourse do anonimowych pul płynności i zamkniętych grup na Telegramie. To tam, w ciągu zaledwie kilku bloków, rozstrzygają się losy miliardów dolarów.

Klasyczny atak 51% na protokół governance poprzez skupowanie natywnych tokenów z rynku (np. UNI czy AAVE) mija się z celem pod kątem ekonomicznym – poślizg cenowy (slippage) i mechanizmy stakingu błyskawicznie wywindują kurs w kosmos. Znacznie taniej jest "wypożyczyć" cudze głosy, wykorzystując mechanizm Voter Bribes (łapówki dla głosujących). Gdy cały ten proceder wychodzi poza przejrzyste platformy w stylu Votium czy Hidden Hand i ucieka w darmowe dilerki OTC albo zaszyfrowane smart kontrakty, rodzi się zjawisko Shadow Governance – ukryte zarządzanie, które potrafi wyczyścić skarbiec projektu do zera albo zmienić parametry ryzyka bez wiedzy zwykłego komunitu.

Anatomia Shadow Governance: Od Curve Wars po prywatne dark poole

Korzenie całego rynku łapówkowego sięgają architektury veTokenomics (vote-escrowed), przetestowanej przez Curve Finance. Blokując CRV nawet na 4 lata, użytkownik zgarniał veCRV, które decydowało o kierowaniu emisji tokenów do konkretnych pul płynności. Inne projekty szybko zwąchały pismo nosem: po co skupować CRV z rynku i zamrażać kapitał na 4 lata, skoro taniej wychodzi płacić cotygodniową "działkę" posiadaczom veCRV za oddanie głosu na wskazaną pulę?

Tak otworzyły się drzwi dla oficjalnych giełd łapówek:

  • Votium (dla ekosystemu Convex/Curve)
  • Hidden Hand od Redacted Cartel (spinający Balancera, Fraxa, Aurę)

Oficjalne przekupstwa mają jednak z punktu widzenia grubych ryb jedną zasadniczą wadę – są w pełni publiczne. Każdy analityk może odpalić dashboard i sprawdzić na tacy, kto komu płaci i za jaką pulę.

W Shadow Governance wjeżdżają zupełnie inne patenty:

  • Flashloans Governance Interception: Przejmowanie protokołów bez blokad ve w mgnieniu oka przy użyciu pożyczek błyskawicznych (flash loans). Atakujący bierze pożyczkę, przepycha propozycję natychmiastowym zastawem i spłaca dług w tej samej transakcji.
  • Off-Chain / OTC Bribe Matching: Umowy pod stołem, w których więksi gracze instytucjonalni trzymający ve-tokeny przytulają stablecoiny, altcoiny albo przydziały w przyszłych umowach SAFT na portfele powiernicze w zamian za ustawienie delegacji głosów.
  • Private Dark Pools (Wrapped Voting Power): Owijanie (wrapping) tokenów governance w smart kontrakty, które rozdzielają wartość czysto ekonomiczną od prawa głosu. Same prawa do głosowania są tokenizowane i licytowane na ślepych aukcjach (Holenderskich).

Akcje z życia: Jak protokoły leciały na łeb przez ciche przekręty

Case 1: Atak na Beanstalk Farms (Kwiecień 2022) – $182 mln w plecy

Choć na papierze wyglądało to na klasyczny exploit z użyciem flash loana, w rzeczywistości był to podręcznikowy "błyskawiczny wrogi przejazd nad governance". Atakujący zgarnął z Aave pożyczkę flash loan na okrągły $1 mld w Lido stETH, Bean i innych tokenach, przejął ponad 70% siły głosu (Voting Power) w propozycji BIP-18 (Beanstalk Improvement Proposal) i w tej samej sekundzie wyprowadził cały skarbiec na swój adres.

Gdzie tu Shadow Governance: Protokół zliczał siłę głosu na żywo z salda tokenów w bieżącym bloku – zero opóźnień czasowych (Timelock), zero wymogu wcześniejszego stakingu.

Case 2: Przejęcie Tornado Cash Governance (Maj 2023)

Haker wrzucił proposal, który na pierwszy rzut oka wyglądał kropka w kropkę jak wcześniej przyjęty wniosek. Pod maską zaszył jednak złośliwy kod. Kiedy społecznośćklepnęła wniosek, atakujący odpalił funkcję selfdestruct, podmienił kod kontraktu pod tym samym adresem (używając CREATE2), przypisał sobie z powietrza 1.2 mln fikcyjnych głosów TORN, po czym przejął pełną władzę nad DAO i wyciągnął z treasury $2.1 mln.

Gdzie tu Shadow Governance: Gość użył sprytnej sztuczki z metamorficznymi kontraktami (metamorphic contracts), co pozwoliło mu całkowicie ominąć wizualne audyty wniosków i podmienić logikę tuż przed samym głosowaniem.

Jak namierzyć Shadow Governance bezpośrednio na chainie

Wyśledzenie ustaleń OTC przy piwie czy na Telegramie graniczy z cudem, ale w momencie egzekucji na blockchainie zawsze zostaje jakiś ślad. Cała analityka sprowadza się do wyłapywania anomaliów w ruchach grubych portfeli (wielorybów) oraz w kontraktach delegacji.

Legitny Bribe vs Shadow Governance – zestawienie

ParametrJawny Bribe (Votium / Hidden Hand)Shadow Governance (OTC / Private)
Przejrzystość wypłatDystrybucja on-chain przez Merkle TreePrzelewy przez Tornado/Railgun/CEX albo świeżo upieczone portfele
Źródło środkówPubliczne smart kontrakty rynkoweZamknięte multisigi, portfele EOA, boty MEV
Delegowanie głosówZautomatyzowane przez meta-repozytoriaNagłe, nietypowe roszady delegatów tuż przed samym głosowaniem
Zwrot z inwestycji (ROI)Ograniczony rynkowym ROI z samej emisjiAbsurdalnie wysokie nagrody za przepchnięcie konkretnego punktu
TimelockPrzestrzegany zgodnie ze standardowymi zasadami DAOOmijany przy użyciu awaryjnych multisigów

Praktyczny algorytm tropienia anomalii na chainie

Żeby wyłapać ukryte machnoje, inżynierowie backendu i analitycy stawiają monitoring pod kątem następujących anomalii:

  • Śledzenie wzorców delegacji (Delegate Tracking): Nasłuchiwanie zdarzenia DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate). Jeśli gruby portfel (top 20 holderów) przerzuca siłę głosu na pusty adres na 2-3 bloki przed zamknięciem okienka votingowego, to masz jak w banku, że wjechał układ OTC.
  • Ruchy środków z mikserów (Flash-Mixers): Jeśli portfel, na który spłynęły delegacje, dostaje strzał ze stablecoinów albo natywnych coinów z mikserów na kilka godzin przed głosowaniem, na 99% trwa właśnie rozliczanie zlecenia.
  • Mempool i podchody przez MEV (MEV-driven Voting): Dopychanie propozycji w ostatnim możliwym bloku. Atakujący wysyłają prywatną transakcję bezpośrednio do buildera (np. przez Flashbots), żeby do samego końca ukryć budowanie krytycznej masy głosów.

Wyłapywanie anomalii: Skrypt w Pythonie do monitorowania delegacji

Poniżej znajdziesz lekki skrypt w Pythonie z użyciem biblioteki web3.py, który wyłapuje nagłe przerzuty dużej siły głosu (voting power) w tokenach ERC20Votes (architektura Compound/OpenZeppelin) tuż przed głosowaniami.

import time
import logging
from collections import defaultdict
from web3 import Web3
# Konfiguracja logowania
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
RPC_URL = "https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"
RAW_TOKEN_ADDRESS = "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" # UNI
# Bufor bezpieczeństwa przed reorgami sieci (12 bloków ~= 2.5 minuty)
SAFE_CONFIRMATIONS = 12
BATCH_STEP = 1000
ABI = [
   {
       "inputs": [],
       "name": "decimals",
       "outputs": [{"type": "uint8"}],
       "stateMutability": "view",
       "type": "function"
   },
   {
       "inputs": [],
       "name": "totalSupply",
       "outputs": [{"type": "uint256"}],
       "stateMutability": "view",
       "type": "function"
   },
   {
       "anonymous": False,
       "inputs": [
           {"indexed": True, "name": "delegate", "type": "address"},
           {"indexed": False, "name": "previousBalance", "type": "uint256"},
           {"indexed": False, "name": "newBalance", "type": "uint256"}
       ],
       "name": "DelegateVotesChanged",
       "type": "event"
   },
   {
       "anonymous": False,
       "inputs": [
           {"indexed": True, "name": "delegator", "type": "address"},
           {"indexed": True, "name": "fromDelegate", "type": "address"},
           {"indexed": True, "name": "toDelegate", "type": "address"}
       ],
       "name": "DelegateChanged",
       "type": "event"
   }
]
# 1. Weryfikacja połączenia RPC
w3 = Web3(Web3.HTTPProvider(RPC_URL))
if not w3.is_connected():
   raise ConnectionError("RPC nie odpowiada. Sprawdź klucz API lub stan węzła.")
# 2. Checksum i załadowanie kontraktu
token_address = w3.to_checksum_address(RAW_TOKEN_ADDRESS)
contract = w3.eth.contract(address=token_address, abi=ABI)
# 3. Parametry dynamiczne
try:
   TOKEN_DECIMALS = contract.functions.decimals().call()
   TOTAL_SUPPLY = contract.functions.totalSupply().call()
   logging.info(f"Token załadowany. Decimals: {TOKEN_DECIMALS} | Total Supply: {TOTAL_SUPPLY / (10 ** TOKEN_DECIMALS):,.0f}")
except Exception as e:
   logging.warning(f"Nie udało się pobrać parametrów tokena, ustawiam wartości domyślne: {e}")
   TOKEN_DECIMALS = 18
   TOTAL_SUPPLY = 1000000000 * (10 ** 18) # Domyślnie 1B
# Próg anomalii: 100,000 tokenów
VOTE_THRESHOLD = 100000 * (10 ** TOKEN_DECIMALS)
def get_logs_batched(event_obj, from_block, to_block):
   """Bezpieczne pobieranie logów w paczkach. Zwraca (logs, is_success)."""
   all_events = []
   for start in range(from_block, to_block + 1, BATCH_STEP):
       end = min(start + BATCH_STEP - 1, to_block)
       try:
           logs = event_obj.get_logs(fromBlock=start, toBlock=end)
           all_events.extend(logs)
       except Exception as e:
           logging.error(f"Błąd podczas pobierania logów dla bloków {start}-{end}: {e}")
           return [], False
   return all_events, True
def analyze_governance_shifts(from_block, to_block):
   """Analityka przetasowań głosów z wyliczeniem udziału w Total Supply."""
   vote_changes, ok1 = get_logs_batched(contract.events.DelegateVotesChanged, from_block, to_block)
   delegations, ok2 = get_logs_batched(contract.events.DelegateChanged, from_block, to_block)
   if not (ok1 and ok2):
       return False  # Błąd w logach, NIE przesuwamy wskaźnika bloku!
   # Grupowanie zdarzeń DelegateChanged w ramach jednej transakcji
   delegation_map = defaultdict(list)
   for d in delegations:
       tx_hash = d.transactionHash.hex()
       delegation_map[tx_hash].append({
           "delegator": d.args.delegator,
           "from": d.args.fromDelegate,
           "to": d.args.toDelegate
       })
   for event in vote_changes:
       prev_bal = event.args.previousBalance
       new_bal = event.args.newBalance
       delta = new_bal - prev_bal
       if abs(delta) >= VOTE_THRESHOLD:
           tx_hash = event.transactionHash.hex()
           delegate = event.args.delegate
           
           # Wyliczenie wskaźników względem Total Supply
           fmt_delta = delta / (10 ** TOKEN_DECIMALS)
           fmt_new = new_bal / (10 ** TOKEN_DECIMALS)
           share_of_supply = (new_bal / TOTAL_SUPPLY) * 100
           delta_share_of_supply = (abs(delta) / TOTAL_SUPPLY) * 100
           # Poziom krytyczności
           severity = "SKOK KRYTYCZNY" if share_of_supply >= 1.0 else "UWAGA"
           logging.warning(f"[{severity}] Zmiana Voting Power: {fmt_delta:+,.0f} tokenów ({delta_share_of_supply:.3f}% podaży)")
           logging.info(f"    Delegat: {delegate}")
           logging.info(f"    Ostateczna siła adresu: {fmt_new:,.0f} głosów ({share_of_supply:.3f}% Total Supply)")
           logging.info(f"    Tx Hash: {tx_hash}")
           contexts = delegation_map.get(tx_hash, [])
           if contexts:
               logging.info(f"    Przyczyna: BEZPOŚREDNIA ZMIANA DELEGATA ({len(contexts)} zdarzeń w Tx)")
               for ctx in contexts:
                   logging.info(f"      • Delegator: {ctx['delegator']} | {ctx['from']} -> {ctx['to']}")
           else:
               logging.info("    Przyczyna: Zmiana salda obecnego delegata (Transfer / Claim / Mint / Burn)")
           
           print("-" * 75)
   return True
def start_realtime_monitoring(poll_interval=12):
   """Demon czasu rzeczywistego pilnujący bufora potwierdzeń."""
   latest_block = w3.eth.block_number
   last_processed_block = latest_block - SAFE_CONFIRMATIONS - 1
   logging.info(f"Start demon. Początkowy bezpieczny blok: #{last_processed_block} (Confirmations = {SAFE_CONFIRMATIONS})")
   while True:
       try:
           current_block = w3.eth.block_number
           safe_block = current_block - SAFE_CONFIRMATIONS
           if safe_block > last_processed_block:
               success = analyze_governance_shifts(last_processed_block + 1, safe_block)
               if success:
                   last_processed_block = safe_block
               else:
                   logging.warning("Zakres nie został w pełni przetworzony przez błąd RPC. Ponawiam próbę...")
       except Exception as e:
           logging.error(f"Krytyczny błąd w pętli głównej: {e}")
       time.sleep(poll_interval)
if __name__ == "__main__":
   start_realtime_monitoring(poll_interval=12)

Jak zabezpieczyć się przed Shadow Governance

Rynek powoli wyciąga wnioski z kolejnych ataków na systemy zarządzania. Pobieżny audyt smart kontraktu to dziś za mało – obrona musi być wbudowana w samą architekturę DAO.

  • Timelocki z funkcją Veto: Zmiany w kodzie nie mogą wchodzić od strzała. Wdrożenie bufora bezpieczeństwa na minimum 48–72 godziny daje czas radzie bezpieczeństwa (Security Council) na zablokowanie podejrzanej propozycji.
  • Przejście na ve-Model z zamrożonym odblokowaniem: Gdy tokeny są zablokowane na twardo bez możliwości szybkiego obrotu, koszt przeprowadzenia błyskawicznego ataku rośnie drastycznie.
  • Zarządzanie optymistyczne (Optimistic Governance): Podejście wdrożone m.in. przez Moonwell czy Lido – wnioski przechodzą automatycznie, a pełne głosowanie odpala się tylko wtedy, gdy społeczność zgłosi sprzeciw (veto).
  • Dual-Token Governance: Rozdzielenie władzy między posiadaczy tokenów użytkowych a dostawców płynności / użytkowników protokołu (dokładnie tak działa to w Lido via Dual Governance, gdzie trzymający stETH mogą uwalić decyzje podejmowane przez holderów LDO).

Shadow Governance to naturalna konsekwencja faktu, że prawa do głosowania stały się zwykłym towarem. Zadaniem analityków i inżynierów blockchain w EXMON jest wyłapywanie takich anomalii w mempoolu oraz na poziomie smart kontraktów na tyle wcześnie, by zapewnić pełne bezpieczeństwo i przejrzystość wszystkim uczestnikom naszego ekosystemu.

Podsumuj ten wpis na blogu za pomocą:

FAQ

Atak na governance polega na tymczasowym lub trwałym przejęciu większościowej siły głosu w protokole w celu uchwalenia złośliwej propozycji i wyprowadzenia środków ze skarbca (treasury). Napastnik zaciąga pożyczkę flash loan, akumuluje duży wolumen tokenów zarządzania, natychmiast zatwierdza zmianę w kodzie smart kontraktu lub transfer aktywów i egzekwuje transakcję w obrębie tego samego bloku, zwracając pożyczone środki w tej samej operacji.

Kupowanie głosów opiera się na oferowaniu zewnętrznych zachęt finansowych posiadaczom tokenów w zamian za skierowanie ich siły głosu na określone propozycje lub wskaźniki emisji tokenów (gauges). Za pośrednictwem dedykowanych rynków lub natywnych kontraktów protokołu, podmioty płacą wyborcom za alokację nagród w konkretnych pulach płynności, przekształcając prawo głosu w bezpośrednie prawo do strumienia przychodów.

Ochrona wymaga wprowadzenia obowiązkowego opóźnienia czasowego (timelock) między zakończeniem głosowania a egzekucją propozycji, co uniemożliwia przeprowadzenie ataku w jednym bloku przy użyciu flash loans. Niezbędne jest również wyliczanie siły głosu na podstawie migawek stanu z wcześniejszych bloków (historical snapshots), stosowanie proporcjonalnych kworum oraz zautomatyzowane prawo weta dla strażników bezpieczeństwa (guardians).
Astra EXMON

Astra is the official voice of EXMON and the editorial collective dedicated to bringing you the most timely and accurate information from the crypto market. Astra represents the combined expertise of our internal analysts, product managers, and blockchain engineers.

...

Dodaj opinię

Twój adres e-mail nie zostanie opublikowany. Obowiązkowe pola są oznaczone*