Created
June 21, 2018 11:28
-
-
Save brunobuddy/551346e025f0b85e521057e654c7fd9f to your computer and use it in GitHub Desktop.
BetDemocracy V 0.1 Contract
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity 0.4.17; | |
import "./JsmnSolLib.sol"; | |
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol"; | |
import "github.com/Arachnid/solidity-stringutils/src/strings.sol"; | |
contract BetDemocracy is usingOraclize { | |
using strings for *; | |
enum Result { Unknown, HomeWin, AwayWin, Draw } | |
enum Prediction { Home, HomeOrDraw, Draw, AwayOrDraw, Away, HomeOrAway } | |
struct Match { | |
Result result; | |
string apiResult; | |
mapping(uint => Bet) bets; | |
uint betCount; | |
uint startDate; | |
bool exists; // explicit bool to test resource existence | |
} | |
struct Bet { | |
address initiator; | |
address taker; | |
uint16 initiatorOdds; // odds * 10**2 | |
uint256 initiatorStake; // stake in wei | |
Prediction initiatorPrediction; | |
address winner; | |
bool withdrawn; | |
bool exists; // explicit bool to test resource existence | |
} | |
mapping (uint32 => Match) public matches; | |
mapping (bytes32 => uint32) public pendingQueries; | |
event Log(string _description); | |
event Log(address _address); | |
event Log(uint _amount); | |
event NewOraclizeQuery(string description); | |
// accepts sending value to contract | |
function acceptValue() public payable {} | |
// Opens a new bet for a defined game | |
function createBet(uint32 _matchId, uint16 _odds, Prediction _prediction) public payable { | |
require(msg.value >= 0.0001 ether); | |
require(_odds >= 105 && _odds <= 2100); // Odds between 1.05 and 21 | |
require(matches[_matchId].exists); | |
require(now < matches[_matchId].startDate); | |
// Add bet to "bet" mapping and increment count | |
matches[_matchId].bets[matches[_matchId].betCount] = | |
Bet(msg.sender, address(0x0), _odds, msg.value, _prediction, address(0x0), false, true); | |
matches[_matchId].betCount++; | |
} | |
// Take an open bet | |
function takeBet(uint32 _matchId, uint _betIndex) public payable returns (bool succeeded) { | |
require(matches[_matchId].exists); | |
require(now < matches[_matchId].startDate); | |
Bet memory bet = matches[_matchId].bets[_betIndex]; | |
require(bet.exists); | |
require(bet.taker == address(0x0)); | |
require(matches[_matchId].result == Result.Unknown); | |
// Ensure that taker paid enough money to take the bet | |
uint takerStake = (bet.initiatorStake * bet.initiatorOdds - bet.initiatorStake * 10 ** 2) / 10 ** 2; | |
require(msg.value == takerStake); | |
matches[_matchId].bets[_betIndex].taker = msg.sender; | |
Log("Bet has been taken"); | |
return true; | |
} | |
// Withdraw bet pot (winner only) | |
function withdrawBet(uint32 _matchId, uint _betIndex) public returns (bool succeeded) { | |
Match memory betMatch = matches[_matchId]; | |
Bet memory bet = matches[_matchId].bets[_betIndex]; | |
require(now > betMatch.startDate + 4 hours); | |
require(!bet.withdrawn); | |
require(betMatch.result != Result.Unknown); | |
// Determine winner and transfer prize | |
if (betMatch.result == Result.HomeWin) { | |
matches[_matchId].bets[_betIndex].winner = (bet.initiatorPrediction == Prediction.Home | |
|| bet.initiatorPrediction == Prediction.HomeOrDraw || bet.initiatorPrediction == Prediction.HomeOrAway) ? | |
bet.initiator : bet.taker; | |
} else if (betMatch.result == Result.AwayWin) { | |
matches[_matchId].bets[_betIndex].winner = (bet.initiatorPrediction == Prediction.Away | |
|| bet.initiatorPrediction == Prediction.AwayOrDraw || bet.initiatorPrediction == Prediction.HomeOrAway) ? | |
bet.initiator : bet.taker; | |
} else { | |
matches[_matchId].bets[_betIndex].winner = (bet.initiatorPrediction == Prediction.HomeOrDraw | |
|| bet.initiatorPrediction == Prediction.AwayOrDraw || bet.initiatorPrediction == Prediction.Draw) ? | |
bet.initiator : bet.taker; | |
} | |
uint256 prize = bet.initiatorStake * bet.initiatorOdds / 100; | |
Log(prize); | |
matches[_matchId].bets[_betIndex].winner.transfer(prize); | |
matches[_matchId].bets[_betIndex].withdrawn = true; | |
return true; | |
} | |
// Refund initiator if nobody took his or her bet | |
function refundBet(uint32 _matchId, uint _betIndex) public returns (bool _refunded) { | |
Bet memory bet = matches[_matchId].bets[_betIndex]; | |
require(bet.exists); | |
require(!bet.withdrawn); | |
require(bet.initiator == msg.sender); | |
require(bet.taker == address(0x0)); | |
require(now > matches[_matchId].startDate); | |
msg.sender.transfer(bet.initiatorStake); | |
matches[_matchId].bets[_betIndex].withdrawn = true; | |
return true; | |
} | |
// Orcale response (scheduled to arrive after match ending) | |
function __callback(bytes32 _queryId, string _apiResult) { | |
require(msg.sender == oraclize_cbAddress()); | |
// find matchId | |
uint32 matchId = pendingQueries[_queryId]; | |
// Store API result into Match (for debug purposes) | |
matches[matchId].apiResult = _apiResult; | |
matches[matchId].result = getResult(_apiResult); | |
delete pendingQueries[_queryId]; | |
} | |
// Returns enum Result based on JSON string received from api | |
function getResult(string json) public returns (Result result) { | |
uint returnValue; | |
JsmnSolLib.Token[] memory tokens; | |
uint tokenCount; | |
int goalsHomeTeam; | |
int goalsAwayTeam; | |
(returnValue, tokens, tokenCount) = JsmnSolLib.parse(json, 11); | |
require(returnValue == 0 && (tokenCount == 5 || tokenCount == 11)); | |
// API returns halftime data | |
if (tokenCount == 11) { | |
JsmnSolLib.Token memory t = tokens[10]; | |
goalsHomeTeam = JsmnSolLib.parseInt(JsmnSolLib.getBytes(json, t.start, t.end)); | |
t = tokens[8]; | |
goalsAwayTeam = JsmnSolLib.parseInt(JsmnSolLib.getBytes(json, t.start, t.end)); | |
// API does not have/return halftime Data | |
} else if (tokenCount == 5) { | |
t = tokens[4]; | |
goalsHomeTeam = JsmnSolLib.parseInt(JsmnSolLib.getBytes(json, t.start, t.end)); | |
t = tokens[2]; | |
goalsAwayTeam = JsmnSolLib.parseInt(JsmnSolLib.getBytes(json, t.start, t.end)); | |
} | |
// Update result based on goals | |
if (goalsHomeTeam > goalsAwayTeam) { | |
return Result.HomeWin; | |
} else if (goalsHomeTeam == goalsAwayTeam) { | |
return Result.Draw; | |
} else if (goalsHomeTeam < goalsAwayTeam) { | |
return Result.AwayWin; | |
} else { | |
return Result.Unknown; | |
} | |
} | |
/* | |
Read functions | |
*/ | |
function readBet(uint32 _matchId, uint _betIndex) public constant returns (address initiator, | |
address taker, uint16 initiatorOdds, uint256 initiatorStake, Prediction initiatorPrediction, | |
address winner, bool withdrawn, bool exists) { | |
Bet memory bet = matches[_matchId].bets[_betIndex]; | |
return (bet.initiator, bet.taker, bet.initiatorOdds, bet.initiatorStake, | |
bet.initiatorPrediction, bet.winner, bet.withdrawn, bet.exists); | |
} | |
function getBalance() public constant returns (uint) { | |
return address(this).balance; | |
} | |
// Helper function : TODO: move to library | |
function uintToString(uint i) internal pure returns (string) { | |
if (i == 0) return "0"; | |
uint j = i; | |
uint len; | |
while (j != 0) { | |
len++; | |
j /= 10; | |
} | |
bytes memory bstr = new bytes(len); | |
uint k = len - 1; | |
while (i != 0) { | |
bstr[k--] = byte(48 + i % 10); | |
i /= 10; | |
} | |
return string(bstr); | |
} | |
// Adds one match and schedule Oraclize call | |
function addMatch(uint32 _matchId, uint _startDate) public payable { | |
bytes32 queryId; | |
NewOraclizeQuery("Oraclize query were scheduled..."); | |
// Group matches | |
matches[_matchId] = Match({ | |
result: Result.Unknown, | |
apiResult: "", | |
betCount: 0, | |
startDate: _startDate, | |
exists: true | |
}); | |
queryId = oraclize_query(matches[_matchId].startDate + 4 * 3600, "URL", getApiPath(_matchId), 500000); | |
pendingQueries[queryId] = _matchId; | |
} | |
// Returns API path for defined match | |
function getApiPath(uint32 _matchId) internal pure returns (string path) { | |
return path = "json(http://api.football-data.org/v1/fixtures/".toSlice().concat(uintToString(_matchId).toSlice()).toSlice().concat("?head2head=0).fixture.result".toSlice()); | |
} | |
function BetDemocracy() public payable { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment