1 - Alephium's prediction game

1 - Alephium's prediction game

In this series of articles, we'll explain how we developed a decentralized application on Alephium.

·

8 min read

Alephium is the first scalable Layer 1 sharded blockchain that enhances the concepts of Proof of Work & UTXO. Decentralization, self-sovereignty and security meet energy efficiency in a developer-friendly network optimized for DeFi applications and smart contracts.

The application developed is a prediction game based on the price of ALPH, Alephium's native token, inspired by Pancakeswap. The app allows players to bet whether the ALPH price will be higher or lower after a defined period of time, currently 30 minutes. Those who find the right outcome win their bet + what people bet on the other side (pro rata to the bet).

The use of blockchain in this kind of application makes it possible to offer a satisfying gaming experience without the risk of centralization.

  1. PredictALPH : main contract which updates the price, stops a round, starts a round and allows players to collect their winnings.

  2. Round: contains all round information, such as number of participants, total bets, etc.

  3. Punter: stores the information of a person who has bet for a round. ALPH.bet

There are 3 contracts:

  • PredictALPH.ral: main contract that updates the price, stops a round, starts a round, allows players to collect their winnings.

  • Round.ral: contains all the information about a round, such as the number of participants, the total amount of bets, etc.

  • Punter.ral: stores information about a person who has bet on a round.

A new "sub-contract" is created for each round and each bet made by a player.

The complete contract code can be found on the Github directory

PredictALPH

ALPH.bet works as follows (we have a script that starts and finishes the rounds):

  1. Start a round with the current price to 2 decimal places (Total: 1 ALPH locked).

  2. A player bets 2 ALPH that the price will be lower (Total: 2 + 1 = 3 ALPH).

  3. A player bets 3 ALPH that the price will be higher (Total: 3 + 1 = 4 ALPH).

After 30 minutes (the current period), it is no longer possible to bet. An interval of around 2 minutes has been introduced to prevent people from betting for a few seconds at the end and then winning the round, and the prize is over. Winnings are calculated before the start of the next round.

In the explanation above, 1 ALPH is always added, whether for the start of a round or a new bet (in either case, even if the bet is wrong, the player can get their 1 ALPH back). This comes from the fact that you have to rent storage on the chain when creating a new contract, which allows several things:

  1. Offers a storage-saving blockchain.

  2. Encourages developers to be neat and tidy.

  3. Reduces supply in circulation.

To find out more

Another incentive has been introduced to enable us to claim back our 1 ALPH for the start of a round. It's only possible to claim it back if everyone has picked up their winnings and ALPH, so after a week, any address can claim unclaimed ALPH on behalf of someone else.

Another interesting point is how the prize is transmitted. Currently, there's no oracle on Alephium, so we've taken the decision to use CoinGecko's API, which allows us to have a manipulation-resistant price. In a 2nd version, we'll also be adding CoinMarketCap for greater resilience. And eventually, we'll be using the oracles available.

Code

A contract on Alephium always starts with the fields, which are its states. The description is available here.

Github

There's one thing in particular here extends DynamicArrayForInt(). This is a contract used to have a dynamic array that is used to retrieve earnings by users. Details can be found here: dynamicArrayInt.ral

Events

Next, a series of events is described and used to notify the world outside the Alephium chain that something has happened, such as that a new person has made a bet.

Github

In our case, we use this feature for two things: to know when someone has played and allow them to collect winnings, and to send a message on Telegram and Twitter when a new bet is made.

The use of events means you don't overload the chain with a complete history, while at the same time making it possible, for example, to have all the games played for one person.

Alephium makes event management and storage very efficient. A miner, for example, doesn't care about events, but still needs a node to be able to mine blocks. It's possible (by default) not to store this kind of information, which allows you to have a fullnode that doesn't take up much space and limits operations. It is also possible to concentrate on a single series of contracts. All these optimizations make running a fullnode less power-hungry and thus improve decentralization.

Error codes

Error codes are enumerated and, when a condition is not met, display an error and stop smart contract execution.

Github

Functions

This function is used to retrieve the subcontract of a particular round and obtain its status.

Github

This function is used to retrieve the states of a person who has played in a round.

Github

This is where things get serious: the startRound function is used to start a round. The parameters are the address and the price. The address is passed as a parameter because the endRound function calls it, and the address is that of the smart contract, not that of the operator.

The first line describes the Asset Permission System (APS).

The Asset Permission System (APS) is one of Ralph's unique features. It explicitly stipulates the flow of assets at code level, enabling developers and smart contract users to ensure that all asset transfers take place as intended. Combined with the UTXOs model, it also offers a simpler, more secure user experience by eliminating the risks associated with token approval in systems such as EVM. More details

In this case, startRound will transfer ALPH (to create the round's contract) and check that the address calling it has the right to do so.

Using assert allows you to stop contract execution if the round already exists, i.e. if it's already in progress.

An event is issued when lines 16-17 create the new round contract with all states, such as price. Line 20 will actually create it and transfer 1 ALPH with it. Again, APS comes into play, and in this case it won't be able to transfer more than one ALPH even in the event of a fault.

Github

Similar to endRound, this function will end the round, change the epoch and possibly start the next one directly or not. APS here indicates that this time the states will be updated, in this case, the epoch. An event is emitted again to indicate that a round has ended.

In this function, a call (lines 7-8) is made to the smart contract Round to validate that the time interval has actually passed.

Github

The bid function is the function that allows players to place bets. Four assertions have been used:

  • Line 8: to prevent betting if the time interval is already over.

  • Line 9: checks that the address interacting with the contract is an address and not a contract.Ligne 10 : stoppe l'exécution du contrat si moins de 1 ALPH est joué.

  • Line 10: stops contract execution if less than 1 ALPH is played.

  • Line 16: validates if the address used has not already been played. A maximum of one bet per address per round is allowed.

Then, as with the other contract, a sub-contract is created with the amount bet (- 1 ALPH), whether the bet is up or down, and the current epoch. With line 24, the bettor will be created for the round, but the ALPH bet will be transferred to the round contract. This centralizes and simplifies the calculation of winnings at the end.

Line 27 will update the round contract with the amount played, APS is used again, this time only for the bet amount.

Finally, depending on the bet made, an event is sent. In our case, it is used to find out when a new bet has been made.

Github

Withdraw is the function that allows an address to retrieve its winnings and ALPH used during participation. To optimize harvesting, an array is passed as a parameter with the list of rounds that will be claimed. The destroy function is used here to delete the contract from the chain, thus freeing up storage space and recovering the ALPH used during the initial bet.

An event is emitted to signal that an address has recovered its bet and winnings.

Github

Another function has been developed to allow anyone to retrieve winnings after a defined period of time. Eventually, this function will be combined with withdraw.

The destroyRound function is used to destroy a series of rounds passed as parameters, thereby recovering the ALPHs used to create them. Note that a round cannot be destroyed if all the players who took part have not yet collected their winnings.

Github

This article is the first in a series describing the ALPH.bet contracts and how we developed a decentralized application on Alephium. In the next article, the Round contract, which manages the different parties, will be presented.

To test the application -> ALPH.bet