Guest User

Untitled

a guest
Oct 22nd, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.16 KB | None | 0 0
  1. pragma solidity ^0.4.24;
  2.  
  3. /* This is fiftyflip
  4. a simple yet elegant game contract
  5. that is connected to Proof of Community
  6. contract(0x08f7039d36f99eedc3d8b02cbd19f854f7dddc4d).
  7.  
  8. Greed serves no-one but the one,
  9. But charity is kind, suffereth not and envieth not.
  10. Charity is to give of oneself in the service of his fellow beings.
  11.  
  12. Play on Players. and Remember fifty feeds the multiudes and gives to the PoC community
  13. Forever and ever.
  14.  
  15.  
  16. */
  17.  
  18.  
  19. contract FiftyFlip {
  20. uint constant DONATING_X = 20; // 2% kujira
  21.  
  22. // Need to be discussed
  23. uint constant JACKPOT_FEE = 10; // 1% jackpot
  24. uint constant JACKPOT_MODULO = 1000; // 0.1% jackpotwin
  25. uint constant DEV_FEE = 20; // 2% devfee
  26. uint constant WIN_X = 1900; // 1.9x
  27.  
  28. // There is minimum and maximum bets.
  29. uint constant MIN_BET = 0.01 ether;
  30. uint constant MAX_BET = 7 ether;
  31.  
  32. uint constant BET_EXPIRATION_BLOCKS = 250;
  33.  
  34. // owner and PoC contract address
  35. address public owner;
  36. address public autoPlayBot;
  37. address public secretSigner;
  38. address public whale;
  39.  
  40. // Accumulated jackpot fund.
  41. uint256 public jackpotSize;
  42. uint256 public devFeeSize;
  43.  
  44. // Funds that are locked in potentially winning bets.
  45. uint256 public lockedInBets;
  46. uint256 public totalAmountToWhale;
  47.  
  48.  
  49. struct Bet {
  50. // Wager amount in wei.
  51. uint amount;
  52. // Block number of placeBet tx.
  53. uint256 blockNumber;
  54. // Bit mask representing winning bet outcomes (see MAX_MASK_MODULO comment).
  55. bool betMask;
  56. // Address of a player, used to pay out winning bets.
  57. address player;
  58. }
  59.  
  60. mapping (uint => Bet) bets;
  61. mapping (address => uint) donateAmount;
  62.  
  63. // events
  64. event Wager(uint ticketID, uint betAmount, uint256 betBlockNumber, bool betMask, address betPlayer);
  65. event Win(address winner, uint amount, uint ticketID, bool maskRes, uint jackpotRes);
  66. event Lose(address loser, uint amount, uint ticketID, bool maskRes, uint jackpotRes);
  67. event Refund(uint ticketID, uint256 amount, address requester);
  68. event Donate(uint256 amount, address donator);
  69. event FailedPayment(address paidUser, uint amount);
  70. event Payment(address noPaidUser, uint amount);
  71. event JackpotPayment(address player, uint ticketID, uint jackpotWin);
  72.  
  73. // constructor
  74. constructor (address whaleAddress, address autoPlayBotAddress, address secretSignerAddress) public {
  75. owner = msg.sender;
  76. autoPlayBot = autoPlayBotAddress;
  77. whale = whaleAddress;
  78. secretSigner = secretSignerAddress;
  79. jackpotSize = 0;
  80. devFeeSize = 0;
  81. lockedInBets = 0;
  82. totalAmountToWhale = 0;
  83. }
  84.  
  85. // modifiers
  86. modifier onlyOwner() {
  87. require (msg.sender == owner, "You are not the owner of this contract!");
  88. _;
  89. }
  90.  
  91. modifier onlyBot() {
  92. require (msg.sender == autoPlayBot, "You are not the bot of this contract!");
  93. _;
  94. }
  95.  
  96. modifier checkContractHealth() {
  97. require (address(this).balance >= lockedInBets + jackpotSize + devFeeSize, "This contract doesn't have enough balance, it is stopped till someone donate to this game!");
  98. _;
  99. }
  100.  
  101. // betMast:
  102. // false is front, true is back
  103.  
  104. function() public payable { }
  105.  
  106.  
  107. function setBotAddress(address autoPlayBotAddress)
  108. onlyOwner()
  109. external
  110. {
  111. autoPlayBot = autoPlayBotAddress;
  112. }
  113.  
  114. function setSecretSigner(address _secretSigner)
  115. onlyOwner()
  116. external
  117. {
  118. secretSigner = _secretSigner;
  119. }
  120.  
  121. // wager function
  122. function wager(bool bMask, uint ticketID, uint ticketLastBlock, uint8 v, bytes32 r, bytes32 s)
  123. checkContractHealth()
  124. external
  125. payable {
  126. Bet storage bet = bets[ticketID];
  127. uint amount = msg.value;
  128. address player = msg.sender;
  129. require (bet.player == address(0), "Ticket is not new one!");
  130. require (amount >= MIN_BET, "Your bet is lower than minimum bet amount");
  131. require (amount <= MAX_BET, "Your bet is higher than maximum bet amount");
  132. require (getCollateralBalance() >= 2 * amount, "If we accept this, this contract will be in danger!");
  133.  
  134. require (block.number <= ticketLastBlock, "Ticket has expired.");
  135. bytes32 signatureHash = keccak256(abi.encodePacked('\x19Ethereum Signed Message:\n37', uint40(ticketLastBlock), ticketID));
  136. secretSigner = ecrecover(signatureHash, v, r, s);
  137. require (secretSigner == ecrecover(signatureHash, v, r, s), "web3 vrs signature is not valid.");
  138.  
  139. jackpotSize += amount * JACKPOT_FEE / 1000;
  140. devFeeSize += amount * DEV_FEE / 1000;
  141. lockedInBets += amount * WIN_X / 1000;
  142.  
  143. uint donate_amount = amount * DONATING_X / 1000;
  144. whale.call.value(donate_amount)(bytes4(keccak256("donate()")));
  145. totalAmountToWhale += donate_amount;
  146.  
  147. bet.amount = amount;
  148. bet.blockNumber = block.number;
  149. bet.betMask = bMask;
  150. bet.player = player;
  151.  
  152. emit Wager(ticketID, bet.amount, bet.blockNumber, bet.betMask, bet.player);
  153. }
  154.  
  155. // method to determine winners and losers
  156. function play(uint ticketReveal)
  157. checkContractHealth()
  158. external
  159. {
  160. uint ticketID = uint(keccak256(abi.encodePacked(ticketReveal)));
  161. Bet storage bet = bets[ticketID];
  162. require (bet.player != address(0), "TicketID is not correct!");
  163. require (bet.amount != 0, "Ticket is already used one!");
  164. uint256 blockNumber = bet.blockNumber;
  165. if(blockNumber < block.number && blockNumber >= block.number - BET_EXPIRATION_BLOCKS)
  166. {
  167. uint256 random = uint256(keccak256(abi.encodePacked(blockhash(blockNumber), ticketReveal)));
  168. bool maskRes = (random % 2) !=0;
  169. uint jackpotRes = random % JACKPOT_MODULO;
  170.  
  171. uint tossWinAmount = bet.amount * WIN_X / 1000;
  172.  
  173. uint tossWin = 0;
  174. uint jackpotWin = 0;
  175.  
  176. if(bet.betMask == maskRes) {
  177. tossWin = tossWinAmount;
  178. }
  179. if(jackpotRes == 0) {
  180. jackpotWin = jackpotSize;
  181. jackpotSize = 0;
  182. }
  183. if (jackpotWin > 0) {
  184. emit JackpotPayment(bet.player, ticketID, jackpotWin);
  185. }
  186. if(tossWin + jackpotWin > 0)
  187. {
  188. payout(bet.player, tossWin + jackpotWin, ticketID, maskRes, jackpotRes);
  189. }
  190. else
  191. {
  192. loseWager(bet.player, bet.amount, ticketID, maskRes, jackpotRes);
  193. }
  194. lockedInBets -= tossWinAmount;
  195. bet.amount = 0;
  196. }
  197. else
  198. {
  199. revert();
  200. }
  201. }
  202.  
  203. function donateForContractHealth()
  204. external
  205. payable
  206. {
  207. donateAmount[msg.sender] += msg.value;
  208. emit Donate(msg.value, msg.sender);
  209. }
  210.  
  211. function withdrawDonation(uint amount)
  212. external
  213. {
  214. require(donateAmount[msg.sender] >= amount, "You are going to withdraw more than you donated!");
  215.  
  216. if (sendFunds(msg.sender, amount)){
  217. donateAmount[msg.sender] -= amount;
  218. }
  219. }
  220.  
  221. // method to refund
  222. function refund(uint ticketID)
  223. checkContractHealth()
  224. external {
  225. Bet storage bet = bets[ticketID];
  226.  
  227. require (bet.amount != 0, "this ticket has no balance");
  228. require (block.number > bet.blockNumber + BET_EXPIRATION_BLOCKS, "this ticket is expired.");
  229. sendRefund(ticketID);
  230. }
  231.  
  232. // Funds withdrawl
  233. function withdrawDevFee(address withdrawAddress, uint withdrawAmount)
  234. onlyOwner()
  235. checkContractHealth()
  236. external {
  237. require (devFeeSize >= withdrawAmount, "You are trying to withdraw more amount than developer fee.");
  238. require (withdrawAmount <= address(this).balance, "Contract balance is lower than withdrawAmount");
  239. require (devFeeSize <= address(this).balance, "Not enough funds to withdraw.");
  240. if (sendFunds(withdrawAddress, withdrawAmount)){
  241. devFeeSize -= withdrawAmount;
  242. }
  243. }
  244.  
  245. // Funds withdrawl
  246. function withdrawBotFee(uint withdrawAmount)
  247. onlyBot()
  248. checkContractHealth()
  249. external {
  250. require (devFeeSize >= withdrawAmount, "You are trying to withdraw more amount than developer fee.");
  251. require (withdrawAmount <= address(this).balance, "Contract balance is lower than withdrawAmount");
  252. require (devFeeSize <= address(this).balance, "Not enough funds to withdraw.");
  253. if (sendFunds(autoPlayBot, withdrawAmount)){
  254. devFeeSize -= withdrawAmount;
  255. }
  256. }
  257.  
  258. // Get Bet Info from id
  259. function getBetInfo(uint ticketID)
  260. constant
  261. external
  262. returns (uint, uint256, bool, address){
  263. Bet storage bet = bets[ticketID];
  264. return (bet.amount, bet.blockNumber, bet.betMask, bet.player);
  265. }
  266.  
  267. // Get Bet Info from id
  268. function getContractBalance()
  269. constant
  270. external
  271. returns (uint){
  272. return address(this).balance;
  273. }
  274.  
  275. // Get Collateral for Bet
  276. function getCollateralBalance()
  277. constant
  278. public
  279. returns (uint){
  280. if (address(this).balance > lockedInBets + jackpotSize + devFeeSize)
  281. return address(this).balance - lockedInBets - jackpotSize - devFeeSize;
  282. return 0;
  283. }
  284.  
  285. // Contract may be destroyed only when there are no ongoing bets,
  286. // either settled or refunded. All funds are transferred to contract owner.
  287. function kill() external onlyOwner() {
  288. require (lockedInBets == 0, "All bets should be processed (settled or refunded) before self-destruct.");
  289. selfdestruct(owner);
  290. }
  291.  
  292. // Payout ETH to winner
  293. function payout(address winner, uint ethToTransfer, uint ticketID, bool maskRes, uint jackpotRes)
  294. internal
  295. {
  296. winner.transfer(ethToTransfer);
  297. emit Win(winner, ethToTransfer, ticketID, maskRes, jackpotRes);
  298. }
  299.  
  300. // sendRefund to requester
  301. function sendRefund(uint ticketID)
  302. internal
  303. {
  304. Bet storage bet = bets[ticketID];
  305. address requester = bet.player;
  306. uint256 ethToTransfer = bet.amount;
  307. requester.transfer(ethToTransfer);
  308.  
  309. uint tossWinAmount = bet.amount * WIN_X / 1000;
  310. lockedInBets -= tossWinAmount;
  311.  
  312. bet.amount = 0;
  313. emit Refund(ticketID, ethToTransfer, requester);
  314. }
  315.  
  316. // Helper routine to process the payment.
  317. function sendFunds(address paidUser, uint amount) private returns (bool){
  318. bool success = paidUser.send(amount);
  319. if (success) {
  320. emit Payment(paidUser, amount);
  321. } else {
  322. emit FailedPayment(paidUser, amount);
  323. }
  324. return success;
  325. }
  326. // Payout ETH to whale when player loses
  327. function loseWager(address player, uint amount, uint ticketID, bool maskRes, uint jackpotRes)
  328. internal
  329. {
  330. emit Lose(player, amount, ticketID, maskRes, jackpotRes);
  331. }
  332.  
  333. // bulk clean the storage.
  334. function clearStorage(uint[] toCleanTicketIDs) external {
  335. uint length = toCleanTicketIDs.length;
  336.  
  337. for (uint i = 0; i < length; i++) {
  338. clearProcessedBet(toCleanTicketIDs[i]);
  339. }
  340. }
  341.  
  342. // Helper routine to move 'processed' bets into 'clean' state.
  343. function clearProcessedBet(uint ticketID) private {
  344. Bet storage bet = bets[ticketID];
  345.  
  346. // Do not overwrite active bets with zeros; additionally prevent cleanup of bets
  347. // for which ticketID signatures may have not expired yet (see whitepaper for details).
  348. if (bet.amount != 0 || block.number <= bet.blockNumber + BET_EXPIRATION_BLOCKS) {
  349. return;
  350. }
  351.  
  352. bet.blockNumber = 0;
  353. bet.betMask = false;
  354. bet.player = address(0);
  355. }
  356.  
  357. // A trap door for when someone sends tokens other than the intended ones so the overseers can decide where to send them.
  358. function transferAnyERC20Token(address tokenAddress, address tokenOwner, uint tokens)
  359. public
  360. onlyOwner()
  361. returns (bool success)
  362. {
  363. return ERC20Interface(tokenAddress).transfer(tokenOwner, tokens);
  364. }
  365. }
  366.  
  367. //Define ERC20Interface.transfer, so PoCWHALE can transfer tokens accidently sent to it.
  368. contract ERC20Interface
  369. {
  370. function transfer(address to, uint256 tokens) public returns (bool success);
  371. }
Add Comment
Please, Sign In to add comment