Bet blueprint: how it works
Introduction
This article explains how the bet blueprint works. Understanding this functioning is essential to anyone implementing this blueprint into a use case.
Currently, this blueprint is available for testing purposes only. It was conceived to demonstrate how blueprints function and provide insight into the design, implementation, and documentation processes for future blueprints.
Behavior
This section explains the behavior of contracts created using the bet blueprint — namely, bet contracts.
Actors
There are three different actors that interact with a bet contract:
- bookmaker;
- bettors; and
- oracle.
Bookmaker
Bookmaker is the one who creates a bet contract for a given event, and once doing it, establishes the terms of the contract.
Bettors
Bettors are the ones who place bets on the result of the event to which the bet contract refers.
Oracle
A bet contract has one and only one oracle. This oracle is responsible for providing the contract the result of the betting event.
Life cycle
The following diagram illustrates the life cycle of a bet contract:
Regarding the reading actions, any of them can be done in any moment of the life cycle of the contract. In turn, different contract execution actions take place in different phases of its life cycle. The life cycle of a bet contract has three phases:
- bets;
- event; and
- winnings.
Bets phase
This phase is when bettors place their bets. It begins once the bookmaker successfully creates a new contract. It does it submitting a nano contract transaction calling the initialize
method. Once the contract is created until the end of the phase, bettors can place their bets. A bettor can place as many bets they wish, each with a different wager. They do it submitting a nano contract transaction calling the bet
method. This phase ends when the date and hour specified by the date_last_offer
attribute is reached. Thereafter, the contract will not accept new bets.
Event phase
The event phase is when the contract's betting event takes place. This phase begins from the date and time specified by the date_last_offer
attribute and lasts until the oracle sets the final_result
attribute, with the result of the betting event. Indeed, the only contract execution that will succeed in this phase, is the set of the result, done by the oracle. It does it submitting a nano contract transaction calling the set_result
method.
Winnings phase
The third and last phase is when winning bettors can withdraw their winnings. This phase begins as soon as the oracle set the result of the betting event, and lasts indefinitely — as long as Hathor Network runs. As already explained, a winning bettor can withdraw to any address — not necessarily their own — any fraction of their winnings using any number of transactions. They do it submitting a nano contract transaction calling the method withdraw
.
Further considerations
Note that the state of the contract does not cover all the information that describes a betting option. For example, there is no attribute to describe the betting event. Therefore, bookmakers must communicate these informations to bettors in an off-chain manner.
One such piece of information concerns which results are liable to occur in the betting event, and what string formats these results must have to be eligible for a winnings. As already explained, a bet contract will accept as valid any bet that contains a string as an argument. There is no format validation for this string. However, only strings that perfectly match the final_result
attribute will be considered as winning bets.
Thus, it is necessary for the bookmaker to agree with bettors and oracle about the set of possible event results as well as their formatting. The bookmaker can establish a betting option with a finite number of results, and in this case provide the oracle and the bettors with a list of strings that can be used to place a bet, and to set final_result
. For example, for a UFC fight, the bookmaker may create a contract, modeling a betting option, in which there are only two possible results: victory for fighter 1, or victory for fighter 2. In this case, the bookmaker specifies the following list of strings:
fighter_1
fighter_2
Or, the bookmaker can specify a betting option in which there is an infinite number of possible results. For example, in a football match, the score could theoretically be any combination of two positive integers. In this case, instead of specifying a list of strings, the bookmaker specifies a regular expression, such as: <score_team_1>x<score_team_2>
, in which <score_team_1>
and <score_team_2>
are positive integers indicating the goals of teams 1 and 2 respectively.
Anatomy
The following diagram depicts the anatomy of the bet blueprint:
In this diagram, we see all attributes of the blueprint, which, along with the balance of the token (that the contract works with), will specify the state of the contract. Also, note that not all methods (of the blueprint) are listed in the diagram. Only those that are useful for users to querying the contract. All other methods were omitted. In the following subsections, we explain each of the listed attributes, public and view methods.
Attributes
Bet blueprint has the following attributes:
token_uid
date_last_offer
oracle_script
final_result
total
bets_total
bets_address
withdrawals
token_uid
TokenUid
object that defines the token the contract works with — i.e., the token used to place bets and to pay out winning bettors. A bet contract works with one and only one token. This token can be any fungible token registered in Hathor blockchain (either a custom token or 'HTR'). It is set once by initialize
and does not change anymore.
date_last_offer
Defines the date and time limit for bettors to place bets. Beyond this limit, the contract does not accept bets anymore. Usually, this limit relates to the date and time when the betting event occurs. A bet contract works with one and only one date and time limit. It is set once by initialize
and does not change anymore.
oracle_script
Defines who the oracle of the contract is. A bet contract has one and only one oracle. It is set once by initialize
and does not change anymore. An oracle might be controlled by either a single private key or a multisignature address.
final_result
Keeps the result of the betting event. A bet contract works with one and only one event result. Is is set once by the oracle, after the ocurrence of the event, and does not change anymore.
total
Keeps the 'handle' of the bet contract — i.e., the total amount of tokens wagered by all bettors. It increases as bettors place bets, until date_last_offer
is reached. After that, since there will be no new bets, it won't change anymore.
bets_total
Keeps the wagered sum of tokens for each result within the universe of results that bets were placed. For example, suppose a betting event with only three possible results: (1) victory of Alice, (2) victory of Bob, or (3) draw. And suppose x bettors wagered (a collective sum of) X tokens in Alice's victory, y bettors wagered Y tokens in a draw, and nobody placed bets in Bob's victory. Thus, bets_total
would keep:
- Alice's victory: X tokens.
- Draw: Y tokens.
bets_address
Keeps how much each bettor wagered in each result it placed bets. A bettor is identified by a wallet address. For example:
- Address A (Bettor A) betted a tokens (summing all its bets) in Alice's victory.
- Address B (Bettor B) betted b tokens in Alice's victory.
- Address A (Bettor A) betted c tokens in draw.
withdrawals
Keeps how much each winning bettor has already cashed out from its winnings.
Public methods
Bet blueprint has the following public methods:
initialize
bet
set_result
withdraw
initialize
Used by the bookmaker to create a new bet contract. Requires the following arguments:
oracle_script
: aTxOutputScript
object used to define the oracle of the contract.token_uid
: aTokenUid
object used to define the token the contract works with.date_last_offer
: aTimestamp
object used to define the date and time limit for bettors to place bets.
Also, it requires that the nano contract transaction (that calls this method) have no deposits or withdrawals. If this method call succeeds, the new contract is registered on Hathor blockchain.
bet
Used by bettors to place a bet. Requires the following arguments:
address
: anAddress
object that identifies the bettor.score
: a string that describes the prediction (or selection) of the bettor as result of the betting event.
Regarding address
, remember that each bettor is identified by a wallet address. Thus, two different addresses are considered as two different bettors. Note that anyone can place bets on behalf of a given address — just providing the address of a bettor as argument. Also, if the same wallet place bets on behalf of different addresses, for the contract, it counts as different bettors.
Regarding score
, note that it is just a string. The contract will consider any valid string as a valid prediction (or selection). Also, the contract will consider two different strings as different results. Thus, only strings that perfectly match final_result
are considered corrected predictions — i.e., winning bets. Therefore, the bookmaker should work in tandem with the oracle to provide to bettors guidance about how to place their bets correctly — i.e., with scores with the right string format.
Regarding deposits and withdrawals, the nano contract transaction must have one and only one deposit, and no withdrawals. Moreover, the deposit must be of the token that the contract works with.
This method call fails in the following situations (non-exhaustive list):
- nano contract transaction does not have one and only one deposit of the token the contract works with; or
- contract is no longer available for placing bets anymore — i.e.,
date_last_offer
has passed.
If this method call succeeds, a new bet is placed on the contract. For example: bettor A (identified by address
), wagered x amount of tokens X (deposit made in the contract), that the result of the betting event will be score
.
set_result
Used one single time by the oracle, to set (in the contract) the result of the betting event. Requires the following argument:
result
: a string with the result of the betting event.
This method call will only succeed if oracle signature is validated, using oracle_script
. Otherwise, it fails. If this method call succeeds, the contract is updated with the result of the betting event — i.e., final_result
attribute of contract is set with result
argument. After that, final_result
does not change anymore.
withdraw
Used by winning bettors to cash out their winnings. Requires no arguments. Regarding deposits and withdrawals, the nano contract transaction must have one and only one withdrawal, and no deposits. Moreover, the deposit must be of the token that the contract works with.
A bettor can withdraw any fraction of their winnings and send it to any address in Hathor blockchain. The withdrawal does not have to be made to the address that identifies them in the contract, nor to any other address in their own wallet.
This method call fails in the following situations (non-exhaustive list):
- oracle has not yet set the result of the betting event — i.e., there is no winning bets yet;
- bettor does not have winning bets (they is not a winning bettor); or
- amount of the withdrawal request is greater than their undrawn winnings.
If this method call succeeds, the winning bettor receives a payout and the contract updates how much of their winnings can still be withdrawn.
View methods
From the set of view methods of this blueprint, the following are relevant to contract users
has_result
get_winner_amount
get_max_withdrawal
has_result
Used to check if the oracle has already set the result of the betting event in the contract. It requires no arguments.
get_winner_amount
Used to check the amount of winnings for a specific bettor. Requires the following argument:
address
: anAddress
string that uniquely identifies a bettor.
It returns zero if bettor does not have winning bets. Otherwise, returns the amount of the winnings (in the token that the contract works with).
get_max_withdrawal
Used to check how much of their winnings a given bettor still has for withdrawing. Requires the following argument:
address
: anAddress
string that uniquely identifies a bettor.
It returns zero if bettor does not have winning bets, or if a winning bettor has already been withdrawn all their winnings. Otherwise, returns the amount of winnings remaining for withdrawing (drawable).
Key takeaways
The purpose of this article, along with the introductory article About the bet blueprint, is to provide you with the necessary knowledge to conceive and design a use case using a bet contract.
What's next?
- About the bet blueprint: to introduce the bet blueprint to those who have decided or are considering using it in their use cases.