This contract represents a Tezos contract written in CameLIGO in which users can bet on events added by the Admin or an Oracle.
The current implementation of the contract is as follows :
- a
Bettingcontract, the main contract - (optional) a
mock Oraclecontract - (optional) a
callbackcontract for theBetting - (optional) a
callbackcontract for themock Oracle
type storage = {
manager : address;
oracle_address : address;
bet_config : bet_config_type;
events : (nat, event_type) map;
events_bets : (nat, event_bets) map;
events_index : nat;
metadata : (string, bytes) map;
}manager: Manager account of the Betting contractoracle_address: Oracle contract allowed to add Events and update themevents,events_bets,events_index: Events mapped to their info, their attached bets, and the latest index
type bet_config_type = {
is_betting_paused : bool;
is_event_creation_paused : bool;
min_bet_amount : tez;
retained_profit_quota : nat;
}is_betting_paused: is Betting on Events paused (true), or is it allowed (false)is_event_creation_paused: is the creation of new Events paused (true), or is it allowed (false)min_bet_amount: the minimum amount to Bet on an Event in a single transactionretainedProfit: the quota to be retained from Betting profits (deduced as operating gains to the contract, shown as percentage, theorical max is 100)
- Deploy the Betting contract with an initial storage
- The
storage.bet_config.is_betting_pausedandstorage.bet_config.is_event_creation_pausedmust have as valuefalse - Add an Event using the
storage.manageraddress - Add a Bet to the Event using an address that is not
storage.managernorstorage.oracle_address - (optional) Add more bets to the first team or second team on the Event
- Update the Bet to specify the outcome in
is_draw, and the winning Team inis_team_one_winif it is not a draw, usingstorage.managerorstorage.oracle_address - Finalize the Bet using
storage.manager
let init_bet_config : bet_config_type = {
is_betting_paused = false;
is_event_creation_paused = false;
min_bet_amount = 5tez;
retained_profit_quota = 10n;
} in
let init_storage : storage = {
manager = "tz1******************";
oracle_address = "KT1******************";
bet_config = init_bet_config;
events = (Map.empty : (nat, event_type) map);
events_bets = (Map.empty : (nat, event_bets) map);
events_index = 0n;
metadata = (Map.empty : (string, bytes) map);
} in- To compile the Betting contract to Michelson code :
docker run --platform linux/amd64 --rm -v "$(PWD)":"$(PWD)" -w "$(PWD)" ligolang/ligo:stable compile contract src/contracts/cameligo/betting/main.mligo > src/compiled/betting.tz- To compile the Betting contract to Michelson code in JSON format :
docker run --platform linux/amd64 --rm -v "$(PWD)":"$(PWD)" -w "$(PWD)" ligolang/ligo:stable compile contract src/contracts/cameligo/betting/main.mligo --michelson-format json > src/compiled/betting.json- Using
tz1bdTsc3QdAj1935KiMxou6frwdm5RDdssTas example forstorage.manager - Using
KT1KMjSSDxTAUZAb7rgGYx3JF4Yz1cwQpwUias example forstorage.oracle_address
docker run --platform linux/amd64 --rm -v "$(PWD)":"$(PWD)" -w "$(PWD)" ligolang/ligo:stable compile storage ./contracts/cameligo/betting/main.mligo '{manager = ("tz1bdTsc3QdAj1935KiMxou6frwdm5RDdssT" : address); oracle_address = ("KT1KMjSSDxTAUZAb7rgGYx3JF4Yz1cwQpwUi" : address); bet_config = {is_betting_paused = false; is_event_creation_paused = false; min_bet_amount = 5tez; retained_profit_quota = 10n}; events = (Map.empty : (nat, TYPES.event_type) map); events_bets = (Map.empty : (nat, TYPES.event_bets) map); events_index = 0n; metadata = (Map.empty : (string, bytes) map)}' -e main- For entrypoint SendValue
docker run --platform linux/amd64 --rm -v "$(PWD)":"$(PWD)" -w "$(PWD)" ligolang/ligo:stable run dry-run src/contracts/cameligo/betting/main.mligo 'SendValue(unit)' '37' -e main- Compile the storage into Michelson expression :
- Using
tz1bdTsc3QdAj1935KiMxou6frwdm5RDdssTas example forstorage.manager - Using
KT1KMjSSDxTAUZAb7rgGYx3JF4Yz1cwQpwUias example forstorage.oracle_address
docker run --platform linux/amd64 --rm -v "$(PWD)":"$(PWD)" -w "$(PWD)" ligolang/ligo:stable compile storage ./contracts/cameligo/betting/main.mligo '{manager = ("tz1bdTsc3QdAj1935KiMxou6frwdm5RDdssT" : address); oracle_address = ("KT1KMjSSDxTAUZAb7rgGYx3JF4Yz1cwQpwUi" : address); bet_config = {is_betting_paused = false; is_event_creation_paused = false; min_bet_amount = 5tez; retained_profit_quota = 10n}; events = (Map.empty : (nat, TYPES.event_type) map); events_bets = (Map.empty : (nat, TYPES.event_bets) map); events_index = 0n; metadata = (Map.empty : (string, bytes) map)}' -e main- This command produces the following Michelson storage :
(Pair (Pair (Pair (Pair (Pair False False) 5000000 10) {}) {} 0)
(Pair "tz1bdTsc3QdAj1935KiMxou6frwdm5RDdssT" {})
"KT1KMjSSDxTAUZAb7rgGYx3JF4Yz1cwQpwUi")- Deploy with tezos-client CLI using the above Michelson code :
tezos-client originate contract betting transferring 1 from '$USER_ADDRESS' running 'src/compiled/betting.tz' --init '(Pair (Pair (Pair (Pair (Pair False False) 5000000 10) {}) {} 0)(Pair "tz1bdTsc3QdAj1935KiMxou6frwdm5RDdssT" {})"KT1KMjSSDxTAUZAb7rgGYx3JF4Yz1cwQpwUi")'type storage = {
isPaused : bool;
manager : address;
signer : address;
events : (nat, event_type) map;
events_index : nat;
metadata : (string, bytes) map;
}isPaused: If the creation of events on the contract is pausedmanager: Manager account of the Betting contractsigner: Signer contract allowed to add Events and update them (usually a backend script)events,events_index: Events mapped to their info and the latest index
type event_type =
[@layout:comb] {
name : string;
videogame : string;
begin_at : timestamp;
end_at : timestamp;
modified_at : timestamp;
opponents : { team_one : string; team_two : string};
game_status : game_status;
}The following entrypoints are available :
- ChangeManager
- ChangeSigner
- SwitchPause
- AddEvent
- GetEvent
- UpdateEvent
For full details, please consult the Oracle contracts in src/contracts/cameligo/oracle
let store : storage = {
isPaused: False;
manager: "tz1******************";
signer: "tz1******************";
events: (Map.empty : (nat, event_type) map);
events_index: 0n;
}It is possible to use an external API to collect sample game data about eSports titles such as CS:GO, DOTA 2, and others.
Some sample requests to get data from a third-party API can be found in the Backend folder. We are using here the API provider : Pandascore.
The API access tokens can be requested by creating an account on Pandascore here
The API reference documentation can be viewed here
The scripts can be executed as follows :
node backend/matches_past.js
node backend/matches_running.js
node backend/matches_upcoming.jsThe result of the queries will be a JSON file in the Backend folder, which will contain game info.
It is possible to inject this data to the Oracle after formatting manually, or automatically using a signer/broadcaster.