diff --git a/server/src/engine/orchestrator.ts b/server/src/engine/orchestrator.ts index 5cf51cf..64306f2 100644 --- a/server/src/engine/orchestrator.ts +++ b/server/src/engine/orchestrator.ts @@ -555,61 +555,63 @@ async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRec potSats: mode === 'ranked' ? 42 : 0, }) - // Publish notable results to Nostr - if (winnerId) { - const winner = winnerId === botA.id ? botA : botB - const loser = winnerId === botA.id ? botB : botA - const isUpset = loser.eloRating - winner.eloRating > 150 - const isKO = (winnerId === botA.id && hpB <= 0) || (winnerId === botB.id && hpA <= 0) - publishFightResult({ - fightId, winnerName: winner.name, loserName: loser.name, winnerId, - winnerElo: newWinnerEloFinal, loserElo: newLoserEloFinal, - winnerEloChange, loserEloChange, - isPerfect: !!isPerfect, isKO, isUpset, - totalRounds: lastRound, arena: arena.name, - }).catch(err => console.warn('[nostr] publish failed:', err)) - } - - // 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() + // Publish notable results to Nostr + if (winnerId) { + const winner = winnerId === botA.id ? botA : botB + const loser = winnerId === botA.id ? botB : botA + const isUpset = loser.eloRating - winner.eloRating > 150 + const isKO = (winnerId === botA.id && hpB <= 0) || (winnerId === botB.id && hpA <= 0) + publishFightResult({ + fightId, winnerName: winner.name, loserName: loser.name, winnerId, + winnerElo: newWinnerEloFinal, loserElo: newLoserEloFinal, + winnerEloChange, loserEloChange, + isPerfect: !!isPerfect, isKO, isUpset, + totalRounds: lastRound, arena: arena.name, + }).catch(err => console.warn('[nostr] publish failed:', err)) } - } 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 - const devMode = process.env.NODE_ENV !== 'production' - const isMockA = botA.webhookUrl.startsWith('http://mock.local') - const isMockB = botB.webhookUrl.startsWith('http://mock.local') - const humanBotId = devMode ? (isMockA ? botB.id : isMockB ? botA.id : winnerId) : winnerId + // 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) + } - if (humanBotId) { - payWinner(fightId, humanBotId).catch(err => { - console.error(`[payments] payout failed for fight ${fightId}:`, err) - }) - } else if (!winnerId) { - // Draw — refund both entry fees - const entryPayments = await db.select().from(schema.payments) - .where(sql`${schema.payments.fightId} = ${fightId} AND ${schema.payments.direction} = 'in' AND ${schema.payments.status} = 'confirmed'`) - for (const payment of entryPayments) { - refundEntry(payment.id).catch(err => { - console.error(`[payments] draw refund failed for ${payment.id}:`, err) + // Ranked fight payout + if (mode === 'ranked') { + // Dev mode: always pay the human bot (not mock), regardless of win/loss + const devMode = process.env.NODE_ENV !== 'production' + const isMockA = botA.webhookUrl.startsWith('http://mock.local') + const isMockB = botB.webhookUrl.startsWith('http://mock.local') + const humanBotId = devMode ? (isMockA ? botB.id : isMockB ? botA.id : winnerId) : winnerId + + if (humanBotId) { + payWinner(fightId, humanBotId).catch(err => { + console.error(`[payments] payout failed for fight ${fightId}:`, err) }) + } else if (!winnerId) { + // Draw — refund both entry fees + const entryPayments = await db.select().from(schema.payments) + .where(sql`${schema.payments.fightId} = ${fightId} AND ${schema.payments.direction} = 'in' AND ${schema.payments.status} = 'confirmed'`) + for (const payment of entryPayments) { + refundEntry(payment.id).catch(err => { + console.error(`[payments] draw refund failed for ${payment.id}:`, err) + }) + } } } + } finally { + fightEvents.cleanup(fightId) } - - fightEvents.cleanup(fightId) } export async function runFight(botAId: string, botBId: string, mode: 'free' | 'ranked' = 'free'): Promise {