骰子博彩游戏合约设计
骰子博彩游戏合约设计
一、功能接口
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.****.net/bedrock_stable/article/details/80347354