Zum Inhalt

02 - ReserveVaultV2

Einziger USDT Fund Holder, Emergency Mode, Multi-Auth


Übersicht

ReserveVaultV2 ist der einzige Contract im System, der USDT hält. Alle Auszahlungen (Gewinne, Fees, Charity) laufen über diesen Contract. Kein Logic-Contract hat direkten Token-Zugriff.

Datei: contracts/contracts/ReserveVaultV2.sol


State Variables

IERC20 public immutable usdt;                              // USDT Token (unveränderlich)
mapping(address => bool) public isAuthorizedSettlement;     // Settlement-Contracts
mapping(address => bool) public isAuthorizedTreasury;       // Treasury-Contracts
bool public emergencyMode;                                  // Emergency Kill-Switch

Funktionen

depositFrom()

function depositFrom(address from, uint256 amount, string calldata reason)
    external nonReentrant
Parameter Typ Beschreibung
from address Spieler-Wallet
amount uint256 Betrag in USDT (6 Decimals)
reason string Buchungsgrund (z.B. "ticket_purchase")
  • Aufgerufen von: GameTreasury bei Ticket-Kauf
  • Mechanismus: usdt.safeTransferFrom(from, address(this), amount)
  • Voraussetzung: Spieler hat USDT-Approval an ReserveVault erteilt
  • Event: FundsDeposited(from, amount, reason)

payPrize()

function payPrize(address to, uint256 amount, uint256 dayId)
    external onlyAuthorizedSettlement nonReentrant
  • Aufgerufen von: Settlement (authorized)
  • Guard: require(!emergencyMode)
  • Zweck: Gewinn-Auszahlung an Spieler
  • Event: PrizePaid(to, amount, dayId)

payFee()

function payFee(address to, uint256 amount, uint256 dayId)
    external onlyAuthorizedSettlement nonReentrant
  • Aufgerufen von: Settlement (authorized)
  • Guard: require(!emergencyMode), require(dayId > 0)
  • Zweck: Net Fee an feeSafe überweisen
  • Event: FeePaid(to, amount, dayId)

payCharity()

function payCharity(address to, uint256 amount, uint256 dayId)
    external onlyAuthorizedSettlement nonReentrant
  • Aufgerufen von: Settlement (authorized)
  • Guard: require(!emergencyMode)
  • Zweck: Charity-Anteil an CharityVault überweisen
  • Event: CharityPaid(to, amount, dayId)

payOperatorFee()

function payOperatorFee(address to, uint256 amount)
    external onlyAuthorizedTreasury nonReentrant
  • Aufgerufen von: GameTreasury (authorized)
  • Guard: require(!emergencyMode)
  • Zweck: Gas-Kosten des Relayers in USDT erstatten
  • Event: OperatorFeePaid(to, amount)

setEmergencyMode()

function setEmergencyMode(bool enabled) external onlyOwner
  • Aufgerufen von: SAFE (Owner) only
  • Effekt: Blockiert alle Payout-Funktionen sofort
  • Einzige aktive Funktion im Emergency: ownerWithdraw()
  • Event: EmergencyModeChanged(enabled)

ownerWithdraw()

function ownerWithdraw(address to, uint256 amount) external onlyOwner
  • Aufgerufen von: SAFE (Owner) only
  • Zweck: Fund Recovery im Notfall
  • Hinweis: Funktioniert auch im Emergency Mode

Access Control

Funktion Owner (SAFE) Settlement Treasury Anyone
depositFrom - - - ✅ (mit Approval)
payPrize - - -
payFee - - -
payCharity - - -
payOperatorFee - - -
setEmergencyMode - - -
ownerWithdraw - - -
addSettlement - - -
addTreasury - - -

Emergency Mode

Normal Mode                    Emergency Mode
─────────────                  ──────────────
payPrize     ✅ aktiv          ❌ revert
payFee       ✅ aktiv          ❌ revert
payCharity   ✅ aktiv          ❌ revert
payOperatorFee ✅ aktiv        ❌ revert
ownerWithdraw  ✅ aktiv        ✅ aktiv (einzige)
depositFrom    ✅ aktiv        ✅ aktiv (Deposits weiterhin)

Aktivierung: SAFE Multisig (~5 Minuten für Signatur-Sammlung)


Sicherheits-Invarianten

  1. Balance-Invariante: ReserveVault.balance >= Σ(alle ausstehenden Claims + Pots + Rollovers + Jackpots + Fees)
  2. Immutable USDT: Token-Adresse ist immutable - kein Token-Swap möglich
  3. ReentrancyGuard: Auf allen Payout-Funktionen
  4. Multi-Auth: Mehrere Settlement/Treasury Contracts autorisierbar (für Migration)
  5. Keine interne Buchhaltung: ReserveVault trackt keine Salden - rein als Fund Holder

Audit-Hinweise

Kritischster Contract

ReserveVault ist der einzige USDT-Holder. Jeder Bug hier gefährdet alle Funds.

Multi-Auth für Migration

Während einer Migration können alter und neuer Settlement-Contract gleichzeitig autorisiert sein. Nach erfolgreicher Migration wird der alte de-autorisiert.

Kein Accounting

ReserveVault führt keine eigene Buchhaltung. Die Accounting-Logik liegt in GameTreasury. ReserveVault vertraut den autorisierten Contracts.