骰子博彩游戏合约设计

骰子博彩游戏合约设计

一、功能接口

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

七、合约代码

 
 
  1. /**

  2. * @file

  3. * @copyright defined in eos/LICENSE.txt

  4. */

  5. #include <utility>

  6. #include <vector>

  7. #include <string>

  8. #include <eosiolib/eosio.hpp>

  9. #include <eosiolib/asset.hpp>

  10. #include <eosiolib/contract.hpp>

  11. #include <eosiolib/crypto.h>

  12.  
  13. using eosio::key256;

  14. using eosio::indexed_by;

  15. using eosio::const_mem_fun;

  16. using eosio::asset;

  17. using eosio::permission_level;

  18. using eosio::action;

  19. using eosio::print;

  20. using eosio::name;

  21.  
  22. class dice : public eosio::contract {

  23. public:

  24. dice(account_name self) : eosio::contract(self),

  25. bets(_self, _self),

  26. gbet(_self, _self),

  27. accounts(_self, _self) {

  28. }

  29.  
  30. //@abi action

  31. void offerbet(const asset& bet, account_name player, const uint64_t betinfo) {

  32.  
  33. eosio_assert( bet.symbol == S(4,EOS) , "only EOS token allowed" );

  34. eosio_assert( bet.is_valid(), "invalid bet" );

  35. eosio_assert( bet.amount > 0, "must bet positive quantity" );

  36.  
  37. //

  38. require_auth( player );

  39.  
  40. auto cur_player_itr = accounts.find( player );

  41. eosio_assert(cur_player_itr != accounts.end(), "unknown account");

  42. eosio_assert(cur_player_itr->balance >= bet, "insufficient balance");

  43.  
  44. auto cur_gbet_itr = gbet.begin();

  45. eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build");

  46. eosio_assert(cur_gbet_itr->open == 1, "bet is not open");

  47. eosio_assert(cur_gbet_itr->reveal == 0, "bet is revealed");

  48.  
  49. uint64_t betid = cur_gbet_itr->betid;

  50. uint64_t exist_bet = false;

  51. auto bybetid_index = bets.template get_index<N(bybetid)>();

  52. auto cur_bets_itr = bybetid_index.find(betid);

  53. while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) {

  54. if(cur_bets_itr->owner == player) {

  55. exist_bet = true;

  56. break;

  57. }

  58. cur_bets_itr ++;

  59. }

  60.  
  61. eosio_assert(exist_bet == false, "bet is done");

  62.  
  63. // Store new offer

  64. auto new_bet_itr = bets.emplace(_self, [&](auto& rbet){

  65. rbet.id = bets.available_primary_key();

  66. rbet.balance = bet;

  67. rbet.owner = player;

  68. rbet.betid = betid;

  69. rbet.info = betinfo;

  70. });

  71.  
  72. // Update player's accounts

  73. accounts.modify( cur_player_itr, 0, [&](auto& acnt) {

  74. eosio_assert( acnt.balance >= bet, "insufficient balance" );

  75. acnt.balance -= bet;

  76. });

  77. }

  78.  
  79. //@abi action

  80. void canceloffer(account_name player) {

  81. //

  82. require_auth( player );

  83.  
  84. auto cur_gbet_itr = gbet.begin();

  85. eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build");

  86. eosio_assert(cur_gbet_itr->open == 1, "bet is closed");

  87. eosio_assert(cur_gbet_itr->reveal == 0, "bet is revealed");

  88.  
  89. uint64_t betid = cur_gbet_itr->betid;

  90. uint64_t exist_bet = false;

  91. auto bybetid_index = bets.template get_index<N(bybetid)>();

  92. auto cur_bets_itr = bybetid_index.find(betid);

  93. while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) {

  94. if(cur_bets_itr->owner == player) {

  95. exist_bet = true;

  96. break;

  97. }

  98. cur_bets_itr ++;

  99. }

  100. eosio_assert(exist_bet == true, "no bet");

  101.  
  102. // Update player's accounts

  103. auto cur_player_itr = accounts.find( player );

  104. if( cur_player_itr == accounts.end() ) {

  105. cur_player_itr = accounts.emplace(_self, [&](auto& acnt){

  106. acnt.owner = player;

  107. });

  108. }

  109.  
  110. accounts.modify( cur_player_itr, 0, [&](auto& acnt) {

  111. acnt.balance += cur_bets_itr->balance;

  112. });

  113.  
  114. bybetid_index.erase(cur_bets_itr);

  115. //bets.erase(cur_bet_itr);

  116. }

  117.  
  118. //@abi action

  119. void openbet() {

  120. //

  121. require_auth(_self);

  122.  
  123. // Create global bet counter if not exists

  124. auto cur_gbet_itr = gbet.begin();

  125. if( cur_gbet_itr == gbet.end() ) {

  126. cur_gbet_itr = gbet.emplace(_self, [&](auto& g_bet){

  127. g_bet.id = gbet.available_primary_key();

  128. g_bet.betid = 0;

  129. g_bet.open = 0;

  130. g_bet.reveal = 1;

  131. });

  132. }

  133.  
  134. eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build");

  135. eosio_assert(cur_gbet_itr->open == 0, "bet is opened");

  136. eosio_assert(cur_gbet_itr->reveal == 1, "bet is not reveal");

  137.  
  138. // Increment global bet counter

  139. gbet.modify(cur_gbet_itr, 0, [&](auto& g_bet){

  140. g_bet.betid++;

  141. g_bet.open = 1;

  142. g_bet.reveal = 0;

  143. });

  144. }

  145.  
  146. //@abi action

  147. void closurebet() {

  148. //

  149. require_auth(_self);

  150.  
  151. auto cur_gbet_itr = gbet.begin();

  152. eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build");

  153. eosio_assert(cur_gbet_itr->open == 1, "bet is closure");

  154. eosio_assert(cur_gbet_itr->reveal == 0, "reveal is done");

  155.  
  156. // udpate global bet status

  157. gbet.modify(cur_gbet_itr, 0, [&](auto& g_bet){

  158. g_bet.open = 0;

  159. });

  160. }

  161.  
  162. //@abi action

  163. void reveal() {

  164. //

  165. require_auth(_self);

  166.  
  167.  
  168. auto cur_gbet_itr = gbet.begin();

  169. eosio_assert(cur_gbet_itr != gbet.end(), "bet is not build");

  170. eosio_assert(cur_gbet_itr->open == 0, "bet is open");

  171. eosio_assert(cur_gbet_itr->reveal == 0, "reveal is done");

  172.  
  173. //

  174. uint64_t bet_result = 0;

  175. uint64_t betid = cur_gbet_itr->betid;

  176.  
  177. //

  178. {

  179. uint32_t t_now = now();

  180. checksum256 hash;

  181. sha256((char*)(&t_now), sizeof(uint32_t), &hash);

  182. bet_result = (hash.hash[15]) % 2;

  183. }

  184.  
  185. //

  186. asset total_balance;

  187. asset win_balance;

  188. auto bybetid_index = bets.template get_index<N(bybetid)>();

  189. auto cur_bets_itr = bybetid_index.find(betid);

  190. while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) {

  191. total_balance += cur_bets_itr->balance;

  192. if(cur_bets_itr->info == bet_result)

  193. win_balance += cur_bets_itr->balance;

  194. cur_bets_itr++;

  195. }

  196.  
  197. if(win_balance.amount == 0) {

  198. bybetid_index = bets.template get_index<N(bybetid)>();

  199. cur_bets_itr = bybetid_index.find(betid);

  200.  
  201. while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) {

  202.  
  203. auto use_balance = cur_bets_itr->balance;

  204. auto cur_player_itr = accounts.find( cur_bets_itr->owner );

  205. if( cur_player_itr == accounts.end() ) {

  206. cur_player_itr = accounts.emplace(_self, [&](auto& acnt){

  207. acnt.owner = cur_bets_itr->owner;

  208. });

  209. }

  210. accounts.modify( cur_player_itr, 0, [&]( auto& acnt ) {

  211. acnt.balance += use_balance;

  212. });

  213.  
  214. cur_bets_itr ++;

  215. }

  216. } else {

  217. bybetid_index = bets.template get_index<N(bybetid)>();

  218. cur_bets_itr = bybetid_index.find(betid);

  219. while(cur_bets_itr != bybetid_index.end() && cur_bets_itr->betid == betid) {

  220. if(cur_bets_itr->info == bet_result) {

  221. //auto use_balance = (cur_bets_itr->balance / win_balance) * total_balance;

  222. auto use_balance = (cur_bets_itr->balance * total_balance.amount) / win_balance.amount;

  223.  
  224. auto cur_player_itr = accounts.find( cur_bets_itr->owner );

  225. if( cur_player_itr == accounts.end() ) {

  226. cur_player_itr = accounts.emplace(_self, [&](auto& acnt){

  227. acnt.owner = cur_bets_itr->owner;

  228. });

  229. }

  230. accounts.modify( cur_player_itr, 0, [&]( auto& acnt ) {

  231. acnt.balance += use_balance;

  232. });

  233. }

  234. cur_bets_itr ++;

  235. }

  236. }

  237.  
  238. // udpate global bet status

  239. gbet.modify(cur_gbet_itr, 0, [&](auto& g_bet){

  240. g_bet.reveal = 1;

  241. });

  242. }

  243.  
  244. //@abi action

  245. void deposit( const account_name from, const asset& quantity ) {

  246.  
  247. require_auth( from );

  248.  
  249. eosio_assert( quantity.is_valid(), "invalid quantity" );

  250. eosio_assert( quantity.amount > 0, "must deposit positive quantity" );

  251.  
  252. auto itr = accounts.find(from);

  253. if( itr == accounts.end() ) {

  254. itr = accounts.emplace(_self, [&](auto& acnt){

  255. acnt.owner = from;

  256. });

  257. }

  258.  
  259. action(

  260. permission_level{ from, N(active) },

  261. N(eosio.token), N(transfer),

  262. std::make_tuple(from, _self, quantity, std::string(""))

  263. ).send();

  264.  
  265. accounts.modify( itr, 0, [&]( auto& acnt ) {

  266. acnt.balance += quantity;

  267. });

  268. }

  269.  
  270. //@abi action

  271. void withdraw( const account_name to, const asset& quantity ) {

  272. require_auth( to );

  273.  
  274. eosio_assert( quantity.is_valid(), "invalid quantity" );

  275. eosio_assert( quantity.amount > 0, "must withdraw positive quantity" );

  276.  
  277. auto itr = accounts.find( to );

  278. eosio_assert(itr != accounts.end(), "unknown account");

  279.  
  280. accounts.modify( itr, 0, [&]( auto& acnt ) {

  281. eosio_assert( acnt.balance >= quantity, "insufficient balance" );

  282. acnt.balance -= quantity;

  283. });

  284.  
  285. action(

  286. permission_level{ _self, N(active) },

  287. N(eosio.token), N(transfer),

  288. std::make_tuple(_self, to, quantity, std::string(""))

  289. ).send();

  290.  
  291. if( itr->is_empty() ) {

  292. accounts.erase(itr);

  293. }

  294. }

  295.  
  296. //@abi action

  297. void reset() {

  298. //

  299. require_auth( _self );

  300.  
  301. auto cur_gbet_itr = gbet.begin();

  302. while(cur_gbet_itr != gbet.end()) {

  303. cur_gbet_itr = gbet.erase(cur_gbet_itr);

  304. }

  305.  
  306. auto cur_bet_itr = bets.begin();

  307. while(cur_bet_itr != bets.end()) {

  308. cur_bet_itr = bets.erase(cur_bet_itr);

  309. }

  310. }

  311.  
  312. private:

  313. //@abi table bet i64

  314. struct bet {

  315. uint64_t id;

  316. account_name owner;

  317. asset balance;

  318. uint64_t betid;

  319. uint64_t info;

  320.  
  321. uint64_t primary_key()const { return id; }

  322. uint64_t by_betid()const { return betid; }

  323. account_name by_owner() const { return owner; }

  324.  
  325. EOSLIB_SERIALIZE( bet, (id)(owner)(balance)(betid)(info) )

  326. };

  327.  
  328. typedef eosio::multi_index< N(bet), bet,

  329. indexed_by< N(bybetid), const_mem_fun<bet, uint64_t, &bet::by_betid > >,

  330. indexed_by< N(byowner), const_mem_fun<bet, account_name, &bet::by_owner > > > bet_index;

  331.  
  332. //@abi table gbet i64

  333. struct gbet {

  334. uint64_t id;

  335. uint64_t betid;

  336. uint64_t betname;

  337. uint64_t open = 0;

  338. uint64_t reveal = 0;

  339.  
  340. uint64_t primary_key()const { return id; }

  341.  
  342. EOSLIB_SERIALIZE( gbet, (id)(betid)(betname)(open)(reveal) )

  343. };

  344.  
  345. typedef eosio::multi_index< N(gbet), gbet> gbet_index;

  346.  
  347. //@abi table account i64

  348. struct account {

  349. account( account_name o = account_name() ):owner(o){

  350. }

  351.  
  352. account_name owner;

  353. asset balance;

  354.  
  355. bool is_empty()const { return !( balance.amount); }

  356. uint64_t primary_key()const { return owner; }

  357.  
  358. EOSLIB_SERIALIZE( account, (owner)(balance) )

  359. };

  360.  
  361. typedef eosio::multi_index< N(account), account> account_index;

  362.  
  363. bet_index bets;

  364. gbet_index gbet;

  365. account_index accounts;

  366. };

  367.  
  368. 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