feat: wire bet settlement into fight finalization

Lock bets when fight goes live, settle all bets atomically when fight
ends. Winners get Cashu payout tokens, losers forfeit. Draws refund
all bets. Settlement results persisted to bets table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-08 19:57:00 +00:00
co-authored by Claude Opus 4.6
parent de15d27468
commit 005a7942fb
+19
View File
@@ -10,6 +10,7 @@ import { generateMockBotResponse, isClassicBot, generateClassicBotResponse } fro
import { setCooldown } from './queue.js'
import { isHumanPlayer, waitForHumanResponse } from './human-responses.js'
import { payWinner, refundEntry, ENTRY_FEE_SATS } from './payments.js'
import { settleBets, lockBets } from './betting.js'
interface BotRecord {
id: string
@@ -295,6 +296,9 @@ async function createFightRecord(botA: BotRecord, botB: BotRecord, arena: Arena,
startedAt: now,
createdAt: now,
})
// Lock bets when fight starts
lockBets(fightId)
emit(fightId, 'fight_start', {
botA: { id: botA.id, name: botA.name, elo: botA.eloRating },
botB: { id: botB.id, name: botB.name, elo: botB.eloRating },
@@ -506,6 +510,21 @@ async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRec
potSats: mode === 'ranked' ? 42 : 0,
})
// Settle bets
try {
const settlements = await settleBets(fightId, winnerId)
for (const s of settlements) {
db.update(schema.bets).set({
status: s.won ? 'won' : winnerId ? 'lost' : 'refunded',
payoutSats: s.payoutSats,
payoutToken: s.payoutToken,
settledAt: new Date().toISOString(),
}).where(eq(schema.bets.id, s.betId)).run()
}
} catch (err) {
console.error(`[betting] settlement failed for fight ${fightId}:`, err)
}
// Ranked fight payout
if (mode === 'ranked') {
// Dev mode: always pay the human bot (not mock), regardless of win/loss