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()¶
| 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()¶
- Aufgerufen von: GameTreasury (authorized)
- Guard:
require(!emergencyMode) - Zweck: Gas-Kosten des Relayers in USDT erstatten
- Event:
OperatorFeePaid(to, amount)
setEmergencyMode()¶
- Aufgerufen von: SAFE (Owner) only
- Effekt: Blockiert alle Payout-Funktionen sofort
- Einzige aktive Funktion im Emergency:
ownerWithdraw() - Event:
EmergencyModeChanged(enabled)
ownerWithdraw()¶
- 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¶
- Balance-Invariante:
ReserveVault.balance >= Σ(alle ausstehenden Claims + Pots + Rollovers + Jackpots + Fees) - Immutable USDT: Token-Adresse ist
immutable- kein Token-Swap möglich - ReentrancyGuard: Auf allen Payout-Funktionen
- Multi-Auth: Mehrere Settlement/Treasury Contracts autorisierbar (für Migration)
- 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.