Skip to content

Commit c35d284

Browse files
matteomekhailclaude
andcommitted
Fix NaN amount corruption and betting race condition
- Validate amount is finite integer before reaching DB (prevents NaN→NULL balance) - Capture round number before async fetch to avoid stale setMyBet on round change Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 674af82 commit c35d284

2 files changed

Lines changed: 12 additions & 4 deletions

File tree

frontend.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,23 +251,27 @@ function BettingPanel({
251251

252252
const handlePlace = async () => {
253253
if (!selected || amount <= 0) return;
254+
const placedForRound = round.num;
254255
setPlacing(true);
255256
setError("");
256257
try {
257258
const res = await fetch("/api/bet", {
258259
method: "POST",
259260
headers: { "Content-Type": "application/json" },
260-
body: JSON.stringify({ userId, roundNum: round.num, contestant: selected, amount }),
261+
body: JSON.stringify({ userId, roundNum: placedForRound, contestant: selected, amount }),
261262
});
262263
const data = await res.json();
263264
if (!res.ok) {
264265
setError(data.error || "Failed");
265266
setPlacing(false);
266267
return;
267268
}
268-
setMyBet({ contestant: selected, amount });
269-
onBalanceChange(data.balance);
270-
localStorage.setItem("qs_balance", String(data.balance));
269+
// Only update if we're still on the same round
270+
if (lastRoundRef.current === placedForRound) {
271+
setMyBet({ contestant: selected, amount });
272+
onBalanceChange(data.balance);
273+
localStorage.setItem("qs_balance", String(data.balance));
274+
}
271275
} catch {
272276
setError("Network error");
273277
}

server.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ const server = Bun.serve<WsData>({
594594
return new Response(JSON.stringify({ error: "Invalid JSON" }), { status: 400, headers: { "Content-Type": "application/json" } });
595595
}
596596

597+
if (!Number.isFinite(amount) || !Number.isInteger(amount) || amount <= 0) {
598+
return new Response(JSON.stringify({ error: "Invalid amount" }), { status: 400, headers: { "Content-Type": "application/json" } });
599+
}
600+
597601
// Validate round is active and betting is open
598602
const active = gameState.active;
599603
if (!active || active.num !== roundNum) {

0 commit comments

Comments
 (0)