Inside Ethoccer : How to build a World Cup Predictions Game on Ethereum

Introduction

Ethoccer is a FIFA World Cup 2018 match result prediction game that runs on the blockchain. Anyone can play it for free as Ethoccer is deployed on Ropsten Test Network*. In addition, users who have the highest scores at the end of the World Cup will be given ETH of Main Network*.

  • play for free
  • get prizes

For details, please see the following page.

※ The Main Network is a network where “real” Ethereum is running, the Test Network refers to the network where “Ethereum” for “developer” is running. ETH on Test Network can be obtained for free, and developers can check the operation free of charge by first deploying smart contract on this network

This article will explain Ethoccer’s internals. This is mainly targeted towards DApps developers, especially developers who are about to develop a Dapp.
Also, in this article we will mainly introduce the Solidity code, and we will consider showing the front-end code as well if anyone is interested.

System

Reference

  • Solidity
    The programming language to write smart contracts running on Ethereum.
  • Truffle
    A framework for testing and deploying smart contract written in Solidity.
  • Metamask
    Ethereum wallet implemented as a google chrome addon.
  • Trust
    Ethereum wallet and browser on mobile devices.
  • Web3.js
    API for accessing smart contract from Javascript.
  • Ganache (not in above figure)
    A test network that runs in the local environment, which helps us to increase development efficiency.

All Solidity Code

Solidity Code Explanation

Contract inheritance relationship

contract StringHelper
contract MultiOwnable
contract Pausable is MultiOwnable
contract EthoccerType
contract EthoccerWeb3Interface is EthoccerType
contract Ethoccer is EthoccerWeb3Interface, Pausable, StringHelper

StringHelper

This contract defines functions that are helpful for using string type. String in Solidity doesn’t have much functions for now. For example, you can not compare two string variables.

MultiOwnable

Ethoccer contracts have functions that only owner can execute, such as createGame and updateScores. The setting for that is described in MultiOwnable.
This contract is an improvement of Ownable of OpenZeppelin to have multiple owner.

Pausable

If a bug is found in the contract, it’ll be necessary to temporarily stop the contract to deal with it. Pausable is the contract in which the setting is written.
We refer to Pausable of OpenZeppelin, again.

EthoccerType

It defines structs and enums used in Ethoccer.

EthoccerWeb3Interface

Functions and events that can be accessed through Web3.js are summarized in this contract.
The main purpose is to make it easier for front-end engineers to find available functions just by looking at this contract.

Ethoccer

This is the main contract of Ethoccer which inherits all the contracts introduced so far.
Ethoccer contract has states “games” and “users” inside, and it works by changing these two states using functions defined in EthoccerWeb3Interface.

// @dev Game
mapping(string => Game) internal games;
string[] internal gameList; // list of game IDs
// @dev User
mapping(address => User) internal users;
address[] internal userList; // list of user addresses

Game and User are defined in EthoccerType like the followings.

struct Game {
string id;
string country1;
string country2;
uint8 numberGoalCountry1;
uint8 numberGoalCountry2;
string time;
string group;
bool isOpen;
bool hasResult;
uint256[3] pointsPlaced;
uint256 betsLength;
mapping(uint256 => Bet) bets;
bool initiated;
}
struct User {
uint256 point;
uint256 userElemsLength;
mapping (uint256 => UserElem) userElems;
bool initiated;
}
struct UserElem {
string gameId;
uint256 betId;
}
  • games
    All game information is stored in games. An element is added by owner calling createGame.
    While a game is open, users can bet (vote) on the game. Betted points are saved in pointsPlaced, and each bet is stored in bets mapping.
    When the owner calls updateScores and gives the result to the game, appropriate amount of points are awarded to users based on these data.
  • users
    users stores all user information. An element, User struct, is added when the user first uses Ethoccer. In this case, createUser is called internally.
    The initial value of the points is 100. It decreases each time the user bets, and increases when user obtain the dividend points. User holds all the information of his/her bets in userElems.

Conclusion

In this article, we introduced Ethoccer’s system.
Ethoccer is an experimental project, and there is still room for improvement in our contract.
For example, it seems unnecessary to have the information of bet stored in the User struct. Originally, we implemented it so that all bet information can be returned from the user’s address, but “information only for getter (information not necessary to refer inside smart contract)” should be implemented as Event to save gas costs. By using Web3.js, all past Events can be easily referred to as follows.

getPlaceBetEvents() { 
return new Promise((resolve, reject) => {
const events = this.instance.PlaceBetEvent({}, {fromBlock: 0, toBlock: 'latest'})
events.get((err, logs) => {
if (err) return reject(err)
return resolve(logs)
})
})
}

While there is still room for improvement as such, we learned a lot through developing Ethoccer, and we also gained a lot of know-how in DApps development. We think that there is some things that can only be learned by actually developing and getting user feedback. For example,

  • How to save gas cost
  • Implementation considering pending and rejection
  • Implementation considering migration and update of data
  • Tutorial for non DApps Users

We would like to contribute to the DApps developer community with feedback obtained from users and knowledge obtained by analyzing user activities through our future services.

We hope that not only DApps users, but also the number of DApps developers will increase. We would be glad if this article helps new DApps developers to get started.