Qu'est-ce que la pool phase
La pool phase est une phase dédiée du cycle de vie d'un event, qui s'intercale entre la fermeture du placement de nouveaux défis et la résolution finale. Concrètement, c'est une fenêtre de quelques minutes juste avant la fermeture, pendant laquelle :
- Plus aucun nouveau défi ne peut être lancé.
- Plus aucune annulation côté user n'est possible (verrou temporaire).
- Le système rassemble tous les résidus non matchés et calcule un pool mutualisé.
Elle commence à un timestamp poolPhaseStartsAt = closesAt − Δ, où Δ dépend de la durée de l'event. Tu vois ce timestamp dans le détail de l'event sous « Phase pool commence à ».
Combien de temps dure la pool phase
Δ est calculé automatiquement selon la durée totale de l'event :
- Event < 1h : Δ = max(5min, 10% de la durée). Exemple : event de 30min → Δ = 5min.
- Event entre 1h et 24h : Δ = 15min fixes.
- Event entre 1 et 7 jours : Δ = 30min.
- Event > 7 jours : Δ = 60min.
L'admin de l'event peut surcharger cette valeur (entre 5 et 120 minutes) à la création, par exemple pour un event sensible qui nécessite plus de temps de calcul.
Ce qui rentre dans le pool
Au démarrage de la pool phase, le système liste tous les défis dont une partie n'a pas trouvé de contrepartie en phase 1 (matching live). Ces résidus sont regroupés par issue : pour chaque issue de l'événement, la somme des montants résiduels forme sa masse.
- Issue « Argentine gagne » : somme des résidus placés dessus = masse de cette issue.
- Issue « France gagne » : somme des résidus placés dessus = masse de cette issue.
Un multiplicateur pool indicatif est calculé pour chaque issue : le multiplicateur d'une issue est le rapport entre la masse totale du pool et la masse de cette issue, diminué de la commission. Plus la masse d'une issue est faible par rapport au total, plus son multiplicateur est élevé.
Le calcul itératif (et pourquoi)
Chaque participant a une préférence personnelle de multiplicateur minimal pool (entre 1.00 et 5.00, par pas de 0.10, défaut 1.20). Si le multiplicateur calculé pour son issue est inférieur à son seuil, il refuse le pool et doit être remboursé.
Mais retirer un participant change les masses, donc change les multiplicateurs, donc peut faire passer un autre participant sous son seuil. D'où le calcul itératif :
- Calcul du multiplicateur de chaque issue avec tous les résidus.
- Identifier les participants sous leur seuil.
- S'il y en a, refunder le plus exigeant (celui dont le seuil est le plus haut). En cas d'égalité, FIFO (le plus ancien d'abord).
- Re-calcul des multiplicateurs avec les participants restants.
- Répéter jusqu'à convergence (tout le monde au-dessus de son seuil) ou pool dégénéré (moins de deux issues couvertes).
Quand on converge, tous les restants rentrent en pool au multiplicateur calculé final. Les refundés reçoivent 100% de leur résidu sans aucune commission.
Atomicité et garanties
Tout le calcul est exécuté en mémoire, puis appliqué en une seule transaction atomique :
- Mise à jour des statuts des défis (POOLED pour les acceptés, REFUNDED pour les autres).
- Création des entrées MutualPool + PoolParticipation.
- Crédit des balances utilisateur pour les refunds.
- Insertion des transactions BET_REFUNDED.
- Audit complet de chaque itération (debug + support).
- Transition de l'event vers le statut CLOSED.
Si le moindre élément échoue, tout est annulé et l'event reste en POOL_PHASE ; le système réessaie (jusqu'à 3 fois avec backoff). Garantie : aucun drift financier possible, pas un centime ne peut se perdre ou se créer.
Le cas du pool dégénéré
Le pool est dit dégénéré s'il reste moins de deux issues couvertes au démarrage de la pool phase : tous les résidus sont massés sur une seule et même issue, il n'y a donc aucune contrepartie possible. Aucun multiplicateur ne peut être calculé. Dans ce cas :
- Tous les résidus sont remboursés à 100%, sans commission.
- Tu reçois une notification « Ton défi a été remboursé (aucune contrepartie en pool) ».
- L'event passe directement à CLOSED.
Aussi : si la pool phase démarre et qu'il y a zéro résidu total (tout a matché en phase 1), la pool phase est skip et l'event passe directement à CLOSED.
Si l'issue gagnante n'a aucune mise dans le pool
Ce cas ne concerne que les événements à trois issues ou plus. Sur un tel événement, une issue sans mise ne rend pas le pool dégénéré : il se forme dès que deux issues au moins sont couvertes. Mais si c'est justement une issue restée sans mise dans le pool qui se réalise, personne n'a gagné le pool : toutes les participations au pool sont remboursées intégralement, sans commission - y compris celles placées sur les issues perdantes.
- Seul le pool est concerné : si une partie de ton défi avait été appariée dans un lot pendant l'event, cette partie est réglée normalement.
- Ta participation au pool peut donc t'être rendue alors que ton issue a perdu. Ce n'est pas une erreur, c'est la règle.
Sur un événement à deux issues, ce cas ne peut pas se produire : un pool ne s'y forme que si les deux issues ont des mises. Sinon, il est dégénéré et remboursé dès le démarrage de la pool phase.
Les défis hybrides (partiellement matchés P2P)
Un défi peut être partiellement matché en phase 1 et avoir un résidu qui rentre en pool phase. Exemple :
- Tu mises 100K. La cascade matche 70K en P2P pendant l'event.
- 30K restent en résidu à l'entrée de la pool phase.
- Le pool accepte ton résidu au multiplicateur 1.40 → ton défi est désormais « 70K matchés en P2P + 30K en pool à 1.40 ».
- Si tu gagnes, tu touches : les gains P2P (70K × multiplicateur P2P) + les gains pool (30K × 1.40), moins les commissions correspondantes.
Le pool refuse ton résidu ? Tu gardes les 70K P2P matchés, et tu récupères les 30K refundés. Tu vois dans le détail du défi les deux composantes clairement.