Blockchain Commit¶
Datei:
cli/commit_from_db.ts(110 Zeilen) Zweck: Approved Settlement auf die Blockchain schreiben Smart Contract: SettlementV4/V5 Gas Limit: 2.000.000
Übersicht¶
Der Blockchain-Commit ist der letzte kritische Schritt der Settlement Pipeline. Er überträgt das genehmigte Settlement als On-Chain-Transaktion.
settlement_runs (status='approved')
│
▼
Load approved run from DB
│
▼
Connect Operator Wallet
│
▼
commitMerkleSettlement(...)
│
▼
Wait for Receipt
│
▼
Update DB: status='committed'
+ tx_hash
+ block_number
Ablauf¶
1. Load Approved Run¶
// commit_from_db.ts:35-50
const run = await pg.query(
`SELECT * FROM settlement_runs
WHERE day_id = $1
AND status = 'approved'
AND commit_tx_hash IS NULL`,
[dayId]
);
Sicherheit: Nur approved-Runs ohne bestehende TX werden geladen.
2. Operator-Wallet¶
// commit_from_db.ts:55-64
const provider = new JsonRpcProvider(RPC_URL);
const operator = new Wallet(OPERATOR_KEY, provider);
const settlement = new Contract(SETTLEMENTV4, SettlementV4ABI, operator);
Der Operator benötigt die OPERATOR_ROLE im SettlementV4-Contract.
3. Contract Call¶
// commit_from_db.ts:67-78
const tx = await settlement.commitMerkleSettlement(
dayId,
poolPayoutArr, // [5] Regular-Pot-Auszahlungen
poolJackpotPayoutArr, // [5] Jackpot-Reserve-Auszahlungen
totalPayout, // Gesamtauszahlung
merkleRoot, // Winners-Merkle-Root
jackpotHitArr, // [5] Jackpot-Flags
affiliateTotal, // Affiliate-Gesamtbetrag
affiliateRoot, // Affiliate-Merkle-Root
charityTotal, // Charity-Betrag
{ gasLimit: 2_000_000 }
);
4. Receipt-Warten¶
// commit_from_db.ts:82-87
const receipt = await tx.wait();
if (receipt.status === 0) {
throw new Error("TX reverted on-chain");
}
5. DB-Update¶
// commit_from_db.ts:90-100
await pg.query(
`UPDATE settlement_runs
SET status = 'committed',
commit_tx_hash = $1,
commit_block = $2,
committed_at = NOW()
WHERE id = $3`,
[receipt.hash, receipt.blockNumber, runId]
);
Status-Transition: approved → committed
On-Chain-Effekte¶
Was der commitMerkleSettlement()-Call im Smart Contract bewirkt:
SettlementV5.commitMerkleSettlement()
├── 1. daySettled[dayId] = true
├── 2. merkleRoots[dayId] = merkleRoot
├── 3. affiliateRoots[dayId] = affiliateRoot
├── 4. ReserveVault.release(totalPayout) → PrizeVault
├── 5. ReserveVault.release(affiliateTotal) → AffiliateVault
├── 6. ReserveVault.release(charityTotal) → CharityVault
├── 7. potAcc[i] -= poolPayoutArr[i]
├── 8. jackpotReserveAcc[i] -= poolJackpotPayoutArr[i]
├── 9. Update jackpotStates (noHitStreak / reset)
└── 10. Emit SettlementCommitted event
Gas-Management¶
| Parameter | Wert |
|---|---|
| Gas Limit | 2.000.000 |
| Typischer Gas-Verbrauch | ~500.000 - 1.500.000 |
| Operator ETH-Balance | Überwacht via Watchdog (Warn: <0.05, Critical: <0.01) |
Fehlerszenarien¶
| Szenario | Verhalten |
|---|---|
| TX reverted | Error geworfen, Pipeline FAILED |
| Insufficient Gas | Error geworfen, Pipeline FAILED |
| RPC-Timeout | Error geworfen, Pipeline FAILED |
| Already settled | SettlementV5 wirft AlreadySettled |
| Falscher Operator | SettlementV5 wirft AccessControlUnauthorized |
Debug-Tool¶
Datei:
debug_commit.ts(60 Zeilen)
Für Fehlerdiagnose: Simuliert den Commit via staticCall() ohne Gas zu verbrauchen:
// Simulation ohne echte TX
const result = await settlement.commitMerkleSettlement.staticCall(
dayId, poolPayoutArr, poolJackpotPayoutArr, ...
);
Sicherheitsmaßnahmen¶
- Status-Gate: Nur
approved-Runs können committed werden - TX-Hash-Guard:
commit_tx_hash IS NULLverhindert Doppel-Commits - Gas Limit: Fix auf 2M - verhindert unbegrenzten Gas-Verbrauch
- Operator-Role: Smart Contract prüft
OPERATOR_ROLE - Finalized Blocks: Settlement wartet auf finalisierte Blöcke (kein Reorg-Risiko)