骰子博彩游戏合约设计
一、功能接口
1. 质押deposit
由用户发起,用户将个人账户中token质押给平台,从而可以进入平台去参与平台活动。
2. 赎回withdraw
由用户发起,在用户结束平台活动需要离开时,发起赎回曾质押给平台的token到个人账户。
3. 开启一期**openbet
由平台发起,平台启动一期**,玩家可以参与**。
4. 结束一期** closurebet
由平台发起,平台关闭一期**,所以玩家的**被锁定。
5. **offerbet
由用户发起,用户参与平台开启的**,需要在一期**开启之后执行。
6. 取消**canneloffer
由用户发起,用户取消曾参与的**,需要在该期**结束之前执行。
7. 开奖reveal
由平台发起,平台在一期**上进行结果操作。
二、数据存储
1. 质押赎回账户表account_index
个人账户token质押给平台和从平台赎回token需要一个账户表来管理个人账户token信息,账户表数据结构如下:
a. 个人账户名称
b. 资产额
2. **期数记录表g_bet_index
游戏从第1期开始,随后每开启一期游戏,期数自动加1,游戏期数记录表记录了总的**期数,同时也记录了当前正在进行或者要开启的下一期**的期数,**期数记录表结构如下:
a. 记录id
b. 当前正在进行的**期数
c. 当前正在进行的**期名称
d. 当前**开启关闭状态
e. 当前**结算状态
3. **记录表bet_index
在一期**开启时间窗口,平台用户可以自由**以及取消**,**记录表则记录了用户的**情况,**记录表数据结构如下:
a. 记录id
b. **期数
c. 个人账户名称
d. **资产额
e. **信息
三、接口实现设计
a. 质押赎回
1. 用户发起质押操作,参数包括质押资产额
2. 从user账户转账token到dice账户,dice.xxx合约将调用eosio.token的transfer action执行转账操作,将user个人账户中token转账到合约账户dice
3. 修改质押赎回账户表,记录user个人用户的质押信息,添加新记录或者修改记录
4. 用户发起赎回操作
5. 从dice账户转账token到user个人账户,dice.xxx合约将调用eosio.token的transfer action执行转账
6. 修改质押赎回账户表,修改user个人用户的质押信息,修改记录或者删除记录
b. 开启**、结束**以及开奖
1. 平台发起一次openbet
2. 检查新一期**是否合法,检查是否有正在进行的**,如果没有则当前期数+1,同时**开启
3. 平台发起一次closurebet
4. 检查关闭的**是否合法,检查是否有正在进行的**,如果有,则关闭**
5. 平台发起一次开奖
6. 计算改期开奖结果,计算池中各用户的**信息并给出各个用户的开奖结果
7. 开奖结果兑现,将开奖结果兑现到各用户的质押上
c. **及取消**
1. 用户发起**,参数包括**资产额、**信息
2. 检查该期**是否在开放窗口期,如果不在开放窗口期则不能**
3. 修改用户质押资产额
4. 修改用户**资产额以及**信息
5. 用户发起取消**
6. 检查该期**是否在开放窗口期,如果不在开放窗口期则不能取消**
7. 修改用户**资产额及**信息
8. 修改用户质押资产额
四、部署合约
1. 创建合约账户
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 create account eosio dice.xxx EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
2. 部署合约
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 set contract dice.xxx /home/kingnet/tangy/eos/mycontracts/dice.xxx
五、平台接口使用
平台接口需要合约账户
1. 开启**
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx openbet '{}' -p dice.xxx
2. 关闭**
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx closurebet '{}' -p dice.xxx
3. 开奖
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx reveal '{}' -p dice.xxx
六、用户接口使用
1. 质押
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx deposit '{"from":"alice", "quantity":"100.0000 EOS"}' -p alice
2. 赎回
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx withdraw '{"to":"alice", "quantity":"100.0000 EOS"}' -p alice
以下用户接口需要在**开启窗口才能被执行
3. 用户**
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx offerbet '{"bet":"10.0000 EOS", "player":"alice","info":0}' -p alice
4. 取消**
cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action dice.xxx canceloffer '{"player":"alice"}' -p alice
七、合约代码
-
/** -
* @file -
* @copyright defined in eos/LICENSE.txt -
*/ -
#include <utility> -
#include <vector> -
#include <string> -
#include <eosiolib/eosio.hpp> -
#include <eosiolib/asset.hpp> -
#include <eosiolib/contract.hpp> -
#include <eosiolib/crypto.h> -
using eosio::key256; -
using eosio::indexed_by; -
using eosio::const_mem_fun; -
using eosio::asset; -
using eosio::permission_level; -
using eosio::action; -
using eosio::print; -
using eosio::name; -
class dice : public eosio::contract { -
public: -
dice(account_name self) : eosio::contract(self), -
bets(_self, _self), -
gbet(_self, _self), -
accounts(_self, _self) { -
} -
//@abi action -
void offerbet(const asset& bet, account_name player, const uint64_t betinfo) { -
eosio_assert( bet.symbol == S(4,EOS) , "only EOS token allowed" ); -
eosio_assert( bet.is_valid(), "invalid bet" ); -
eosio_assert( bet.amount > 0, "must bet positive quantity" ); -
// -
require_auth( player ); -
auto cur_player_itr = accounts.find( player ); -
eosio_assert(cur_player_itr != accounts.end(), "unknown account"); -
eosio_assert(cur_player_itr->balance >= bet, "insufficient balance"); -
auto cur_gbet_itr = gbet.begin(); -
eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build"); -
eosio_assert(cur_gbet_itr->open == 1, "bet is not open"); -
eosio_assert(cur_gbet_itr->reveal == 0, "bet is revealed"); -
uint64_t betid = cur_gbet_itr->betid; -
uint64_t exist_bet = false; -
auto bybetid_index = bets.template get_index<N(bybetid)>(); -
auto cur_bets_itr = bybetid_index.find(betid); -
while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) { -
if(cur_bets_itr->owner == player) { -
exist_bet = true; -
break; -
} -
cur_bets_itr ++; -
} -
eosio_assert(exist_bet == false, "bet is done"); -
// Store new offer -
auto new_bet_itr = bets.emplace(_self, [&](auto& rbet){ -
rbet.id = bets.available_primary_key(); -
rbet.balance = bet; -
rbet.owner = player; -
rbet.betid = betid; -
rbet.info = betinfo; -
}); -
// Update player's accounts -
accounts.modify( cur_player_itr, 0, [&](auto& acnt) { -
eosio_assert( acnt.balance >= bet, "insufficient balance" ); -
acnt.balance -= bet; -
}); -
} -
//@abi action -
void canceloffer(account_name player) { -
// -
require_auth( player ); -
auto cur_gbet_itr = gbet.begin(); -
eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build"); -
eosio_assert(cur_gbet_itr->open == 1, "bet is closed"); -
eosio_assert(cur_gbet_itr->reveal == 0, "bet is revealed"); -
uint64_t betid = cur_gbet_itr->betid; -
uint64_t exist_bet = false; -
auto bybetid_index = bets.template get_index<N(bybetid)>(); -
auto cur_bets_itr = bybetid_index.find(betid); -
while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) { -
if(cur_bets_itr->owner == player) { -
exist_bet = true; -
break; -
} -
cur_bets_itr ++; -
} -
eosio_assert(exist_bet == true, "no bet"); -
// Update player's accounts -
auto cur_player_itr = accounts.find( player ); -
if( cur_player_itr == accounts.end() ) { -
cur_player_itr = accounts.emplace(_self, [&](auto& acnt){ -
acnt.owner = player; -
}); -
} -
accounts.modify( cur_player_itr, 0, [&](auto& acnt) { -
acnt.balance += cur_bets_itr->balance; -
}); -
bybetid_index.erase(cur_bets_itr); -
//bets.erase(cur_bet_itr); -
} -
//@abi action -
void openbet() { -
// -
require_auth(_self); -
// Create global bet counter if not exists -
auto cur_gbet_itr = gbet.begin(); -
if( cur_gbet_itr == gbet.end() ) { -
cur_gbet_itr = gbet.emplace(_self, [&](auto& g_bet){ -
g_bet.id = gbet.available_primary_key(); -
g_bet.betid = 0; -
g_bet.open = 0; -
g_bet.reveal = 1; -
}); -
} -
eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build"); -
eosio_assert(cur_gbet_itr->open == 0, "bet is opened"); -
eosio_assert(cur_gbet_itr->reveal == 1, "bet is not reveal"); -
// Increment global bet counter -
gbet.modify(cur_gbet_itr, 0, [&](auto& g_bet){ -
g_bet.betid++; -
g_bet.open = 1; -
g_bet.reveal = 0; -
}); -
} -
//@abi action -
void closurebet() { -
// -
require_auth(_self); -
auto cur_gbet_itr = gbet.begin(); -
eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build"); -
eosio_assert(cur_gbet_itr->open == 1, "bet is closure"); -
eosio_assert(cur_gbet_itr->reveal == 0, "reveal is done"); -
// udpate global bet status -
gbet.modify(cur_gbet_itr, 0, [&](auto& g_bet){ -
g_bet.open = 0; -
}); -
} -
//@abi action -
void reveal() { -
// -
require_auth(_self); -
auto cur_gbet_itr = gbet.begin(); -
eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build"); -
eosio_assert(cur_gbet_itr->open == 0, "bet is open"); -
eosio_assert(cur_gbet_itr->reveal == 0, "reveal is done"); -
// -
uint64_t bet_result = 0; -
uint64_t betid = cur_gbet_itr->betid; -
// -
{ -
uint32_t t_now = now(); -
checksum256 hash; -
sha256((char*)(&t_now), sizeof(uint32_t), &hash); -
bet_result = (hash.hash[15]) % 2; -
} -
// -
asset total_balance; -
asset win_balance; -
auto bybetid_index = bets.template get_index<N(bybetid)>(); -
auto cur_bets_itr = bybetid_index.find(betid); -
while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) { -
total_balance += cur_bets_itr->balance; -
if(cur_bets_itr->info == bet_result) -
win_balance += cur_bets_itr->balance; -
cur_bets_itr++; -
} -
if(win_balance.amount == 0) { -
bybetid_index = bets.template get_index<N(bybetid)>(); -
cur_bets_itr = bybetid_index.find(betid); -
while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) { -
auto use_balance = cur_bets_itr->balance; -
auto cur_player_itr = accounts.find( cur_bets_itr->owner ); -
if( cur_player_itr == accounts.end() ) { -
cur_player_itr = accounts.emplace(_self, [&](auto& acnt){ -
acnt.owner = cur_bets_itr->owner; -
}); -
} -
accounts.modify( cur_player_itr, 0, [&]( auto& acnt ) { -
acnt.balance += use_balance; -
}); -
cur_bets_itr ++; -
} -
} else { -
bybetid_index = bets.template get_index<N(bybetid)>(); -
cur_bets_itr = bybetid_index.find(betid); -
while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) { -
if(cur_bets_itr->info == bet_result) { -
//auto use_balance = (cur_bets_itr->balance / win_balance) * total_balance; -
auto use_balance = (cur_bets_itr->balance * total_balance.amount) / win_balance.amount; -
auto cur_player_itr = accounts.find( cur_bets_itr->owner ); -
if( cur_player_itr == accounts.end() ) { -
cur_player_itr = accounts.emplace(_self, [&](auto& acnt){ -
acnt.owner = cur_bets_itr->owner; -
}); -
} -
accounts.modify( cur_player_itr, 0, [&]( auto& acnt ) { -
acnt.balance += use_balance; -
}); -
} -
cur_bets_itr ++; -
} -
} -
// udpate global bet status -
gbet.modify(cur_gbet_itr, 0, [&](auto& g_bet){ -
g_bet.reveal = 1; -
}); -
} -
//@abi action -
void deposit( const account_name from, const asset& quantity ) { -
require_auth( from ); -
eosio_assert( quantity.is_valid(), "invalid quantity" ); -
eosio_assert( quantity.amount > 0, "must deposit positive quantity" ); -
auto itr = accounts.find(from); -
if( itr == accounts.end() ) { -
itr = accounts.emplace(_self, [&](auto& acnt){ -
acnt.owner = from; -
}); -
} -
action( -
permission_level{ from, N(active) }, -
N(eosio.token), N(transfer), -
std::make_tuple(from, _self, quantity, std::string("")) -
).send(); -
accounts.modify( itr, 0, [&]( auto& acnt ) { -
acnt.balance += quantity; -
}); -
} -
//@abi action -
void withdraw( const account_name to, const asset& quantity ) { -
require_auth( to ); -
eosio_assert( quantity.is_valid(), "invalid quantity" ); -
eosio_assert( quantity.amount > 0, "must withdraw positive quantity" ); -
auto itr = accounts.find( to ); -
eosio_assert(itr != accounts.end(), "unknown account"); -
accounts.modify( itr, 0, [&]( auto& acnt ) { -
eosio_assert( acnt.balance >= quantity, "insufficient balance" ); -
acnt.balance -= quantity; -
}); -
action( -
permission_level{ _self, N(active) }, -
N(eosio.token), N(transfer), -
std::make_tuple(_self, to, quantity, std::string("")) -
).send(); -
if( itr->is_empty() ) { -
accounts.erase(itr); -
} -
} -
//@abi action -
void reset() { -
// -
require_auth( _self ); -
auto cur_gbet_itr = gbet.begin(); -
while(cur_gbet_itr != gbet.end()) { -
cur_gbet_itr = gbet.erase(cur_gbet_itr); -
} -
auto cur_bet_itr = bets.begin(); -
while(cur_bet_itr != bets.end()) { -
cur_bet_itr = bets.erase(cur_bet_itr); -
} -
} -
private: -
//@abi table bet i64 -
struct bet { -
uint64_t id; -
account_name owner; -
asset balance; -
uint64_t betid; -
uint64_t info; -
uint64_t primary_key()const { return id; } -
uint64_t by_betid()const { return betid; } -
account_name by_owner() const { return owner; } -
EOSLIB_SERIALIZE( bet, (id)(owner)(balance)(betid)(info) ) -
}; -
typedef eosio::multi_index< N(bet), bet, -
indexed_by< N(bybetid), const_mem_fun<bet, uint64_t, &bet::by_betid > >, -
indexed_by< N(byowner), const_mem_fun<bet, account_name, &bet::by_owner > > > bet_index; -
//@abi table gbet i64 -
struct gbet { -
uint64_t id; -
uint64_t betid; -
uint64_t betname; -
uint64_t open = 0; -
uint64_t reveal = 0; -
uint64_t primary_key()const { return id; } -
EOSLIB_SERIALIZE( gbet, (id)(betid)(betname)(open)(reveal) ) -
}; -
typedef eosio::multi_index< N(gbet), gbet> gbet_index; -
//@abi table account i64 -
struct account { -
account( account_name o = account_name() ):owner(o){ -
} -
account_name owner; -
asset balance; -
bool is_empty()const { return !( balance.amount); } -
uint64_t primary_key()const { return owner; } -
EOSLIB_SERIALIZE( account, (owner)(balance) ) -
}; -
typedef eosio::multi_index< N(account), account> account_index; -
bet_index bets; -
gbet_index gbet; -
account_index accounts; -
}; -
EOSIO_ABI( dice, (offerbet)(canceloffer)(openbet)(closurebet)(reveal)(deposit)(withdraw)(reset) )
八、合约ABI
{
"____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-03-29T02:09:11",
"types": [],
"structs": [{
"name": "bet",
"base": "",
"fields": [{
"name": "id",
"type": "uint64"
},{
"name": "owner",
"type": "account_name"
},{
"name": "balance",
"type": "asset"
},{
"name": "betid",
"type": "uint64"
},{
"name": "info",
"type": "uint64"
}
]
},{
"name": "gbet",
"base": "",
"fields": [{
"name": "id",
"type": "uint64"
},{
"name": "betid",
"type": "uint64"
},{
"name": "betname",
"type": "uint64"
},{
"name": "open",
"type": "uint64"
},{
"name": "reveal",
"type": "uint64"
}
]
},{
"name": "account",
"base": "",
"fields": [{
"name": "owner",
"type": "account_name"
},{
"name": "balance",
"type": "asset"
}
]
},{
"name": "offerbet",
"base": "",
"fields": [{
"name": "bet",
"type": "asset"
},{
"name": "player",
"type": "account_name"
},{
"name": "info",
"type": "uint64"
}
]
},{
"name": "canceloffer",
"base": "",
"fields": [{
"name": "player",
"type": "account_name"
}
]
},{
"name": "openbet",
"base": "",
"fields": [
]
},{
"name": "closurebet",
"base": "",
"fields": [
]
},{
"name": "reveal",
"base": "",
"fields": [
]
},{
"name": "deposit",
"base": "",
"fields": [{
"name": "from",
"type": "account_name"
},{
"name": "quantity",
"type": "asset"
}
]
},{
"name": "withdraw",
"base": "",
"fields": [{
"name": "to",
"type": "account_name"
},{
"name": "quantity",
"type": "asset"
}
]
},{
"name": "reset",
"base": "",
"fields": [
]
}
],
"actions": [{
"name": "offerbet",
"type": "offerbet",
"ricardian_contract": ""
},{
"name": "canceloffer",
"type": "canceloffer",
"ricardian_contract": ""
},{
"name": "openbet",
"type": "openbet",
"ricardian_contract": ""
},{
"name": "closurebet",
"type": "closurebet",
"ricardian_contract": ""
},{
"name": "reveal",
"type": "reveal",
"ricardian_contract": ""
},{
"name": "deposit",
"type": "deposit",
"ricardian_contract": ""
},{
"name": "withdraw",
"type": "withdraw",
"ricardian_contract": ""
},{
"name": "reset",
"type": "reset",
"ricardian_contract": ""
}
],
"tables": [{
"name": "bet",
"index_type": "i64",
"key_names": [
"id"
],
"key_types": [
"uint64"
],
"type": "bet"
},{
"name": "gbet",
"index_type": "i64",
"key_names": [
"id"
],
"key_types": [
"uint64"
],
"type": "gbet"
},{
"name": "account",
"index_type": "i64",
"key_names": [
"owner"
],
"key_types": [
"account_name"
],
"type": "account"
}
],
"ricardian_clauses": []
}
原文地址请点击:https://blog.csdn.net/bedrock_stable/article/details/80347354