Het contract: hoe en waarom het werkt
Alle tegoeden en alle regels van FAIRDRUM zitten in één programma op het Solana-netwerk: een smart contract. De site stuurt het alleen opdrachten en toont het antwoord. Hieronder lees je wat het contract bewaart, welke opdrachten het begrijpt, hoe uit een willekeurig getal een resultaat ontstaat en wat de beheerder wel en niet kan.
Wat een contract is en waar het zich bevindt
Een smart contract is een programma dat wordt uitgevoerd door de nodes van het Solana-netwerk en niet op een server van het project. De code is voor iedereen gelijk en elke handeling is een openbare transactie. Het FAIRDRUM-contract is geschreven in Rust met de bibliotheek Anchor; de broncode is open.
Het adres van het programma verschijnt hier zodra de site met het contract is verbonden.
Een belangrijk gevolg: als de site fairdrum.to verdwijnt, blijven de tegoeden van de spelers in het contract staan en kun je ze opnemen met elk programma dat de opname-opdracht met de handtekening van je wallet kan versturen.
Wat het contract bewaart
- Kluis. Eén account in wrapped SOL waarover alleen het programma zelf beschikt. Daarin zit alles: de saldi van de spelers, de prijzenbank, de jackpots, de reserve en het nog niet opgenomen aandeel van de beheerder.
- Gedeeld spelaccount. De registratie van hoe het bedrag in de kluis is verdeeld: prijzenbank, jackpot, mini-jackpot, superjackpot, reserve voor startbedragen, aandeel van de beheerder, startbedragen van de jackpots, rondetellers per spel.
- Spelersaccount. Wordt aangemaakt met de opdracht register, die de site samen met de eerste storting verstuurt, en is gekoppeld aan het walletadres: spelsaldo, tijdstip van de laatste storting, onafgemaakte ronde, nog niet uitbetaald deel van de jackpot.
- Sessieaccount (als ‘spelen zonder handtekeningen’ aanstaat): een tijdelijke sleutel, een looptijd en een inzetlimiet.
De boekhouding is zo opgezet dat de som van alle saldi en potten gelijk is aan het bedrag in de kluis. Een test controleert die gelijkheid na elk van tienduizenden willekeurige bewerkingen.
Welke opdrachten het contract begrijpt
| Opdracht | Wie mag aanroepen | Wat het doet |
|---|---|---|
register | speler | Maakt het spelersaccount aan. De site verstuurt deze opdracht samen met de eerste storting. |
deposit | speler | Storting op het spelsaldo. Onthoudt het tijdstip: vanaf dan lopen de 12 uur tot opnemen kan. |
withdraw | speler | Opname naar je eigen wallet. Wordt geweigerd zolang er nog geen 12 uur zijn verstreken sinds de laatste storting. |
spin_commit | de speler of zijn sessiesleutel | Inzet: schrijft de ronde af van het saldo, onthoudt het spel en de geldende kansen en vraagt een willekeurig getal aan bij het orakel. |
spin_settle | iedereen | Afrekening: leest het getal van het orakel, berekent de uitbetaling en schrijft die bij op het saldo van de speler. Iedereen mag dit aanroepen — het resultaat hangt daar niet van af. |
spin_expire | iedereen | Sluit een ronde die niet binnen 20 minuten is afgerekend. Heeft het orakel niet gereageerd, dan gaat de inzet volledig terug naar de speler. Heeft het orakel gereageerd en is de ronde verzegeld, dan worden de gewone prijzen uitbetaald zonder jackpottrekking. |
spin_seal | iedereen | Verzegelt de ronde: legt de hash van het blok van de inzet vast zolang die beschikbaar is (ongeveer 3,5 minuut). Alleen nodig als het orakel er langer over doet; meestal roept de dienstdoende service deze instructie aan. Een ronde die niet op tijd is afgerekend en ook niet is verzegeld, wordt zonder resultaat gesloten. |
skip_nonce | speler | Schuift het nummer van de volgende willekeur-aanvraag op als het adres van de aanvraag bezet blijkt. |
session_open / session_close | speler | Staat een tijdelijke sleutel toe om in te zetten binnen de looptijd en de limiet; de sleutel kan niet opnemen en niet storten. |
donate | iedereen | Legt SOL in de reserve voor de startbedragen van de jackpots. Een omgekeerde opdracht bestaat niet. |
set_jackpot_starts | beheerder | Stelt nieuwe startbedragen in voor de jackpot en de superjackpot; ze gaan in na 24 uur. |
rescale_pools | beheerder | Zet een deel van de reserve voor startbedragen over naar de prijzenbank van de spellen. Alleen in die richting; naar de jackpots overzetten kan niet — die worden na een winst vanzelf uit de reserve aangevuld. |
set_paused | beheerder | Pauzeert of hervat het aannemen van nieuwe inzetten — voor het geval het orakel uitvalt. Inzetten die al zijn gedaan worden afgerekend; uitbetalingen en opnemen werken zoals gewoonlijk. |
set_guardian / guard_pause | beheerder | De beheerder wijst een bewaker aan — een sleutel van de dienstdoende service die maar één ding kan: het aannemen van nieuwe inzetten pauzeren als het orakel niet meer reageert. Alleen de beheerder kan de pauze opheffen. |
propose_dev_authority / accept_dev_authority | beheerder | Overdracht van de beheerdersrechten aan een andere sleutel in twee stappen: de huidige sleutel wijst de nieuwe aan, en de nieuwe bevestigt dat zelf. |
roll_epoch / checkin | iedereen | Hulpopdrachten: ze werken de weekstatistiek en de dagmarkering bij. Ze verplaatsen geen tegoeden. |
claim_dev | beheerder | Neemt het opgebouwde aandeel van de beheerder op — en alleen dat. |
initialize / fund_pools | beheerder | Eenmalige start. initialize maakt de accounts aan (ondertekend door de houder van het updaterecht van het programma); fund_pools verdeelt de ingelegde startbank één keer over de potten en boekt het meerdere daarboven op een aparte regel, die de beheerder kan opnemen met de opdracht promo_pay. |
Een opdracht die de prijzenbank, de jackpots of de saldi van spelers naar de beheerder zou overmaken, staat niet in de code.
Een ronde in stappen
- Inzet. De opdracht spin_commit schrijft de ronde af van je saldo en maakt in dezelfde transactie bij het orakel ORAO een aanvraag voor een willekeurig getal aan. Het adres van de aanvraag wordt berekend uit je wallet en het rondenummer, dus de aanvraag van iemand anders onderschuiven kan niet.
- Getal. Meerdere onafhankelijke ORAO-nodes ondertekenen het willekeurige getal en schrijven het naar het netwerk. Tot dat moment kent niemand het: jij niet, het project niet en ook geen afzonderlijke node.
- Afrekening. De opdracht spin_settle leest het getal uit de registratie van het orakel, controleert of het de aanvraag van precies jouw ronde is en berekent de uitbetaling. De site verstuurt die zelf; is de pagina gesloten, dan doet het dienstdoende programma van het project het, of jijzelf bij je volgende bezoek.
- Weergave. Kaarten, mijnen, raket, stenen: het zijn manieren om de al berekende uitbetaling te tonen. Wat je in het spel aanklikt, heeft er geen invloed op.
Waarom het resultaat niet vooraf te kennen en niet te vervalsen is. Het uiteindelijke getal van een ronde is het getal van het orakel, gemengd met de hash van het blok waarin de inzet is vastgelegd. Op het moment van de inzet bestaat die hash nog niet, en het getal van het orakel komt later en van een derde partij: niemand kan de uitkomst vooraf berekenen — de speler niet, het project niet en het orakel zelf ook niet. Het spel, de startbedragen van de jackpots en het prijsplafond worden vastgelegd op het moment van de inzet, en de rekenformule staat in open code. Een te late afrekening is nooit gunstiger dan een tijdige. De regels zijn alleen te veranderen door de code van het programma te vervangen, en dat ziet iedereen (zie het deel over de beheerder).
Hoe uit een willekeurig getal een resultaat ontstaat
Een ronde bestaat uit 1 tot 100 inzetten van 0,01 SOL (op het rad tot 1000). Het getal van het orakel wordt uitgewerkt tot een onafhankelijke willekeurige waarde voor elke inzet, en voor elke inzet beantwoordt het contract achtereenvolgens deze vragen:
- Superjackpot, jackpot, mini-jackpot? De kans op elke pot is gelijk aan de bijdrage van de inzet aan die pot, gedeeld door het startbedrag van de pot. Een pot wordt alleen verloot als er minstens 25% van het startbedrag in zit.
- Prijs van het spel? Elk spel heeft een eigen prijskans en een eigen tabel van zes treden met gewichten. Op het rad valt er bijvoorbeeld bij 10% van de inzetten een prijs. De tabellen van alle spellen staan op hun pagina's.
- ‘Nog een keer’? Met een kans van 11,6% wordt de inzet gratis herhaald op kosten van de prijzenbank.
- Anders is het een inzet zonder prijs. Die wordt net zo verdeeld als elke andere: prijzenbank, jackpots en aandeel van de beheerder.
De tabellen van de spellen verschillen, maar de verwachte uitbetaling is overal gelijk (tot op honderdsten van een procent; bij een prijzenbank vanaf 40 SOL, wanneer prijzen niet tegen het plafond lopen): ongeveer 77,5% van de inzet aan gewone prijzen, en samen met de herhalingen ‘Nog een keer’ ongeveer 88% van de betaalde inzetten. De compiler controleert die gelijkheid: als de verwachting van een spel hoger uitkomt dan die van het rad, of meer dan een half procent lager, laat het programma zich niet bouwen.
Waar het contract elke inzet neerlegt
| Waarheen | Aandeel van de betaalde inzet | Waarvoor |
|---|---|---|
| Prijzenbank | ≈88% | gewone prijzen van alle spellen |
| Jackpot, mini-jackpot, superjackpot en startbedrag | 2% | drie gedeelde potten |
| Beheerder | 10% | inkomsten van het project; andere zijn er niet |
In de code zijn de aandelen vastgelegd per uitgevoerde inzet, inclusief gratis herhalingen; daarom staat daar 8,84% en 1,77%: omgerekend naar betaalde inzetten is dat gemiddeld 10% en 2%.
Begrenzende regels en waarvoor ze dienen
- Eén prijs is niet meer dan een kwart van de prijzenbank. Het contract kan niet meer beloven dan het heeft, en één grote winst maakt de bank niet leeg voor de anderen. Wat niet wordt uitbetaald, blijft in de bank.
- Opnemen kan 12 uur na de laatste storting. De regel is voor iedereen gelijk en als constante vastgelegd: hij kan alleen met een nieuwe versie van het programma worden gewijzigd.
- De startbedragen van de jackpots veranderen met een vertraging van 24 uur. De kansen van een ronde worden vastgelegd op het moment van de inzet; ze aanpassen ‘op een al geplaatste inzet’ kan dus niet.
- 20 minuten voor de afrekening. Als het orakel niet heeft gereageerd, gaat de inzet volledig terug naar de speler: zolang het getal er niet is, kent niemand de uitkomst, dus op deze manier kan niemand onder een verlies uitkomen. Als het wel reageerde maar de afrekening te laat kwam, worden de gewone prijzen uitbetaald en worden de jackpots in die ronde niet verloot. Kluisbeveiliging. Vóór elke uitbetaling en na elke afrekening controleert het contract of er in de kluis niet minder zit dan het aan spelers en potten verschuldigd is; anders wordt de bewerking geweigerd. Bewaker. Als het orakel niet meer reageert, wordt het aannemen van nieuwe inzetten automatisch gepauzeerd; afrekeningen en opnemen blijven werken.
- De jackpot wordt in delen uitbetaald: de winnaar heeft recht op 95% van de pot, waarvan 20% direct en 8% per week. Het nog niet uitbetaalde deel staat op het account van de winnaar.
- Eén onafgemaakte ronde per speler. Zolang de ronde niet is afgerekend, wordt er geen nieuwe inzet aangenomen.
Wat de beheerder wel en niet kan
Kan wel
- zijn aandeel opnemen — 10% van de betaalde inzetten;
- SOL in de reserve inleggen en van de reserve naar de prijzenbank overzetten;
- het overschot opnemen dat bij de start boven de startbank in de kluis terecht is gekomen;
- de startbedragen van de jackpots wijzigen — met vertraging en binnen vaste grenzen;
- het aannemen van nieuwe inzetten pauzeren als het orakel niet reageert, en zijn rechten aan een andere sleutel overdragen.
Kan niet
- de prijzenbank, de jackpots, de reserve of de saldi van spelers opnemen (als speler wint hij onder dezelfde voorwaarden als iedereen);
- de prijzentabellen, de prijskans van de spellen en de aandelen van de inzet wijzigen: dat zijn constanten in de code;
- het willekeurige getal van een ronde vóór de inzet te weten komen of het kiezen;
- de afrekening van gedane inzetten of het opnemen stopzetten: de pauze geldt alleen voor nieuwe inzetten.
Eerlijk voorbehoud. Het programma heeft een updaterecht: zolang dat niet is ingetrokken, kan de houder de code door een nieuwe versie vervangen, en dan geldt al het bovenstaande voor de nieuwe code. De status van dit recht en elke update zijn zichtbaar in de Solana-verkenner. Er is geen onafhankelijke audit van het contract.
Hoe dit is getest
- Tests van het contract: aandeel van de beheerder 10% in elk spel, vrijwel gelijk rendement van alle spellen bij een bank van 50 SOL, de kwartregel en het prijsplafond van het moment van de inzet, het opnameslot, de uitgestelde wijziging van startbedragen, een late afrekening is niet gunstiger dan een tijdige.
- Controle op behoud van tegoeden: tienduizenden willekeurige bewerkingen; na elke bewerking wordt het bedrag in de kluis vergeleken met de som van saldi en potten.
- Lange runs: twee miljoen inzetten per spel — hoeveel er aan spelers is uitbetaald en hoeveel de beheerder heeft gekregen.
- Echte transacties op een lokale Solana-node: storting, geweigerde opname vóór de termijn, inleg in de reserve, wijziging van startbedragen.
- Tests van de site: de site berekent de kansen met dezelfde formules als het contract en vergelijkt ze met voorbeelden die het contract heeft vastgelegd.
Wat niet is getest en niet is gedaan, staat onverbloemd op de pagina ‘Waarom FAIRDRUM’. Hoe je zelf een willekeurige ronde controleert, staat op de pagina ‘Ronde controleren’.
De parameters van het contract in één tabel
- Eenheidsinzet
- 0,01 SOL
- Ronde
- tot 100 inzetten in de spellen, tot 1.000 op het rad
- Spellen (modi)
- 16
- Kans op ‘Nog een keer’
- 11,6%
- Plafond van één prijs
- 1/4 van de prijzenbank
- Kleinste startbedrag
- jackpot 0,2 SOL, superjackpot 2 SOL
- Mini-jackpot
- start met 1/10 van de jackpot
- Voor de winnaar van de jackpot
- 95% · 5% gaat naar de superjackpot
- Voor de winnaar van de superjackpot
- 90%
- Opnameslot
- 12 uur na de laatste storting
- Termijn voor de afrekening van een ronde
- 3.000 netwerkslots, ongeveer 20 minuten
- Netwerk- en orakelkosten
- 0,005 SOL per ronde, niet door het project gerekend