1 - Jeu de prédiction sur Alephium
Dans cette série d'articles nous allons expliquer comment nous avons développé une application décentralisée sur Alephium
Alephium est la première blockchain shardée de couche 1 extensible qui améliore les concepts de Proof of Work & UTXO. La décentralisation, l'auto-souveraineté et la sécurité rencontrent l'efficacité énergétique dans un réseau adapté aux développeurs optimisé pour les applications DeFi et les contrats intelligents.
L'application développée est un jeu de prédiction basé sur le prix du ALPH, token natif de Alephium, inspiré de Pancakeswap. L'application permet aux joueur-euse-s de parier si le cours ALPH sera plus haut ou plus bas après une période de temps définie, actuellement 30 minutes. Les personnes qui ont trouvé la bonne issue gagnent leur mise + ce que les personnes ont parié de l'autre côté (au prorata du pari).
L'utilisation d'une blockchain dans ce genre d'application permet d'offrir une expérience de jeu satisfaisante sans le risque de la centralisation.
L'article va s'articuler autour des contrats qui ont été écrits pour arriver à l'application finale :Il y a 3 contrats :
PredictALPH : contrat principal qui se charge de mettre à jour le prix, d'arrêter un round, de démarrer un round et de permettre aux joueur-euse-s de récupérer leurs gains.
Round : contient toutes les informations d'un round, comme le nombre de participants, le montant total des paris, etc.
Punter : stocke les informations d'une personne qui a parié pour un round. ALPH.bet
Il y 3 contrats:
PredictALPH.ral: contrat principal qui se charge de mettre à jour le prix, arrêter un round, démarrer un round, permettre aux joueur-euse-s de récupérer leur gains
Round.ral: contient toutes les informations d'une round comme le nombre de participants, le montant total des paris, etc
Punter.ral: stocke les informations d'une personne qui a parié pour une round
Un nouveau "sous-contrat" est créé pour chaque round et chaque pari fait par un joueur-euse-s.
Le code complet des contrats peut être retrouvé sur le répertoire Github
PredictALPH
Le fonctionnement de ALPH.bet se déroule de la manière suivante (nous avons un script qui démarre et finit les rounds) :
Démarrage d'une round avec le prix actuel sur 2 décimales (Total : 1 ALPH bloqué).
Un joueur parie 2 ALPH que le prix sera plus bas (Total : 2 + 1 = 3 ALPH).
Une joueuse parie 3 ALPH que le prix sera plus haut (Total : 3 + 1 = 4 ALPH).
Après 30 minutes (période actuelle), il n'est plus possible de parier. Un intervalle d'environ 2 minutes a été mis en place pour éviter que des gens ne parient quelques secondes à la fin et gagnent ensuite la round, et le prix sont terminés. Le calcul des gains est effectué avant le début de la prochaine round.
Dans l'explication ci-dessus, 1 ALPH est toujours ajouté, que ce soit pour le démarrage d'une round ou d'un nouveau pari (dans tous les cas, même si le pari est faux, le joueur ou la joueuse peut récupérer leur 1 ALPH). Ceci vient du fait qu'il faut louer le stockage sur la chaîne lors de la création d'un nouveau contrat, ce qui permet plusieurs choses :
Offre une blockchain peu gourmande en espace de stockage.
Incite les développeurs à être ordonnés et propres.
Diminue l'offre en circulation.
Une autre incitative a été mise en place afin de nous permettre de récupérer nos 1 ALPH pour le démarrage d'un round. Il est possible de le récupérer uniquement si tout le monde a repris ses gains et ALPH, et donc après une semaine, n'importe quelle adresse peut demander au nom d'une autre personne les ALPH non réclamés.
Autre chose d'intéressant est comment le prix est transmis. Actuellement, il n'y a pas d'oracle sur Alephium, donc nous avons pris la décision d'utiliser l'API de CoinGecko qui nous permet d'avoir un prix résistant à la manipulation. Nous allons aussi ajouter, dans une 2ème version, CoinMarketCap afin d'avoir une meilleure résilience. Et à terme, nous utiliserons les oracles disponibles.
Code
Un contract sur Alephium commence toujours par les champs, qui sont ses états. La description est disponible ici
Il y a une chose particulière ici qui est extends DynamicArrayForInt()
. C'est un contrat utilisé afin d'avoir un tableau dynamique qui est utilisé pour récupérer les gains par les utilisateur-trice-s. Le détail peut être trouvé ici : dynamicArrayInt.ral
Événements
Ensuite, une série d'événements est décrite et sert à notifier le monde en dehors de la chaîne d'Alephium que quelque chose s'est passé, comme par exemple qu'une nouvelle personne a fait un pari.
Dans notre cas, nous utilisons cette fonctionnalité pour deux choses : savoir quand une personne a joué et lui permettre de récupérer les gains, et envoyer un message sur Telegram et Twitter lorsqu'un nouveau pari est fait.
L'utilisation d'événements permet de ne pas surcharger la chaîne avec un historique complet tout en donnant la possibilité, par exemple, d'avoir toutes les parties jouées pour une personne.
À savoir qu'Alephium rend la gestion et le stockage des événements très efficaces. Un mineur, par exemple, ne se soucie pas des événements mais a quand même besoin d'un nœud pour pouvoir miner des blocs. Il est possible (par défaut) de ne pas stocker ce genre d'informations, ce qui permet d'avoir un fullnode qui ne prend pas beaucoup de place et de limiter les opérations. Il est aussi possible de se concentrer uniquement sur une série de contrats. Toutes ces optimisations rendent le fait de faire fonctionner un fullnode peu gourmand et donc améliorent la décentralisation.
Codes d'erreurs
Les codes d'erreurs sont sous forme d'énumération (enum) et permettent, lorsqu'une condition n'est pas remplie, d'afficher une erreur et d'arrêter l'exécution du smart contrat.
Fonctions
Cette fonction est utilisée pour récupérer le sous-contrat d'un round en particulier et obtenir ses états.
Cette fonction va servir à récupérer les états d'une personne qui a joué dans un round.
C'est ici que les choses sérieuses commencent : la fonction startRound
permet de démarrer un round. Sont passés en paramètre l'adresse et le prix. L'adresse est passée en paramètre car la fonction endRound
l'appelle et l'adresse est celle du smart contract et non celle de l'opérateur.
La première ligne décrit l'APS (Asset Permission System).
Le système de permission des actifs (APS) est l'une des caractéristiques uniques de Ralph. Il stipule explicitement le flux d'actifs au niveau du code, ce qui permet aux développeurs et aux utilisateurs des contrats intelligents de s'assurer que tous les transferts d'actifs se déroulent comme prévu. Associé au modèle UTXOs, il offre également une expérience utilisateur plus simple et plus sûre en éliminant les risques liés à l'approbation des jetons dans des systèmes tels que l'EVM*.* Plus de détails
Dans ce cas, startRound
va transférer des ALPH (pour créer le contrat de la round) et contrôler que l'adresse qui l'appelle a bien les droits.
L'utilisation de assert
permet de stopper l'exécution du contrat dans le cas où la round existe déjà, ce qui veut dire qu'elle est déjà en cours.
Un événement est émis lorsque les lignes 16-17 permettent de créer le nouveau contrat de la round avec tous les états, tels que le prix. La ligne 20 va réellement le créer et transférer 1 ALPH avec. Encore une fois, APS entre en compte, et dans ce cas, elle ne pourra pas transférer plus d'un ALPH même en cas de faille.
Semblable à endRound
, cette fonction va terminer la round, changer l'epoch et éventuellement démarrer directement le prochain ou non. APS ici indique que cette fois-ci les états seront mis à jour, dans ce cas, l'epoch. Un événement est émis à nouveau pour indiquer qu'un round s'est terminé.
Dans cette fonction, un appel (lignes 7-8) au smart contract Round est fait afin de valider que l'intervalle de temps est réellement passé.
La fonction bid
est la fonction qui permet aux joueur-euse-s de parier. Quatre assertions ont été utilisées :
Ligne 8 : afin d'empêcher le pari si l'intervalle de temps est déjà terminé.
Ligne 9 : contrôle que l'adresse qui interagit avec le contrat soit une adresse et non un contrat.
Ligne 10 : stoppe l'exécution du contrat si moins de 1 ALPH est joué.
Ligne 16 : valide si l'adresse utilisée n'a pas déjà joué. Un pari par adresse par round maximum est autorisé.
Ensuite, à l'image de l'autre contrat, un sous-contrat est créé avec le montant parié (- 1 ALPH), que le pari soit à la hausse ou à la baisse, ainsi que l'epoch actuel. Avec la ligne 24, le parieur ou la parieuse sera créé(e) pour le round, mais les ALPH pariés seront transférés dans le contrat du round. Cela permet de centraliser et de simplifier le calcul des gains à la fin.
La ligne 27 va mettre à jour le contrat du round avec le montant joué, APS est à nouveau utilisé, cette fois-ci uniquement pour le montant du pari.
Pour terminer, selon le pari fait, un événement est envoyé dans notre cas il est utilisé pour savoir quand un nouveau pari a été fait
Withdraw
est la fonction qui permet à une adresse de récupérer ses gains et ALPH utilisés lors de la participation. Pour optimiser la récolte, un tableau est passé en paramètre avec la liste des rounds qui seront réclamées. La fonction destroy
est utilisée ici pour supprimer le contrat de la chaîne et donc libérer de l'espace de stockage ainsi que retrouver le ALPH utilisé lors du pari initial.
Un événement est émis afin de signaler qu'une adresse a récupéré sa mise et ses gains.
Une autre fonction a été développée pour permettre à n'importe qui de récupérer les gains après une période de temps définie. À terme, cette fonction sera combinée avec withdraw
.
La fonction destroyRound
est utilisée pour détruire une série de rounds passée en paramètres, permettant ainsi de récupérer les ALPH utilisés pour les créer. À noter qu'un round ne peut pas être détruit si tous les joueurs qui ont participé n'ont pas encore récupéré leurs gains.
Cet article est le premier d'une série qui va décrire les contrats de ALPH.bet et comment nous avons développé une application décentralisée sur Alephium. Dans le prochain article, le contrat Round, celui qui gère les différentes parties, sera présenté.
Pour tester l'application -> ALPH.bet