Zum Inhalt

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: approvedcommitted

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

  1. Status-Gate: Nur approved-Runs können committed werden
  2. TX-Hash-Guard: commit_tx_hash IS NULL verhindert Doppel-Commits
  3. Gas Limit: Fix auf 2M - verhindert unbegrenzten Gas-Verbrauch
  4. Operator-Role: Smart Contract prüft OPERATOR_ROLE
  5. Finalized Blocks: Settlement wartet auf finalisierte Blöcke (kein Reorg-Risiko)