Skip to main content

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.

warning

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:

Life cycle of a bet contract

Credits: Bookmaker icon created by Freepik - Flaticon; Bettor icon created by Smashicons - Flaticon; Oracle icon created by Becris - Flaticon; Winning bettor icon created by Freepik - Flaticon; and Hathor users icon created by SBTS from the Noun Project.

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:

Anatomy of a nano contract

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: a TxOutputScript object used to define the oracle of the contract.
  • token_uid: a TokenUid object used to define the token the contract works with.
  • date_last_offer: a Timestamp 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: an Address 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: an Address 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: an Address 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.