Add draw_animation_seconds config and expose winner info during a round

RoundConfig gains draw_animation_seconds (default 20) — the minimum
time the frontend's "estrazione in corso" animation plays before
revealing a winner. It's purely a UI cue: the real draw still waits for
a confirmed block for its entropy (rounds/scheduler.py), which usually
takes much longer than this value, so it only ever extends the
animation, never truncates the real wait.

GET /rounds/current now also returns draw_animation_seconds,
winner_user_id and winner_amount_sats (all populated once the
scheduler sets them on the round, i.e. from "paying_out" onward) so a
client can determine and reveal the outcome. GET /users/me now returns
the user's own id, needed client-side to compare against winner_user_id.

Admin config CRUD refactored to a shared field tuple (_CONFIG_FIELDS)
instead of repeating the same 7-then-8 field list three times.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 16:04:02 +02:00
co-authored by Claude Sonnet 5
parent b52a8023de
commit 669c3fb714
5 changed files with 71 additions and 20 deletions
+16 -18
View File
@@ -20,6 +20,18 @@ async def require_admin(x_admin_token: str = Header(default="")) -> None:
raise HTTPException(status.HTTP_403_FORBIDDEN, "invalid admin token")
_CONFIG_FIELDS = (
"fee_address",
"bet_amount_sats",
"round_duration_seconds",
"round_cooldown_seconds",
"min_amount_sats",
"fee_rate_sat_vb",
"rbf_timeout_seconds",
"draw_animation_seconds",
)
class RoundConfigResponse(BaseModel):
fee_address: str
bet_amount_sats: int
@@ -28,6 +40,7 @@ class RoundConfigResponse(BaseModel):
min_amount_sats: int
fee_rate_sat_vb: int
rbf_timeout_seconds: int
draw_animation_seconds: int
class RoundConfigUpdate(BaseModel):
@@ -38,18 +51,11 @@ class RoundConfigUpdate(BaseModel):
min_amount_sats: int | None = None
fee_rate_sat_vb: int | None = None
rbf_timeout_seconds: int | None = None
draw_animation_seconds: int | None = None
def _config_response(config) -> RoundConfigResponse:
return RoundConfigResponse(
fee_address=config.fee_address,
bet_amount_sats=config.bet_amount_sats,
round_duration_seconds=config.round_duration_seconds,
round_cooldown_seconds=config.round_cooldown_seconds,
min_amount_sats=config.min_amount_sats,
fee_rate_sat_vb=config.fee_rate_sat_vb,
rbf_timeout_seconds=config.rbf_timeout_seconds,
)
return RoundConfigResponse(**{field: getattr(config, field) for field in _CONFIG_FIELDS})
@router.get("/config", response_model=RoundConfigResponse, dependencies=[Depends(require_admin)])
@@ -64,15 +70,7 @@ async def update_config(
body: RoundConfigUpdate, session: AsyncSession = Depends(get_session)
) -> RoundConfigResponse:
config = await get_round_config(session)
for field in (
"fee_address",
"bet_amount_sats",
"round_duration_seconds",
"round_cooldown_seconds",
"min_amount_sats",
"fee_rate_sat_vb",
"rbf_timeout_seconds",
):
for field in _CONFIG_FIELDS:
value = getattr(body, field)
if value is not None:
setattr(config, field, value)