├── README.md ├── frontend ├── .env ├── .gitignore ├── .vscode │ └── settings.json ├── GNUmakefile ├── README.md ├── build │ ├── asset-manifest.json │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ ├── precache-manifest.7f0a1849234fb16afd74cd290c1ec9fc.js │ ├── service-worker.js │ └── static │ │ ├── css │ │ ├── main.54b516df.chunk.css │ │ └── main.54b516df.chunk.css.map │ │ ├── js │ │ ├── 2.8a0cc92f.chunk.js │ │ ├── 2.8a0cc92f.chunk.js.map │ │ ├── main.22e40df3.chunk.js │ │ ├── main.22e40df3.chunk.js.map │ │ ├── runtime-main.9c63dd59.js │ │ └── runtime-main.9c63dd59.js.map │ │ └── media │ │ ├── bg.03b4fd11.jpg │ │ ├── ic_arrow-down-circle.3d1db861.svg │ │ ├── ig_coin_card.968dcb99.png │ │ ├── ig_lose_coin.91f34167.png │ │ ├── ig_win_coin.44207f94.png │ │ └── tt-usdt.6ef85566.png ├── environment.yml ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── ContractEnum.ts │ ├── assets │ │ ├── bg.jpg │ │ ├── ic_arrow-down-circle.svg │ │ ├── icon_TT.png │ │ ├── ig_bet_btn.png │ │ ├── ig_coin_card.png │ │ ├── ig_double_btn.png │ │ ├── ig_lose_coin.png │ │ ├── ig_reset_btn.png │ │ ├── ig_win_coin.png │ │ └── tt-usdt.png │ ├── components │ │ ├── App │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── DoubleOrNothing.json │ │ │ └── ERC677.json │ │ ├── Coin │ │ │ ├── Coin.css │ │ │ └── Coin.tsx │ │ ├── CoinPicker │ │ │ ├── CoinPicker.css │ │ │ └── CoinPicker.tsx │ │ ├── ContractLoader │ │ │ └── ContractLoader.tsx │ │ ├── Display │ │ │ ├── Display.css │ │ │ └── Display.tsx │ │ ├── Game │ │ │ ├── Game.css │ │ │ └── Game.tsx │ │ ├── Header │ │ │ ├── Header.css │ │ │ └── Header.tsx │ │ ├── ReferralRules │ │ │ ├── ReferralRules.css │ │ │ └── ReferralRules.tsx │ │ └── Web3Loader │ │ │ └── Web3Loader.tsx │ ├── config.ts │ ├── containers │ │ ├── DoubleGameContainer │ │ │ └── DoubleGameContainer.tsx │ │ ├── Erc677GameContainer │ │ │ └── Erc677GameContainer.tsx │ │ └── GameContainer │ │ │ └── GameContainer.tsx │ ├── contexts │ │ ├── ContractContext │ │ │ └── ContractContext.tsx │ │ └── Web3Context │ │ │ └── Web3Context.tsx │ ├── index.css │ ├── index.tsx │ ├── react-app-env.d.ts │ └── serviceWorker.ts ├── tsconfig.json ├── typings │ ├── abi.d.ts │ ├── env.d.ts │ ├── images.d.ts │ ├── sounds.d.ts │ └── web3.d.ts └── yarn.lock ├── index.html └── smart-contracts ├── .gitignore ├── GNUmakefile ├── build └── contracts │ ├── DoubleOrNothing.json │ ├── ERC20.json │ ├── ERC677.json │ ├── ERC677Receiver.json │ ├── IBurnableMintableERC677Token.json │ ├── IERC20.json │ ├── Migrations.json │ ├── Ownable.json │ ├── Referral.json │ ├── SafeMath.json │ └── ThunderRandomLibraryInterface.json ├── contracts ├── DoubleOrNothing.sol ├── ERC677Interface.sol ├── Migrations.sol └── ThunderRandomLibraryInterface.sol ├── environment.yml ├── migrations └── 1_initial_migration.js ├── package.json ├── truffle-config.js └── yarn.lock /README.md: -------------------------------------------------------------------------------- 1 | THIS IS NOT PRODUCTION READY AND SHOULD NOT BE USED IN ANY WAY IN PRODUCTION. 2 | 3 | [DoubleOrNothing](https://thundercore.github.io/DoubleOrNothing/) is a coin flip game built on Thunder. 4 | 5 | # Getting Started 6 | 7 | 1. Fork this repo 8 | 2. Rename the forked repo as {{Your-github-username}}.github.io 9 | 3. ssh `git clone git@github.com:{{Your-github-username}}/{{Your-github-username}}.github.io.git` 10 | \ 11 | or 12 | \ 13 | https `git clone https://github.com/{{Your-github-username}}/{{Your-github-username}}.github.io.git` 14 | 4. `cd {{Your-github-username}}.github.io.git` 15 | 5. `git commit --allow-empty -m "bump"` 16 | 6. `git push` 17 | *Note: If you see the error “push declined due to email privacy restrictions”, you will need to allow command line pushes that expose your email address. This under “Settings”, “Emails” 18 | 7. It will take ~10 mins for Github to create your page. It can be accessed at 19 | \ 20 | `https://{{Your-github-username}}.github.io` 21 | 8. While you wait, make sure to have [Metamask](https://metamask.io/) installed 22 | 9. Set it up to a new Custom RPC url: https://mainnet-rpc.thundercore.com 23 | 10. When your page is built, you should be able to play the game 24 | 25 | 26 | # Understanding the Repo for development 27 | 28 | ### Setup 29 | We will be using node v8 or node v10 30 | - `cd smart-contracts` 31 | - `yarn install` or ` npm install` 32 | - `cd ../frontend` 33 | - `yarn install` or `npm install` 34 | - `yarn start` or `npm run start` 35 | 36 | ### Smart Contracts 37 | 38 | This project uses [Truffle](https://www.trufflesuite.com) to handle all of the smart contract related work. 39 | 40 | In the `/smart-contracts/contracts` folder, you will find `DoubleOrNothing.sol` which contains the game logic. 41 | 42 | After you make any updates to it, you will have to redeploy the contract. 43 | 44 | `yarn migrate --network development/thunder --reset` or `npm run migrate -- --network development/thunder --reset` 45 | 46 | ** Development points to localhost:8545 [Ganache](https://www.trufflesuite.com/ganache) 47 | 48 | ** To deploy on thunder, you must add a mnemonic to `/smart-contracts/truffle-config.js` 49 | 50 | ### Frontend 51 | The frontend is built using the [create-react-app](https://github.com/facebook/create-react-app) project with [Typescript](https://www.typescriptlang.org/). 52 | To interact with the chain, we use [Ethers.js](https://docs.ethers.io/ethers.js/html/). 53 | -------------------------------------------------------------------------------- /frontend/.env: -------------------------------------------------------------------------------- 1 | #REACT_APP_DOUBLE_CONTRACT_ADDRESS=0x48caD7fe30Fd1CA52EcBda9C82E398B0FFd321eE 2 | #REACT_APP_TT_DAI_CONTRACT=0xd60db41a718a73da844a4c454c8bd6e07173d722 3 | #REACT_APP_TT_USDT_CONTRACT=0x42532085e51e5618575005f626589ff57d280d68 4 | #REACT_APP_RPC_URL=https://testnet-rpc.thundercore.com 5 | 6 | REACT_APP_DOUBLE_CONTRACT_ADDRESS=0x8693a164ebc4429fCFF4461B481FCD4E60690fD3 7 | #REACT_APP_TT_DAI_CONTRACT=0x2b31e3b88847f03c1335E99A0d1274A2c72059DE 8 | REACT_APP_TT_USDT_CONTRACT=0x4f3C8E20942461e2c3Bdd8311AC57B0c222f2b82 9 | REACT_APP_RPC_URL=https://mainnet-rpc.thundercore.com 10 | #REACT_APP_RPC_URL=http://localhost:8545 11 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | conda-env 23 | 24 | # VIM 25 | *.swp 26 | *.swo 27 | -------------------------------------------------------------------------------- /frontend/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Numberify", 4 | "Usdt" 5 | ] 6 | } -------------------------------------------------------------------------------- /frontend/GNUmakefile: -------------------------------------------------------------------------------- 1 | CONDA := $(HOME)/miniconda3/bin/conda 2 | 3 | TOP_DIR := $(patsubst %/,%,$(dir $(realpath $(lastword $(MAKEFILE_LIST))))) 4 | CONDA_ENV_DIR := $(TOP_DIR)/conda-env 5 | 6 | # This can be used to customized local builds. 7 | -include $(TOP_DIR)/Local.mk 8 | 9 | PATH := $(CONDA_ENV_DIR)/bin:$(TOP_DIR)/node_modules/.bin:$(PATH) 10 | export PATH 11 | 12 | PREFERRED_INTERACTIVE_SHELL ?= bash 13 | PS1_NAME ?= 'double-or-nothing' 14 | MAKE_SHELL_PS1 ?= '$(PS1_NAME) $$ ' 15 | .PHONY: shell 16 | ifeq ($(PREFERRED_INTERACTIVE_SHELL),bash) 17 | shell: 18 | @INIT_FILE=$(shell mktemp); \ 19 | printf '[ -e $$HOME/.bashrc ] && source $$HOME/.bashrc\n' > $$INIT_FILE; \ 20 | printf '[ -e Local.env ] && source Local.env\n' >> $$INIT_FILE; \ 21 | printf 'PS1='"$(MAKE_SHELL_PS1) "'\n' >> $$INIT_FILE; \ 22 | $(PREFERRED_INTERACTIVE_SHELL) --init-file $$INIT_FILE || true 23 | else ifeq ($(PREFERRED_INTERACTIVE_SHELL),fish) 24 | shell: 25 | @INIT_FILE=$(shell mktemp); \ 26 | printf 'if functions -q fish_right_prompt\n' > $$INIT_FILE; \ 27 | printf ' functions -c fish_right_prompt __fish_right_prompt_original\n' >> $$INIT_FILE; \ 28 | printf ' functions -e fish_right_prompt\n' >> $$INIT_FILE; \ 29 | printf 'else\n' >> $$INIT_FILE; \ 30 | printf ' function __fish_right_prompt_original\n' >> $$INIT_FILE; \ 31 | printf ' end\n' >> $$INIT_FILE; \ 32 | printf 'end\n' >> $$INIT_FILE; \ 33 | printf 'function fish_right_prompt\n' >> $$INIT_FILE; \ 34 | printf ' echo -n "($(PS1_NAME)) "\n' >> $$INIT_FILE; \ 35 | printf ' __fish_right_prompt_original\n' >> $$INIT_FILE; \ 36 | printf 'end\n' >> $$INIT_FILE; \ 37 | $(PREFERRED_INTERACTIVE_SHELL) --init-command="source $$INIT_FILE" || true 38 | else 39 | shell: 40 | @$(PREFERRED_INTERACTIVE_SHELL) || true 41 | endif 42 | 43 | .PHONY: conda-env 44 | conda-env: 45 | if [ ! -d $(CONDA_ENV_DIR) ]; then \ 46 | $(CONDA) env create -f environment.yml -p $(CONDA_ENV_DIR); \ 47 | else \ 48 | $(CONDA) env update -f environment.yml -p $(CONDA_ENV_DIR); \ 49 | fi 50 | yarn install 51 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | -------------------------------------------------------------------------------- /frontend/build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "main.css": "/frontend/build/static/css/main.54b516df.chunk.css", 4 | "main.js": "/frontend/build/static/js/main.22e40df3.chunk.js", 5 | "main.js.map": "/frontend/build/static/js/main.22e40df3.chunk.js.map", 6 | "runtime-main.js": "/frontend/build/static/js/runtime-main.9c63dd59.js", 7 | "runtime-main.js.map": "/frontend/build/static/js/runtime-main.9c63dd59.js.map", 8 | "static/js/2.8a0cc92f.chunk.js": "/frontend/build/static/js/2.8a0cc92f.chunk.js", 9 | "static/js/2.8a0cc92f.chunk.js.map": "/frontend/build/static/js/2.8a0cc92f.chunk.js.map", 10 | "index.html": "/frontend/build/index.html", 11 | "precache-manifest.7f0a1849234fb16afd74cd290c1ec9fc.js": "/frontend/build/precache-manifest.7f0a1849234fb16afd74cd290c1ec9fc.js", 12 | "service-worker.js": "/frontend/build/service-worker.js", 13 | "static/css/main.54b516df.chunk.css.map": "/frontend/build/static/css/main.54b516df.chunk.css.map", 14 | "static/media/App.css": "/frontend/build/static/media/bg.03b4fd11.jpg", 15 | "static/media/ic_arrow-down-circle.3d1db861.svg": "/frontend/build/static/media/ic_arrow-down-circle.3d1db861.svg", 16 | "static/media/ig_coin_card.png": "/frontend/build/static/media/ig_coin_card.968dcb99.png", 17 | "static/media/Coin.css": "/frontend/build/static/media/ig_win_coin.44207f94.png", 18 | "static/media/tt-usdt.png": "/frontend/build/static/media/tt-usdt.6ef85566.png" 19 | } 20 | } -------------------------------------------------------------------------------- /frontend/build/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/build/favicon.ico -------------------------------------------------------------------------------- /frontend/build/index.html: -------------------------------------------------------------------------------- 1 | DoubleOrNothing
-------------------------------------------------------------------------------- /frontend/build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "DON", 3 | "name": "Double Or Nothing", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /frontend/build/precache-manifest.7f0a1849234fb16afd74cd290c1ec9fc.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = (self.__precacheManifest || []).concat([ 2 | { 3 | "revision": "0cf4e84343a789d7b726ed63e73c5b45", 4 | "url": "/frontend/build/index.html" 5 | }, 6 | { 7 | "revision": "637e1350797521a4f18d", 8 | "url": "/frontend/build/static/css/main.54b516df.chunk.css" 9 | }, 10 | { 11 | "revision": "61f1d6268fca7f171314", 12 | "url": "/frontend/build/static/js/2.8a0cc92f.chunk.js" 13 | }, 14 | { 15 | "revision": "637e1350797521a4f18d", 16 | "url": "/frontend/build/static/js/main.22e40df3.chunk.js" 17 | }, 18 | { 19 | "revision": "161c561bd634b38eb726", 20 | "url": "/frontend/build/static/js/runtime-main.9c63dd59.js" 21 | }, 22 | { 23 | "revision": "03b4fd11fa86248c71b3aba06a289206", 24 | "url": "/frontend/build/static/media/bg.03b4fd11.jpg" 25 | }, 26 | { 27 | "revision": "3d1db8614cf33111c1d108d4d6e02a95", 28 | "url": "/frontend/build/static/media/ic_arrow-down-circle.3d1db861.svg" 29 | }, 30 | { 31 | "revision": "968dcb9920a507c65df339dca7c73edd", 32 | "url": "/frontend/build/static/media/ig_coin_card.968dcb99.png" 33 | }, 34 | { 35 | "revision": "91f341670a83880989a6a467a519f2a7", 36 | "url": "/frontend/build/static/media/ig_lose_coin.91f34167.png" 37 | }, 38 | { 39 | "revision": "44207f94d90658bedf76545bed55f30d", 40 | "url": "/frontend/build/static/media/ig_win_coin.44207f94.png" 41 | }, 42 | { 43 | "revision": "6ef855666d8f483e3f6fa8cdffb27051", 44 | "url": "/frontend/build/static/media/tt-usdt.6ef85566.png" 45 | } 46 | ]); -------------------------------------------------------------------------------- /frontend/build/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); 15 | 16 | importScripts( 17 | "/frontend/build/precache-manifest.7f0a1849234fb16afd74cd290c1ec9fc.js" 18 | ); 19 | 20 | self.addEventListener('message', (event) => { 21 | if (event.data && event.data.type === 'SKIP_WAITING') { 22 | self.skipWaiting(); 23 | } 24 | }); 25 | 26 | workbox.core.clientsClaim(); 27 | 28 | /** 29 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 30 | * requests for URLs in the manifest. 31 | * See https://goo.gl/S9QRab 32 | */ 33 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 34 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 35 | 36 | workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("/frontend/build/index.html"), { 37 | 38 | blacklist: [/^\/_/,/\/[^/?]+\.[^/]+$/], 39 | }); 40 | -------------------------------------------------------------------------------- /frontend/build/static/css/main.54b516df.chunk.css: -------------------------------------------------------------------------------- 1 | body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}#root,.app,body,html{height:100%;font-family:Russo One,sans-serif}.app{background-image:url(/frontend/build/static/media/bg.03b4fd11.jpg);background-repeat:no-repeat;background-size:cover;background-position:50%;min-height:510px}.app-message{padding-top:5vh;text-align:center;color:#fff}.game-container{display:flex;max-width:420px;width:95%;align-items:center;flex-direction:column;margin:1em auto auto}.display-container{margin-bottom:1.5em;width:100%}.coin-display-container{position:relative;width:90%}.coin-display-container img{width:100%}.flip{-webkit-animation:flip .5s linear 3;animation:flip .5s linear 3}.container{text-align:center;margin-bottom:1em}.center{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.coin{-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform:rotateX(15deg);transform:rotateX(15deg);-webkit-transition:all .5s linear;transition:all .5s linear}.button{outline:none;border:none;height:60px;width:150px;background-color:transparent;background-size:contain;background-repeat:no-repeat;-webkit-transition:all .25s ease;transition:all .25s ease}.button[disabled]{-webkit-filter:grayscale(1);filter:grayscale(1)}.bet-button{background-image:url(data:image/png;base64,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)}.reset-button{background-image:url(data:image/png;base64,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)}.double-button{background-image:url(data:image/png;base64,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)}@-webkit-keyframes flip{0%{-webkit-transform:rotateX(10deg);transform:rotateX(10deg)}to{-webkit-transform:rotateX(370deg);transform:rotateX(370deg)}}@keyframes flip{0%{-webkit-transform:rotateX(10deg);transform:rotateX(10deg)}to{-webkit-transform:rotateX(370deg);transform:rotateX(370deg)}}#debug-messages{background-image:none;background-color:#fff;font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.coin-container{-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transition:all .5s;transition:all .5s;position:relative;width:140px;height:140px;border-radius:50%}.flipped{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.face{-webkit-backface-visibility:hidden;backface-visibility:hidden}.top-face{-webkit-transform:translateZ(8px);transform:translateZ(8px)}.disk-body,.top-back-face{background:#444}.disk-body{width:140px;height:16px;position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translate3d(0,63px,0) rotateX(90deg);transform:translate3d(0,63px,0) rotateX(90deg)}.disk-body.back{background:#938506;-webkit-transform:translate3d(0,63px,0) rotateX(90deg) rotateY(180deg);transform:translate3d(0,63px,0) rotateX(90deg) rotateY(180deg)}.disk{overflow:hidden;border-radius:50%;position:absolute;height:100%;width:100%;background:#444}.bottom-front-face{background-size:contain;background-image:url(/frontend/build/static/media/ig_lose_coin.91f34167.png);-webkit-transform:translateZ(-8px) rotateX(180deg);transform:translateZ(-8px) rotateX(180deg);box-shadow:0 0 8px rgba(0,0,0,.45)}.bottom-back-face{-webkit-transform:translateZ(-8px);transform:translateZ(-8px);background:#444}.half-face-lower{top:50%;background:#938506}.half-face-upper{background:#444}.half-face{position:absolute;height:50%;width:100%}.top-face-front{background-size:contain;background-image:url(/frontend/build/static/media/ig_win_coin.44207f94.png)}.display{flex-wrap:wrap;justify-content:space-between;width:100%}.display,.title-container{display:flex;flex-direction:row}.title-container{font-size:1.25em;color:#fff;margin:8px}.value{margin-left:6px}@media (max-width:400px){.title-container{font-size:1em}}.coin-picker-container{display:flex;width:100%}.coin-button-container{flex:1 1;padding:6px 12px}.coin-picker-button-icon{width:20px;height:20px;margin-right:6px}.coin-picker-button{width:100%;height:100%;outline:none;-webkit-filter:grayscale(100%);filter:grayscale(100%);display:flex;align-items:center;justify-content:center;min-height:42px;font-family:inherit;cursor:pointer;border-radius:8px;color:#fff;font-size:16px;font-weight:700;border:3px solid #c5c5c5;background-color:#dedede;-webkit-transition:all .25s ease;transition:all .25s ease}.coin-picker-button.active{cursor:default;-webkit-filter:grayscale(0);filter:grayscale(0);border-color:#fe9f25;background-color:#ffc529}.header{z-index:2000;padding:1em 1.5em;background:#48197c;color:#fff;justify-content:space-between}.header,.header-reward{display:flex;align-items:center}.header-reward{justify-content:center}.reward-container{border-radius:5px;margin:0 8px;background:#2a0e4a;padding:2px 8px}.arrow-circle{-webkit-transition:all .25s;transition:all .25s}.arrow-circle.open{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.ReferralRule-container{top:55px;bottom:0;width:100%;overflow:auto;position:absolute;z-index:200;background:rgba(29,6,34,.9)}.inner-container{max-width:420px;margin:auto;color:#fff;padding:24px}.share-container{line-height:1.5;font-size:1.15em;text-align:center;border-radius:5px;background:rgba(72,26,86,.75);padding:24px;margin-bottom:1.5em}.referral-title{text-align:center;color:#faf528;margin-bottom:1em}.referral-link-container{display:flex;align-items:stretch;justify-content:center;margin-bottom:1.5em}.referral-link{font-size:.85em;font-family:sans-serif;word-break:break-all;padding:12px;background:rgba(56,34,63,.75);border-radius:5px;flex:1 1}.copy-button{cursor:pointer;margin-bottom:6px;border:none;outline:none;font-size:1.5em;font-family:inherit;padding:20px;margin-left:8px;border-radius:5px;color:#000;background:#ffc529;box-shadow:0 6px 2px #ba751a;-webkit-transition:all .25s;transition:all .25s}.copy-button.clicked{margin-top:6px;margin-bottom:0;box-shadow:0 0 0 #ba751a}.referral-stats-container{margin-bottom:2em}.referral-stat{display:flex;justify-content:space-between;margin-bottom:.75em;font-size:.85em}.referral-rule-block,.table{margin-bottom:1em}.table{display:flex;border-radius:5px;overflow:hidden}.table-column{flex:1 1}.table-column.dark{background-color:#461351}.table-column.light{background-color:#863499}.table-column.med{background-color:#5d226b}.cell{display:flex;padding:6px;align-items:center;justify-content:center;height:50px;text-align:center;border:1px solid hsla(0,0%,100%,.05)} 2 | /*# sourceMappingURL=main.54b516df.chunk.css.map */ -------------------------------------------------------------------------------- /frontend/build/static/css/main.54b516df.chunk.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["index.css","App.css","Game.css","Coin.css","Display.css","CoinPicker.css","Header.css","ReferralRules.css"],"names":[],"mappings":"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","file":"main.54b516df.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n","html, body, .app, #root {\n height: 100%;\n font-family: 'Russo One', sans-serif;\n}\n\n.app {\n background-image: url(\"../../assets/bg.jpg\");\n background-repeat: no-repeat;\n background-size: cover;\n background-position: center;\n min-height: 510px;\n}\n\n.app-message {\n padding-top: 5vh;\n text-align: center;\n color: white;\n}\n",".game-container {\n display: flex;\n max-width: 420px;\n width: 95%;\n margin: auto;\n align-items: center;\n flex-direction: column;\n margin-top: 1em;\n}\n\n.display-container {\n margin-bottom: 1.5em;\n width: 100%;\n}\n\n.coin-display-container {\n position: relative;\n width: 90%;\n}\n\n.coin-display-container img {\n width: 100%;\n}\n\n.flip {\n animation: flip 0.5s linear 3;\n}\n\n.container {\n text-align: center;\n margin-bottom: 1em;\n}\n\n.center {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%,-50%)\n}\n\n.coin {\n transform-style: preserve-3d;\n transform: rotateX(15deg);\n transition: all 0.5s linear;\n}\n\n.button {\n outline: none;\n border: none;\n height: 60px;\n width: 150px;\n background-color: transparent;\n background-size: contain;\n background-repeat: no-repeat;\n transition: all 0.25s ease;\n}\n\n.button[disabled] {\n filter: grayscale(1);\n}\n\n.bet-button {\n background-image: url(\"../../assets/ig_bet_btn.png\");\n}\n\n\n.reset-button {\n background-image: url(\"../../assets/ig_reset_btn.png\");\n}\n\n.double-button {\n background-image: url(\"../../assets/ig_double_btn.png\");\n}\n\n\n@keyframes flip {\n 0% {\n transform: rotateX(10deg);\n }\n 100% {\n transform: rotateX(370deg);\n }\n}\n\n#debug-messages {\n background-image: none;\n background-color: white;\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;\n}\n",".coin-container {\n transform-style: preserve-3d;\n transition: 0.5s all;\n position: relative;\n width: 140px;\n height: 140px;\n border-radius: 50%;\n}\n\n.flipped {\n transform: rotateX(180deg);\n}\n\n.face {\n backface-visibility: hidden;\n}\n\n.top-face {\n transform: translateZ(8px);\n}\n\n.top-back-face {\n background: #444;\n}\n\n.disk-body {\n width: 140px;\n height: 16px;\n position: absolute;\n background: #444;\n backface-visibility: hidden;\n transform: translate3d(0,63px,0) rotateX(90deg);\n}\n\n.disk-body.back {\n background: #938506;\n transform: translate3d(0,63px,0) rotateX(90deg) rotateY(180deg);\n}\n\n.disk {\n overflow: hidden;\n border-radius: 50%;\n position: absolute;\n height: 100%;\n width: 100%;\n background: #444;\n}\n\n.bottom-front-face {\n background-size: contain;\n background-image: url(\"../../assets/ig_lose_coin.png\");\n transform: translateZ(-8px) rotateX(180deg);\n box-shadow: 0 0 8px rgba(0, 0, 0, 0.45);\n}\n\n.bottom-back-face {\n transform: translateZ(-8px);\n background: #444;\n}\n\n.half-face-lower {\n top: 50%;\n background: #938506;\n}\n\n.half-face-upper {\n background: #444;\n}\n\n.half-face {\n position: absolute;\n height: 50%;\n width: 100%;\n}\n\n.top-face-front {\n background-size: contain;\n background-image: url(\"../../assets/ig_win_coin.png\");\n}\n",".display {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: space-between;\n width: 100%;\n}\n\n.title-container {\n font-size: 1.25em;\n color: #ffffff;\n margin: 8px;\n display: flex;\n flex-direction: row;\n}\n\n.value {\n margin-left: 6px;\n}\n\n@media (max-width: 400px) {\n .title-container {\n font-size: 1em;\n }\n}\n",".coin-picker-container {\n display: flex;\n width: 100%;\n}\n\n.coin-button-container {\n flex: 1;\n padding: 6px 12px;\n}\n\n.coin-picker-button-icon {\n width: 20px;\n height: 20px;\n margin-right: 6px;\n}\n\n.coin-picker-button {\n width: 100%;\n height: 100%;\n outline: none;\n filter: grayscale(100%);\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 42px;\n font-family: inherit;\n cursor: pointer;\n border-radius: 8px;\n color: white;\n font-size: 16px;\n font-weight: bold;\n border: 3px solid rgb(197,197,197);\n background-color: rgb(222,222,222);\n transition: 0.25s ease all\n}\n\n.coin-picker-button.active {\n cursor: default;\n filter: grayscale(0%);\n border-color: rgb(254,159,37);\n background-color: rgb(255,197,41);\n}\n",".header {\n z-index: 2000;\n padding: 1em 1.5em;\n background: rgb(72,25,124);\n color: white;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.header-reward {\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.reward-container {\n border-radius: 5px;\n margin: 0 8px;\n background: rgb(42,14,74);\n padding: 2px 8px;\n}\n\n.arrow-circle {\n transition: 0.25s all;\n}\n\n.arrow-circle.open {\n transform: rotateX(180deg);\n}\n",".ReferralRule-container {\n top:55px;\n bottom:0;\n width: 100%;\n overflow: auto;\n position: absolute;\n z-index: 200;\n background: rgba(29,6,34,0.9);\n}\n\n.inner-container {\n max-width: 420px;\n margin: auto;\n color: white;\n padding: 24px;\n}\n\n.share-container {\n line-height: 1.5;\n font-size: 1.15em;\n text-align: center;\n border-radius: 5px;\n background: rgba(72,26,86,0.75);\n padding: 24px;\n margin-bottom: 1.5em;\n}\n\n.referral-title {\n text-align: center;\n color: rgb(250,245,40);\n margin-bottom: 1em;\n}\n\n.referral-link-container {\n display: flex;\n align-items: stretch;\n justify-content: center;\n margin-bottom: 1.5em;\n}\n\n.referral-link {\n font-size: .85em;\n font-family: sans-serif;\n word-break: break-all;\n padding: 12px;\n background: rgba(56,34,63, 0.75);\n border-radius: 5px;\n flex: 1;\n}\n\n.copy-button {\n cursor: pointer;\n margin-bottom: 6px;\n border: none;\n outline: none;\n font-size: 1.5em;\n font-family: inherit;\n padding: 20px;\n margin-left: 8px;\n border-radius: 5px;\n color: black;\n background: rgb(255,197,41);\n box-shadow: 0 6px 2px rgb(186,117,26);\n transition: 0.25s all;\n}\n\n.copy-button.clicked {\n margin-top: 6px;\n margin-bottom: 0;\n box-shadow: 0 0 0 rgb(186,117,26);\n}\n\n.referral-stats-container {\n margin-bottom: 2em;\n}\n\n.referral-stat {\n display: flex;\n justify-content: space-between;\n margin-bottom: 0.75em;\n font-size: 0.85em;\n}\n\n.referral-rule-block {\n margin-bottom: 1em;\n}\n\n.table {\n display: flex;\n border-radius: 5px;\n overflow: hidden;\n margin-bottom: 1em;\n}\n\n.table-column {\n flex: 1;\n}\n\n.table-column.dark {\n background-color: rgb(70,19,81);\n}\n\n.table-column.light {\n background-color: rgb(134,52,153);\n}\n\n.table-column.med {\n background-color: rgb(93,34,107);\n}\n\n.cell {\n display: flex;\n padding: 6px;\n align-items: center;\n justify-content: center;\n height: 50px;\n text-align: center;\n border: 1px solid rgba(255,255,255,0.05);\n}\n"]} -------------------------------------------------------------------------------- /frontend/build/static/js/main.22e40df3.chunk.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonpfrontend=window.webpackJsonpfrontend||[]).push([[0],{126:function(e){e.exports=JSON.parse('{"a":[{"constant":true,"inputs":[{"name":"data","type":"uint256[]"}],"name":"sum","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"hasReferrer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_secondsUntilInactive","type":"uint256"}],"name":"setSecondsUntilInactive","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"accounts","outputs":[{"name":"referrer","type":"address"},{"name":"reward","type":"uint256"},{"name":"referredCount","type":"uint256"},{"name":"lastActiveTimestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"amount","type":"uint256"}],"name":"getRefereeBonusRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_onlyRewardActiveReferrers","type":"bool"}],"name":"setOnlyRewardAActiveReferrers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_decimals","type":"uint256"},{"name":"_referralBonus","type":"uint256"},{"name":"_secondsUntilInactive","type":"uint256"},{"name":"_onlyRewardActiveReferrers","type":"bool"},{"name":"_levelRate","type":"uint256[]"},{"name":"_refereeBonusRateMap","type":"uint256[]"},{"name":"_tokenAddresses","type":"address[]"},{"name":"_randomNumberContractAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"player","type":"address"},{"indexed":false,"name":"winnings","type":"uint256"}],"name":"BetSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"referee","type":"address"},{"indexed":false,"name":"referrer","type":"address"}],"name":"RegisteredReferer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"referee","type":"address"},{"indexed":false,"name":"referrer","type":"address"},{"indexed":false,"name":"reason","type":"string"}],"name":"RegisteredRefererFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"from","type":"address"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"level","type":"uint256"}],"name":"PaidReferral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"user","type":"address"},{"indexed":false,"name":"timestamp","type":"uint256"}],"name":"UpdatedUserLastActiveTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"constant":false,"inputs":[{"name":"_tokenAddress","type":"address"}],"name":"addToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenAddress","type":"address"}],"name":"deleteToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_referrer","type":"address"}],"name":"bet","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"bet","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"_value","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"onTokenTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenAddress","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]}')},129:function(e,t,a){e.exports=a.p+"static/media/ig_coin_card.968dcb99.png"},130:function(e,t,a){e.exports=a.p+"static/media/tt-usdt.6ef85566.png"},131:function(e,t){e.exports="data:image/png;base64,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"},133:function(e){e.exports=JSON.parse('{"a":[{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"},{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"data","type":"bytes"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"bytes"}],"name":"transferAndCall","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]}')},135:function(e,t,a){e.exports=a(291)},140:function(e,t,a){},141:function(e,t,a){},143:function(e,t){},147:function(e,t){},176:function(e,t){},178:function(e,t){},282:function(e,t,a){},283:function(e,t,a){},284:function(e,t,a){},285:function(e,t,a){},286:function(e,t,a){},290:function(e,t,a){},291:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),s=a(125),i=a.n(s),o=(a(140),a(19)),c=a(4),l=a(5),u=a(7),d=a(6),p=(a(141),a(126)),m=a(17),f=a(134),y=a(127),b=r.a.createContext({enable:function(){},address:"",signer:void 0,enabling:!1,enabled:!1}),v=b.Consumer,g=b.Provider,h=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(e){var n;Object(c.a)(this,a),(n=t.call(this,e)).enable=function(){n.state.signer&&(n.setState({enabling:!0}),n.state.signer.provider._web3Provider.enable().then(function(e){var t=Object(f.a)(e,1)[0];n.setState({enabling:!1,enabled:!0,address:t})}).catch(function(){n.setState({enabling:!1,enabled:!1})}))};var r=!!window.ethereum;return n.state={address:"",signer:r&&new y.Web3Provider(window.ethereum).getSigner(),enabled:!1,enabling:r&&!!e.enableOnLoad},n}return Object(l.a)(a,[{key:"componentDidMount",value:function(){this.props.enableOnLoad&&this.enable()}},{key:"render",value:function(){return r.a.createElement(g,{value:Object(m.a)(Object(m.a)({},this.state),{},{enable:this.enable})},this.props.children)}}]),a}(r.a.PureComponent),E=v,w=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(){var e;Object(c.a)(this,a);for(var n=arguments.length,r=new Array(n),s=0;s=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var L,Q=r.a.createElement("g",{id:"ic_arrow-down-circle",transform:"translate(1,1)",fill:"none",stroke:"#FFFFFF",strokeWidth:2},r.a.createElement("circle",{id:"Oval",cx:10,cy:10,r:10}),r.a.createElement("polyline",{id:"Path",points:"6 10 10 14 14 10"}),r.a.createElement("path",{d:"M10,6 L10,14",id:"Path"})),q=function(e){var t=e.svgRef,a=e.title,n=V(e,["svgRef","title"]);return r.a.createElement("svg",Z({width:"22px",height:"22px",viewBox:"0 0 22 22",ref:t},n),r.a.createElement("title",null,a),Q)},W=r.a.forwardRef(function(e,t){return r.a.createElement(q,Z({svgRef:t},e))}),Y=(a.p,a(132)),K=(a(290),function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(){var e;Object(c.a)(this,a);for(var n=arguments.length,r=new Array(n),s=0;s="5"?t.slice(a,n-1)+(parseInt(t.slice(n-1,n))+1).toString():t.slice(a,n);return r=r.replace(/0+$/,""),t.slice(0,a)+(r?"."+r:"")}},{key:"render",value:function(){var e=this.state.open;return r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"header"},r.a.createElement("div",null,"Double or Nothing"),r.a.createElement("div",{className:"header-reward"},r.a.createElement("div",null,"Reward"),r.a.createElement("div",{className:"reward-container"},this.calcualteEther(this.props.rewards)),r.a.createElement(W,{onClick:this.toggle,className:"arrow-circle ".concat(e?"open":"")}))),e&&r.a.createElement(K,{address:this.props.address,reward:this.calcualteEther(this.props.rewards),refereeCount:this.props.refereeCount,activeTimestamp:this.props.activeTimestamp}))}}]),a}(r.a.PureComponent),z=.5,_=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(e){var n;Object(c.a)(this,a),(n=t.call(this,e)).intervals=[],n.watchBalance=function(){n.intervals.push(setInterval(function(){n.props.contract.provider.getBalance(n.props.address).then(function(e){n.setState({balance:e.toString()})})},500))},n.watchReferrals=function(){n.intervals.push(setInterval(function(){n.props.contract.accounts(n.props.address).then(function(e){n.setState({accountInfo:{reward:e.reward.toString(),referredCount:e.referredCount.toString(),activeTimestamp:1e3*e.lastActiveTimestamp.toString()+864e5}})})},500))},n.log=function(e){n.setState(function(t){return{debugMessages:["".concat(e)].concat(t.debugMessages)}})},n.play=function(e){var t;n.setState({disabled:!0});var a=[{value:Object(T.parseEther)(e.toString()).toHexString(),gasPrice:Object(T.bigNumberify)("1000000000").toHexString(),gasLimit:Object(T.bigNumberify)("2000000").toHexString()}],r=!!n.state.referrer;r&&a.unshift(n.state.referrer),(t=n.props.contract)[r?"bet(address)":"bet()"].apply(t,a).then(function(e){return n.setState({flipping:!0}),e.wait()}).then(function(e){var t=e.events.find(function(e){return"BetSettled"===e.event});n.setState({flipping:!1,win:"0"!==t.args.winnings.toString()})}).catch(function(e){console.log('setState("logs", '.concat(e,")")),n.log(JSON.stringify(e))}).finally(function(){n.setState({disabled:!1,flipping:!1})})},n.playGame=function(){n.play(n.state.betAmount)},n.double=function(){var e=2*n.state.betAmount;n.setState({betAmount:e}),n.play(e)},n.reset=function(){n.setState({betAmount:z})},n.watchBalance(),n.watchReferrals();var r=window.location.search.match(/referrer=(0x[a-fA-F0-9]{40})/),s=r?r[1]:"";return n.state={referrer:s.toLowerCase(),betAmount:z,balance:"",win:!0,disabled:!1,flipping:!1,accountInfo:{reward:"0",referredCount:"0",activeTimestamp:Date.now()},debugMessages:[]},n}return Object(l.a)(a,[{key:"componentWillUnmount",value:function(){this.intervals.forEach(function(e){return clearInterval(e)})}},{key:"render",value:function(){var e=this.state,t=e.disabled,a=e.flipping,n=e.win,s=e.balance,i=e.betAmount,o=e.accountInfo;return r.a.createElement(r.a.Fragment,null,r.a.createElement(X,{address:this.props.address,rewards:o.reward,refereeCount:o.referredCount,activeTimestamp:o.activeTimestamp}),r.a.createElement(G,{changeContract:this.props.changeContract,active:S.DoubleOrNothing,double:this.double,playGame:this.playGame,reset:this.reset,betAmount:i,balance:s,win:n,disabled:t,flipping:a,decimals:18,symbol:"TT"}),r.a.createElement("div",{id:"debug-messages"},this.state.debugMessages.map(function(e,t){return r.a.createElement("div",{key:t},e)})))}}]),a}(r.a.PureComponent),$=.5,ee=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(e){var n;return Object(c.a)(this,a),(n=t.call(this,e)).interval=void 0,n.watchBalance=function(){n.interval=setInterval(function(){n.props.contract.balanceOf(n.props.address).then(function(e){return n.props.contract.decimals().then(function(t){n.setState({balance:e.toString(),decimals:t})})})},500)},n.play=function(e){n.setState({disabled:!0}),n.props.contract.decimals().then(function(t){console.log(t),n.props.contract.transferAndCall(n.props.gameAddress,Object(T.parseUnits)(e.toString(),t),"0xfae",{gasPrice:Object(T.bigNumberify)("1000000000").toHexString(),gasLimit:Object(T.bigNumberify)("100000").toHexString()}).then(function(e){return n.setState({flipping:!0}),e.wait()}).then(function(e){var t=!!e.events.find(function(e){return"Transfer"===e.event&&e.args.to.toLowerCase()===n.props.address.toLowerCase()});n.setState({flipping:!1,win:t})}).finally(function(){n.setState({disabled:!1,flipping:!1})})})},n.playGame=function(){n.play(n.state.betAmount)},n.double=function(){var e=2*n.state.betAmount;n.setState({betAmount:e}),n.play(e)},n.reset=function(){n.setState({betAmount:$})},n.state={betAmount:$,balance:"",win:!0,disabled:!1,flipping:!1,accountInfo:{reward:"0",referredCount:"0",activeTimestamp:Date.now()},decimals:6},n.watchBalance(),n}return Object(l.a)(a,[{key:"componentWillUnmount",value:function(){this.interval&&clearInterval(this.interval)}},{key:"render",value:function(){var e=this.state,t=e.disabled,a=e.flipping,n=e.win,s=e.balance,i=e.betAmount,o=e.accountInfo,c=e.decimals;return r.a.createElement(r.a.Fragment,null,r.a.createElement(X,{address:this.props.address,rewards:o.reward,refereeCount:o.referredCount,activeTimestamp:o.activeTimestamp}),r.a.createElement(G,{changeContract:this.props.changeContract,active:this.props.contractName,double:this.double,playGame:this.playGame,reset:this.reset,betAmount:i,balance:s,win:n,disabled:t,flipping:a,decimals:c,symbol:"USDT"}))}}]),a}(r.a.PureComponent),te=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(){var e;Object(c.a)(this,a);for(var n=arguments.length,r=new Array(n),s=0;s 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/build/static/media/ig_coin_card.968dcb99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/build/static/media/ig_coin_card.968dcb99.png -------------------------------------------------------------------------------- /frontend/build/static/media/ig_lose_coin.91f34167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/build/static/media/ig_lose_coin.91f34167.png -------------------------------------------------------------------------------- /frontend/build/static/media/ig_win_coin.44207f94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/build/static/media/ig_win_coin.44207f94.png -------------------------------------------------------------------------------- /frontend/build/static/media/tt-usdt.6ef85566.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/build/static/media/tt-usdt.6ef85566.png -------------------------------------------------------------------------------- /frontend/environment.yml: -------------------------------------------------------------------------------- 1 | name: double-or-nothing 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - nodejs=10.16.3 # hub-analytics-frontend 6 | - yarn=1.22.0 7 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "ethers": "^4.0.29", 7 | "react": "^16.8.6", 8 | "react-countdown-now": "^2.1.1", 9 | "react-dom": "^16.8.6" 10 | }, 11 | "devDependencies": { 12 | "@types/jest": "24.0.13", 13 | "@types/node": "12.0.7", 14 | "@types/react": "16.8.19", 15 | "@types/react-dom": "16.8.4", 16 | "react-scripts": "3.1.2", 17 | "typescript": "^3.8.3" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "PUBLIC_URL=/frontend/build react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 23 | DoubleOrNothing 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "DON", 3 | "name": "Double Or Nothing", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/ContractEnum.ts: -------------------------------------------------------------------------------- 1 | export enum ContractEnum { 2 | TTUsdt = 'tt-usdt', 3 | DoubleOrNothing = 'doubleOrNothing' 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/bg.jpg -------------------------------------------------------------------------------- /frontend/src/assets/ic_arrow-down-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/src/assets/icon_TT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/icon_TT.png -------------------------------------------------------------------------------- /frontend/src/assets/ig_bet_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/ig_bet_btn.png -------------------------------------------------------------------------------- /frontend/src/assets/ig_coin_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/ig_coin_card.png -------------------------------------------------------------------------------- /frontend/src/assets/ig_double_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/ig_double_btn.png -------------------------------------------------------------------------------- /frontend/src/assets/ig_lose_coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/ig_lose_coin.png -------------------------------------------------------------------------------- /frontend/src/assets/ig_reset_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/ig_reset_btn.png -------------------------------------------------------------------------------- /frontend/src/assets/ig_win_coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/ig_win_coin.png -------------------------------------------------------------------------------- /frontend/src/assets/tt-usdt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thundercore/DoubleOrNothing/dd0501343022f2c4f5217c42a69fad2280306e84/frontend/src/assets/tt-usdt.png -------------------------------------------------------------------------------- /frontend/src/components/App/App.css: -------------------------------------------------------------------------------- 1 | html, body, .app, #root { 2 | height: 100%; 3 | font-family: 'Russo One', sans-serif; 4 | } 5 | 6 | .app { 7 | background-image: url("../../assets/bg.jpg"); 8 | background-repeat: no-repeat; 9 | background-size: cover; 10 | background-position: center; 11 | min-height: 510px; 12 | } 13 | 14 | .app-message { 15 | padding-top: 5vh; 16 | text-align: center; 17 | color: white; 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/components/App/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './App.css' 3 | import { abi } from './DoubleOrNothing.json' 4 | import Web3Loader from '../Web3Loader/Web3Loader' 5 | import ContractLoader from '../ContractLoader/ContractLoader' 6 | import { IWeb3Context } from '../../contexts/Web3Context/Web3Context' 7 | import { IContractContext } from '../../contexts/ContractContext/ContractContext' 8 | import GameContainer from '../../containers/GameContainer/GameContainer' 9 | import config from '../../config' 10 | import { abi as Erc677Abi } from './ERC677.json' 11 | import { ContractEnum } from '../../ContractEnum' 12 | 13 | interface IAppProps {} 14 | interface IAppState {} 15 | 16 | export class App extends React.PureComponent { 17 | renderIncapable() { 18 | return ( 19 |
20 |
Please connect a Web3 provider
21 |
22 | ) 23 | } 24 | 25 | renderPleaseEnable() { 26 | return ( 27 |
28 |
Please enable your Web3 Provider
29 |
30 | ) 31 | } 32 | 33 | renderEnabled = (params: IWeb3Context) => { 34 | return ( 35 |
36 | 50 | this.renderGame(contractParams, params.address) 51 | } 52 | renderLoading={this.renderLoading} 53 | renderUnavailable={this.renderUnavailable} 54 | /> 55 |
56 | ) 57 | } 58 | 59 | renderLoading() { 60 | return
Loading...
61 | } 62 | 63 | renderUnavailable() { 64 | return
Error loading contract
65 | } 66 | 67 | renderGame(params: IContractContext, address: string) { 68 | return ( 69 | 77 | ) 78 | } 79 | 80 | render() { 81 | return ( 82 | 88 | ) 89 | } 90 | } 91 | 92 | export default App 93 | -------------------------------------------------------------------------------- /frontend/src/components/App/DoubleOrNothing.json: -------------------------------------------------------------------------------- 1 | ../../../../smart-contracts/build/contracts/DoubleOrNothing.json -------------------------------------------------------------------------------- /frontend/src/components/Coin/Coin.css: -------------------------------------------------------------------------------- 1 | .coin-container { 2 | transform-style: preserve-3d; 3 | transition: 0.5s all; 4 | position: relative; 5 | width: 140px; 6 | height: 140px; 7 | border-radius: 50%; 8 | } 9 | 10 | .flipped { 11 | transform: rotateX(180deg); 12 | } 13 | 14 | .face { 15 | backface-visibility: hidden; 16 | } 17 | 18 | .top-face { 19 | transform: translateZ(8px); 20 | } 21 | 22 | .top-back-face { 23 | background: #444; 24 | } 25 | 26 | .disk-body { 27 | width: 140px; 28 | height: 16px; 29 | position: absolute; 30 | background: #444; 31 | backface-visibility: hidden; 32 | transform: translate3d(0,63px,0) rotateX(90deg); 33 | } 34 | 35 | .disk-body.back { 36 | background: #938506; 37 | transform: translate3d(0,63px,0) rotateX(90deg) rotateY(180deg); 38 | } 39 | 40 | .disk { 41 | overflow: hidden; 42 | border-radius: 50%; 43 | position: absolute; 44 | height: 100%; 45 | width: 100%; 46 | background: #444; 47 | } 48 | 49 | .bottom-front-face { 50 | background-size: contain; 51 | background-image: url("../../assets/ig_lose_coin.png"); 52 | transform: translateZ(-8px) rotateX(180deg); 53 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.45); 54 | } 55 | 56 | .bottom-back-face { 57 | transform: translateZ(-8px); 58 | background: #444; 59 | } 60 | 61 | .half-face-lower { 62 | top: 50%; 63 | background: #938506; 64 | } 65 | 66 | .half-face-upper { 67 | background: #444; 68 | } 69 | 70 | .half-face { 71 | position: absolute; 72 | height: 50%; 73 | width: 100%; 74 | } 75 | 76 | .top-face-front { 77 | background-size: contain; 78 | background-image: url("../../assets/ig_win_coin.png"); 79 | } 80 | -------------------------------------------------------------------------------- /frontend/src/components/Coin/Coin.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './Coin.css' 3 | 4 | interface ICoinProps { 5 | showFace: boolean 6 | } 7 | 8 | export class Coin extends React.PureComponent { 9 | render() { 10 | return ( 11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ) 28 | } 29 | } 30 | 31 | export default Coin 32 | -------------------------------------------------------------------------------- /frontend/src/components/CoinPicker/CoinPicker.css: -------------------------------------------------------------------------------- 1 | .coin-picker-container { 2 | display: flex; 3 | width: 100%; 4 | } 5 | 6 | .coin-button-container { 7 | flex: 1; 8 | padding: 6px 12px; 9 | } 10 | 11 | .coin-picker-button-icon { 12 | width: 20px; 13 | height: 20px; 14 | margin-right: 6px; 15 | } 16 | 17 | .coin-picker-button { 18 | width: 100%; 19 | height: 100%; 20 | outline: none; 21 | filter: grayscale(100%); 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | min-height: 42px; 26 | font-family: inherit; 27 | cursor: pointer; 28 | border-radius: 8px; 29 | color: white; 30 | font-size: 16px; 31 | font-weight: bold; 32 | border: 3px solid rgb(197,197,197); 33 | background-color: rgb(222,222,222); 34 | transition: 0.25s ease all 35 | } 36 | 37 | .coin-picker-button.active { 38 | cursor: default; 39 | filter: grayscale(0%); 40 | border-color: rgb(254,159,37); 41 | background-color: rgb(255,197,41); 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/components/CoinPicker/CoinPicker.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './CoinPicker.css' 3 | import TTUsdtImg from '../../assets/tt-usdt.png' 4 | import TTImg from '../../assets/icon_TT.png' 5 | import { ContractEnum } from '../../ContractEnum' 6 | 7 | interface ICoinPickerProps { 8 | active: ContractEnum 9 | changeContract(coin: ContractEnum): any 10 | } 11 | 12 | const buttons = [ 13 | { 14 | name: ContractEnum.DoubleOrNothing, 15 | img: TTImg, 16 | text: 'TT' 17 | }, 18 | { 19 | name: ContractEnum.TTUsdt, 20 | img: TTUsdtImg, 21 | text: 'TT USDT' 22 | }, 23 | ] 24 | 25 | export class CoinPicker extends React.PureComponent { 26 | render() { 27 | const { active, changeContract } = this.props 28 | return ( 29 |
30 | {buttons.map(button => ( 31 |
32 | 46 |
47 | ))} 48 |
49 | ) 50 | } 51 | } 52 | 53 | export default CoinPicker 54 | -------------------------------------------------------------------------------- /frontend/src/components/ContractLoader/ContractLoader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import ContractProvider, { 4 | ContractConsumer, 5 | IContractContext 6 | } from '../../contexts/ContractContext/ContractContext' 7 | import { Signer } from 'ethers' 8 | 9 | interface IContractData { 10 | abi: any[] 11 | address: string 12 | signer: Signer 13 | } 14 | 15 | interface IContractLoaderProps { 16 | contractData: IContractData[] 17 | renderLoading(params: IContractContext): React.ReactNode 18 | renderEnabled(params: IContractContext): React.ReactNode 19 | renderUnavailable(params: IContractContext): React.ReactNode 20 | } 21 | 22 | interface IContractLoaderState { 23 | contracts: IContractData[] 24 | } 25 | 26 | export class ContractLoader extends React.PureComponent< 27 | IContractLoaderProps, 28 | IContractLoaderState 29 | > { 30 | static getDerivedStateFromProps(props: IContractLoaderProps) { 31 | return { 32 | contracts: props.contractData.map(data => ({ 33 | ...data, 34 | checkOnLoad: true 35 | })) 36 | } 37 | } 38 | state: IContractLoaderState = { 39 | contracts: [] 40 | } 41 | 42 | renderContractState = (params: IContractContext) => { 43 | // @ts-ignore 44 | if (Object.keys(params).find(key => params[key].loading)) { 45 | return this.props.renderLoading(params) 46 | // @ts-ignore 47 | } else if (Object.keys(params).find(key => params[key].error)) { 48 | return this.props.renderUnavailable(params) 49 | } 50 | return this.props.renderEnabled(params) 51 | } 52 | 53 | render() { 54 | return ( 55 | 56 | {this.renderContractState} 57 | 58 | ) 59 | } 60 | } 61 | 62 | export default ContractLoader 63 | -------------------------------------------------------------------------------- /frontend/src/components/Display/Display.css: -------------------------------------------------------------------------------- 1 | .display { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | justify-content: space-between; 6 | width: 100%; 7 | } 8 | 9 | .title-container { 10 | font-size: 1.25em; 11 | color: #ffffff; 12 | margin: 8px; 13 | display: flex; 14 | flex-direction: row; 15 | } 16 | 17 | .value { 18 | margin-left: 6px; 19 | } 20 | 21 | @media (max-width: 400px) { 22 | .title-container { 23 | font-size: 1em; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/components/Display/Display.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './Display.css' 3 | 4 | interface IDisplayProps { 5 | balance: string 6 | betAmount: string 7 | symbol: string 8 | } 9 | 10 | export class Display extends React.PureComponent { 11 | render() { 12 | const { balance, betAmount, symbol } = this.props 13 | return ( 14 |
15 |
16 |
Balance:
17 |
18 | {parseFloat(balance).toFixed(2)} {symbol} 19 |
20 |
21 |
22 |
Bet Size:
23 |
{betAmount} {symbol}
24 |
25 |
26 | ) 27 | } 28 | } 29 | 30 | export default Display 31 | -------------------------------------------------------------------------------- /frontend/src/components/Game/Game.css: -------------------------------------------------------------------------------- 1 | .game-container { 2 | display: flex; 3 | max-width: 420px; 4 | width: 95%; 5 | margin: auto; 6 | align-items: center; 7 | flex-direction: column; 8 | margin-top: 1em; 9 | } 10 | 11 | .display-container { 12 | margin-bottom: 1.5em; 13 | width: 100%; 14 | } 15 | 16 | .coin-display-container { 17 | position: relative; 18 | width: 90%; 19 | } 20 | 21 | .coin-display-container img { 22 | width: 100%; 23 | } 24 | 25 | .flip { 26 | animation: flip 0.5s linear 3; 27 | } 28 | 29 | .container { 30 | text-align: center; 31 | margin-bottom: 1em; 32 | } 33 | 34 | .center { 35 | position: absolute; 36 | top: 50%; 37 | left: 50%; 38 | transform: translate(-50%,-50%) 39 | } 40 | 41 | .coin { 42 | transform-style: preserve-3d; 43 | transform: rotateX(15deg); 44 | transition: all 0.5s linear; 45 | } 46 | 47 | .button { 48 | outline: none; 49 | border: none; 50 | height: 60px; 51 | width: 150px; 52 | background-color: transparent; 53 | background-size: contain; 54 | background-repeat: no-repeat; 55 | transition: all 0.25s ease; 56 | } 57 | 58 | .button[disabled] { 59 | filter: grayscale(1); 60 | } 61 | 62 | .bet-button { 63 | background-image: url("../../assets/ig_bet_btn.png"); 64 | } 65 | 66 | 67 | .reset-button { 68 | background-image: url("../../assets/ig_reset_btn.png"); 69 | } 70 | 71 | .double-button { 72 | background-image: url("../../assets/ig_double_btn.png"); 73 | } 74 | 75 | 76 | @keyframes flip { 77 | 0% { 78 | transform: rotateX(10deg); 79 | } 80 | 100% { 81 | transform: rotateX(370deg); 82 | } 83 | } 84 | 85 | #debug-messages { 86 | background-image: none; 87 | background-color: white; 88 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 89 | } 90 | -------------------------------------------------------------------------------- /frontend/src/components/Game/Game.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './Game.css' 3 | import Coin from '../Coin/Coin' 4 | import Display from '../Display/Display' 5 | import cardSrc from '../../assets/ig_coin_card.png' 6 | import CoinPicker from '../CoinPicker/CoinPicker' 7 | import { ContractEnum } from '../../ContractEnum' 8 | import { formatUnits } from 'ethers/utils' 9 | 10 | interface IGameProps { 11 | active: ContractEnum 12 | changeContract(coin: ContractEnum): any 13 | playGame(): any 14 | double(): any 15 | reset(): any 16 | flipping: boolean 17 | disabled: boolean 18 | win: boolean 19 | balance: string 20 | betAmount: number 21 | decimals: number 22 | symbol: string 23 | } 24 | 25 | interface IGameState { 26 | animating: boolean 27 | } 28 | 29 | export class Game extends React.PureComponent { 30 | static getDerivedStateFromProps(props: IGameProps, state: IGameState) { 31 | return props.flipping && !state.animating ? { animating: true } : null 32 | } 33 | 34 | state = { 35 | animating: false 36 | } 37 | 38 | render() { 39 | const { 40 | playGame, 41 | disabled, 42 | win, 43 | double, 44 | balance, 45 | betAmount, 46 | reset, 47 | active, 48 | changeContract, 49 | decimals, 50 | symbol, 51 | } = this.props 52 | const { animating } = this.state 53 | let b = balance.length === 0 ? '0' : balance 54 | return ( 55 |
56 | 57 |
58 | 59 |
60 |
61 | 62 |
63 |
{ 66 | this.setState({ animating: false }) 67 | }} 68 | > 69 | 70 |
71 |
72 |
73 |
74 |
80 |
81 |
92 |
93 | ) 94 | } 95 | } 96 | 97 | export default Game 98 | -------------------------------------------------------------------------------- /frontend/src/components/Header/Header.css: -------------------------------------------------------------------------------- 1 | .header { 2 | z-index: 2000; 3 | padding: 1em 1.5em; 4 | background: rgb(72,25,124); 5 | color: white; 6 | display: flex; 7 | justify-content: space-between; 8 | align-items: center; 9 | } 10 | 11 | .header-reward { 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | } 16 | 17 | .reward-container { 18 | border-radius: 5px; 19 | margin: 0 8px; 20 | background: rgb(42,14,74); 21 | padding: 2px 8px; 22 | } 23 | 24 | .arrow-circle { 25 | transition: 0.25s all; 26 | } 27 | 28 | .arrow-circle.open { 29 | transform: rotateX(180deg); 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/components/Header/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './Header.css' 3 | import { ReactComponent as ArrowCircle } from '../../assets/ic_arrow-down-circle.svg' 4 | import ReferralRules from '../ReferralRules/ReferralRules' 5 | interface IHeaderProps { 6 | address: string 7 | rewards: string 8 | refereeCount: string 9 | activeTimestamp: number 10 | } 11 | interface IHeaderState { 12 | open: boolean 13 | } 14 | 15 | export class Header extends React.PureComponent { 16 | state = { 17 | open: false 18 | } 19 | 20 | calcualteEther(wei: string) { 21 | const amt = wei.padStart(19, '0') 22 | const decimalIdx = amt.length - 18 23 | const precisionIdx = decimalIdx + 4 24 | // round the next precision 25 | const roundUp = amt.slice(precisionIdx, precisionIdx + 1) >= '5' 26 | let decimal = roundUp 27 | ? amt.slice(decimalIdx, precisionIdx - 1) + 28 | (parseInt(amt.slice(precisionIdx - 1, precisionIdx)) + 1).toString() 29 | : amt.slice(decimalIdx, precisionIdx) 30 | decimal = decimal.replace(/0+$/, '') 31 | return amt.slice(0, decimalIdx) + (decimal ? '.' + decimal : '') 32 | } 33 | 34 | toggle = () => this.setState({ open: !this.state.open }) 35 | 36 | render() { 37 | const { open } = this.state 38 | return ( 39 | <> 40 |
41 |
Double or Nothing
42 |
43 |
Reward
44 |
45 | {this.calcualteEther(this.props.rewards)} 46 |
47 | 51 |
52 |
53 | {open && ( 54 | 60 | )} 61 | 62 | ) 63 | } 64 | } 65 | 66 | export default Header 67 | -------------------------------------------------------------------------------- /frontend/src/components/ReferralRules/ReferralRules.css: -------------------------------------------------------------------------------- 1 | .ReferralRule-container { 2 | top:55px; 3 | bottom:0; 4 | width: 100%; 5 | overflow: auto; 6 | position: absolute; 7 | z-index: 200; 8 | background: rgba(29,6,34,0.9); 9 | } 10 | 11 | .inner-container { 12 | max-width: 420px; 13 | margin: auto; 14 | color: white; 15 | padding: 24px; 16 | } 17 | 18 | .share-container { 19 | line-height: 1.5; 20 | font-size: 1.15em; 21 | text-align: center; 22 | border-radius: 5px; 23 | background: rgba(72,26,86,0.75); 24 | padding: 24px; 25 | margin-bottom: 1.5em; 26 | } 27 | 28 | .referral-title { 29 | text-align: center; 30 | color: rgb(250,245,40); 31 | margin-bottom: 1em; 32 | } 33 | 34 | .referral-link-container { 35 | display: flex; 36 | align-items: stretch; 37 | justify-content: center; 38 | margin-bottom: 1.5em; 39 | } 40 | 41 | .referral-link { 42 | font-size: .85em; 43 | font-family: sans-serif; 44 | word-break: break-all; 45 | padding: 12px; 46 | background: rgba(56,34,63, 0.75); 47 | border-radius: 5px; 48 | flex: 1; 49 | } 50 | 51 | .copy-button { 52 | cursor: pointer; 53 | margin-bottom: 6px; 54 | border: none; 55 | outline: none; 56 | font-size: 1.5em; 57 | font-family: inherit; 58 | padding: 20px; 59 | margin-left: 8px; 60 | border-radius: 5px; 61 | color: black; 62 | background: rgb(255,197,41); 63 | box-shadow: 0 6px 2px rgb(186,117,26); 64 | transition: 0.25s all; 65 | } 66 | 67 | .copy-button.clicked { 68 | margin-top: 6px; 69 | margin-bottom: 0; 70 | box-shadow: 0 0 0 rgb(186,117,26); 71 | } 72 | 73 | .referral-stats-container { 74 | margin-bottom: 2em; 75 | } 76 | 77 | .referral-stat { 78 | display: flex; 79 | justify-content: space-between; 80 | margin-bottom: 0.75em; 81 | font-size: 0.85em; 82 | } 83 | 84 | .referral-rule-block { 85 | margin-bottom: 1em; 86 | } 87 | 88 | .table { 89 | display: flex; 90 | border-radius: 5px; 91 | overflow: hidden; 92 | margin-bottom: 1em; 93 | } 94 | 95 | .table-column { 96 | flex: 1; 97 | } 98 | 99 | .table-column.dark { 100 | background-color: rgb(70,19,81); 101 | } 102 | 103 | .table-column.light { 104 | background-color: rgb(134,52,153); 105 | } 106 | 107 | .table-column.med { 108 | background-color: rgb(93,34,107); 109 | } 110 | 111 | .cell { 112 | display: flex; 113 | padding: 6px; 114 | align-items: center; 115 | justify-content: center; 116 | height: 50px; 117 | text-align: center; 118 | border: 1px solid rgba(255,255,255,0.05); 119 | } 120 | -------------------------------------------------------------------------------- /frontend/src/components/ReferralRules/ReferralRules.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Countdown, { CountdownRenderProps } from 'react-countdown-now' 3 | 4 | import './ReferralRules.css' 5 | 6 | interface IReferralRuleProps { 7 | address: string 8 | refereeCount: string 9 | reward: string 10 | activeTimestamp: number 11 | } 12 | 13 | interface IReferralRuleState { 14 | clicked: boolean 15 | } 16 | 17 | export class ReferralRules extends React.PureComponent< 18 | IReferralRuleProps, 19 | IReferralRuleState 20 | > { 21 | state = { 22 | clicked: false 23 | } 24 | 25 | renderStat(title: string, val: any) { 26 | return ( 27 |
28 |
{title}
29 |
{val}
30 |
31 | ) 32 | } 33 | 34 | referralLink = () => { 35 | return window.location.origin + `?referrer=${this.props.address}` 36 | } 37 | 38 | copy = () => { 39 | const input = document.createElement('input') 40 | document.body.append(input) 41 | input.value = this.referralLink() 42 | input.select() 43 | document.execCommand('copy') 44 | document.body.removeChild(input) 45 | this.setState({ clicked: true }) 46 | } 47 | 48 | renderColumn(header: string, val: string, className: string) { 49 | return ( 50 |
51 |
{header}
52 |
{val}
53 |
54 | ) 55 | } 56 | 57 | renderCountdown({ 58 | hours, 59 | minutes, 60 | seconds, 61 | completed 62 | }: CountdownRenderProps) { 63 | function paddingTime(val: number) { 64 | return ('00' + val).slice(-2) 65 | } 66 | 67 | return completed ? ( 68 | 00:00:00 69 | ) : ( 70 | 71 | {paddingTime(hours)}:{paddingTime(minutes)}:{paddingTime(seconds)} 72 | 73 | ) 74 | } 75 | 76 | render() { 77 | const { clicked } = this.state 78 | const { refereeCount, reward, activeTimestamp } = this.props 79 | return ( 80 |
81 |
82 |
83 | Share Your Referral Link to Earn More Rewards! 84 |
85 |
Your Referral Link
86 |
87 |
{this.referralLink()}
88 | 94 |
95 |
96 | {this.renderStat('Total Referral Reward', reward)} 97 | {this.renderStat('Number of Referees', refereeCount)} 98 | {this.renderStat( 99 | 'Your referral active time', 100 | 104 | )} 105 |
106 |
107 |
Referral Rule
108 |
109 | For every transaction, 3% of the transaction value is reserved for 110 | the referrers. 60 % of the reserved amount is added to the first 111 | level referrer’s bonus pool, 30% is added to the 2nd level 112 | referrer’s bonus pool, and 10% is added to the 3rd level 113 | referrer’s bonus pool. 114 |
115 |
116 | {this.renderColumn('Bonus Rate', '%', 'dark')} 117 | {this.renderColumn('Level 1', '60 %', 'light')} 118 | {this.renderColumn('Level 2', '30 %', 'med')} 119 | {this.renderColumn('Level 3', '10 %', 'dark')} 120 |
121 | 122 |
123 | As a referrer, you will be awarded 50% of your bonus pool if you 124 | have 4 or less referees, 75% of the pool if you have 5 -24 125 | referees, and 100% if you have 25 or more referees. 126 |
127 | 128 |
129 | {this.renderColumn('Referee Amount', '%', 'dark')} 130 | {this.renderColumn('1-4', '50 %', 'dark')} 131 | {this.renderColumn('5-24', '75 %', 'med')} 132 | {this.renderColumn('25+', '100 %', 'light')} 133 |
134 |
135 |
136 |
137 | ) 138 | } 139 | } 140 | 141 | export default ReferralRules 142 | -------------------------------------------------------------------------------- /frontend/src/components/Web3Loader/Web3Loader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Web3Provider, { 3 | IWeb3Context, 4 | Web3Consumer 5 | } from '../../contexts/Web3Context/Web3Context' 6 | 7 | interface IWeb3LoaderProps { 8 | renderWeb3Incapable(params: IWeb3Context): React.ReactNode 9 | renderEnabling(params: IWeb3Context): React.ReactNode 10 | renderEnabled(params: IWeb3Context): React.ReactNode 11 | renderUnabled(params: IWeb3Context): React.ReactNode 12 | } 13 | interface IWeb3LoaderState {} 14 | 15 | export class Web3Loader extends React.PureComponent< 16 | IWeb3LoaderProps, 17 | IWeb3LoaderState 18 | > { 19 | renderAppState = (params: IWeb3Context) => { 20 | if (!params.signer) { 21 | return this.props.renderWeb3Incapable(params) 22 | } else if (params.enabling) { 23 | return this.props.renderEnabling(params) 24 | } else if (params.enabled) { 25 | return this.props.renderEnabled(params) 26 | } 27 | return this.props.renderUnabled(params) 28 | } 29 | 30 | render() { 31 | return ( 32 | 33 | {this.renderAppState} 34 | 35 | ) 36 | } 37 | } 38 | 39 | export default Web3Loader 40 | -------------------------------------------------------------------------------- /frontend/src/config.ts: -------------------------------------------------------------------------------- 1 | import { ContractEnum } from './ContractEnum' 2 | 3 | export default { 4 | [ContractEnum.DoubleOrNothing]: process.env.REACT_APP_DOUBLE_CONTRACT_ADDRESS, 5 | [ContractEnum.TTUsdt]: process.env.REACT_APP_TT_USDT_CONTRACT 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/containers/DoubleGameContainer/DoubleGameContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Contract } from 'ethers' 3 | import { bigNumberify, parseEther } from 'ethers/utils' 4 | import { TransactionReceipt, TransactionResponse } from 'ethers/providers' 5 | import Game from '../../components/Game/Game' 6 | import Header from '../../components/Header/Header' 7 | import { ContractEnum } from '../../ContractEnum' 8 | 9 | interface IDoubleGameContainerProps { 10 | contract: Contract 11 | address: string 12 | changeContract(coin: ContractEnum): any 13 | } 14 | 15 | interface IAccountInfo { 16 | reward: string 17 | referredCount: string 18 | activeTimestamp: number 19 | } 20 | 21 | interface StateWithDebugLogs { 22 | debugMessages: string[] 23 | } 24 | 25 | interface IDoubleGameContainerState extends StateWithDebugLogs{ 26 | referrer?: string 27 | betAmount: number 28 | balance: string 29 | disabled: boolean 30 | flipping: boolean 31 | win: boolean 32 | accountInfo: IAccountInfo 33 | } 34 | 35 | const INITIAL_AMOUNT = 0.5 36 | 37 | export class DoubleGameContainer extends React.PureComponent< 38 | IDoubleGameContainerProps, 39 | IDoubleGameContainerState 40 | > { 41 | intervals: NodeJS.Timeout[] = [] 42 | 43 | constructor(props: IDoubleGameContainerProps) { 44 | super(props) 45 | this.watchBalance() 46 | this.watchReferrals() 47 | const referrerMatch = window.location.search.match( 48 | /referrer=(0x[a-fA-F0-9]{40})/ 49 | ) 50 | const address = referrerMatch ? referrerMatch[1] : '' 51 | this.state = { 52 | referrer: address.toLowerCase(), 53 | betAmount: INITIAL_AMOUNT, 54 | balance: '', 55 | win: true, 56 | disabled: false, 57 | flipping: false, 58 | accountInfo: { 59 | reward: '0', 60 | referredCount: '0', 61 | activeTimestamp: Date.now() 62 | }, 63 | debugMessages: [], 64 | } 65 | } 66 | 67 | componentWillUnmount(): void { 68 | this.intervals.forEach(interval => clearInterval(interval)) 69 | } 70 | 71 | watchBalance = () => { 72 | this.intervals.push( 73 | setInterval(() => { 74 | this.props.contract.provider 75 | .getBalance(this.props.address) 76 | .then(bal => { 77 | this.setState({ balance: bal.toString() }) 78 | }) 79 | }, 500) 80 | ) 81 | } 82 | 83 | watchReferrals = () => { 84 | this.intervals.push( 85 | setInterval(() => { 86 | this.props.contract.accounts(this.props.address).then((info: any) => { 87 | this.setState({ 88 | accountInfo: { 89 | reward: info.reward.toString(), 90 | referredCount: info.referredCount.toString(), 91 | activeTimestamp: 92 | info.lastActiveTimestamp.toString() * 1000 + 24 * 60 * 60 * 1000 93 | } 94 | }) 95 | }) 96 | }, 500) 97 | ) 98 | } 99 | 100 | log = (v: any) => { 101 | this.setState(prevState => ({ 102 | debugMessages: [`${v}`].concat(prevState.debugMessages) 103 | })) 104 | } 105 | 106 | play = (val: number) => { 107 | this.setState({ disabled: true }) 108 | const params: any = [ 109 | { 110 | value: parseEther(val.toString()).toHexString(), 111 | // because there is an if else based on time, the estimate gas will fail and the transaction will fail 112 | // you must set the gas limit 113 | gasPrice: bigNumberify('1000000000').toHexString(), 114 | gasLimit: bigNumberify('2000000').toHexString() 115 | } 116 | ] 117 | const referrer = !!this.state.referrer 118 | if (referrer) { 119 | params.unshift(this.state.referrer) 120 | } 121 | this.props.contract[referrer ? 'bet(address)' : 'bet()'](...params) 122 | .then((trans: TransactionResponse) => { 123 | this.setState({ flipping: true }) 124 | return trans.wait() 125 | }) 126 | .then((receipt: TransactionReceipt) => { 127 | //@ts-ignore 128 | const event = receipt.events.find(evt => evt.event === 'BetSettled') 129 | 130 | this.setState({ 131 | flipping: false, 132 | win: event.args.winnings.toString() !== '0' 133 | }) 134 | }) 135 | .catch((err: Error) => { 136 | console.log(`setState("logs", ${err})`) 137 | this.log(JSON.stringify(err)) 138 | }) 139 | .finally(() => { 140 | this.setState({ disabled: false, flipping: false }) 141 | }) 142 | } 143 | 144 | playGame = () => { 145 | this.play(this.state.betAmount) 146 | } 147 | 148 | double = () => { 149 | const newBet = this.state.betAmount * 2 150 | this.setState({ betAmount: newBet }) 151 | this.play(newBet) 152 | } 153 | 154 | reset = () => { 155 | this.setState({ betAmount: INITIAL_AMOUNT }) 156 | } 157 | 158 | render() { 159 | const { 160 | disabled, 161 | flipping, 162 | win, 163 | balance, 164 | betAmount, 165 | accountInfo 166 | } = this.state 167 | return ( 168 | <> 169 |
175 | 189 |
190 | {this.state.debugMessages.map((message, index) => (
{message}
))} 191 |
192 | 193 | ) 194 | } 195 | } 196 | 197 | export default DoubleGameContainer 198 | -------------------------------------------------------------------------------- /frontend/src/containers/Erc677GameContainer/Erc677GameContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Contract } from 'ethers' 3 | import { BigNumber, bigNumberify, parseUnits } from 'ethers/utils' 4 | import Game from '../../components/Game/Game' 5 | import Header from '../../components/Header/Header' 6 | import { ContractEnum } from '../../ContractEnum' 7 | import { TransactionReceipt, TransactionResponse } from 'ethers/providers' 8 | 9 | interface IErc677GameContainerProps { 10 | contract: Contract 11 | address: string 12 | gameAddress: string 13 | contractName: ContractEnum 14 | changeContract(coin: ContractEnum): any 15 | } 16 | 17 | interface IAccountInfo { 18 | reward: string 19 | referredCount: string 20 | activeTimestamp: number 21 | } 22 | 23 | interface IErc677GameContainerState { 24 | betAmount: number 25 | balance: string 26 | disabled: boolean 27 | flipping: boolean 28 | win: boolean 29 | accountInfo: IAccountInfo 30 | decimals: number 31 | } 32 | 33 | const INITIAL_AMOUNT = 0.5 34 | 35 | export class Erc677GameContainer extends React.PureComponent< 36 | IErc677GameContainerProps, 37 | IErc677GameContainerState 38 | > { 39 | interval?: NodeJS.Timeout 40 | 41 | constructor(props: IErc677GameContainerProps) { 42 | super(props) 43 | this.state = { 44 | betAmount: INITIAL_AMOUNT, 45 | balance: '', 46 | win: true, 47 | disabled: false, 48 | flipping: false, 49 | accountInfo: { 50 | reward: '0', 51 | referredCount: '0', 52 | activeTimestamp: Date.now() 53 | }, 54 | decimals: 6 55 | } 56 | this.watchBalance() 57 | } 58 | 59 | componentWillUnmount(): void { 60 | if (this.interval) { 61 | clearInterval(this.interval) 62 | } 63 | } 64 | 65 | watchBalance = () => { 66 | this.interval = setInterval(() => { 67 | this.props.contract 68 | .balanceOf(this.props.address) 69 | .then((bal: BigNumber) => this.props.contract.decimals() 70 | .then((d: number) => { 71 | this.setState({ balance: bal.toString(), decimals: d }) 72 | } 73 | )) 74 | }, 500) 75 | } 76 | 77 | play = (val: number) => { 78 | this.setState({ disabled: true }) 79 | 80 | this.props.contract.decimals().then((d:number) => { 81 | console.log(d) 82 | this.props.contract 83 | .transferAndCall( 84 | this.props.gameAddress, 85 | parseUnits(val.toString(), d), 86 | '0xfae', 87 | { 88 | gasPrice: bigNumberify('1000000000').toHexString(), 89 | gasLimit: bigNumberify('100000').toHexString() 90 | } 91 | ) 92 | .then((trans: TransactionResponse) => { 93 | this.setState({ flipping: true }) 94 | return trans.wait() 95 | }) 96 | .then((receipt: TransactionReceipt) => { 97 | //@ts-ignore 98 | const didWin = !!receipt.events.find( 99 | //@ts-ignore 100 | evt => 101 | evt.event === 'Transfer' && 102 | evt.args.to.toLowerCase() === this.props.address.toLowerCase() 103 | ) 104 | 105 | this.setState({ 106 | flipping: false, 107 | win: didWin 108 | }) 109 | }) 110 | .finally(() => { 111 | this.setState({ disabled: false, flipping: false }) 112 | }) 113 | }) 114 | } 115 | 116 | playGame = () => { 117 | this.play(this.state.betAmount) 118 | } 119 | 120 | double = () => { 121 | const newBet = this.state.betAmount * 2 122 | this.setState({ betAmount: newBet }) 123 | this.play(newBet) 124 | } 125 | 126 | reset = () => { 127 | this.setState({ betAmount: INITIAL_AMOUNT }) 128 | } 129 | 130 | render() { 131 | const { 132 | disabled, 133 | flipping, 134 | win, 135 | balance, 136 | betAmount, 137 | accountInfo, 138 | decimals 139 | } = this.state 140 | return ( 141 | <> 142 |
148 | 162 | 163 | ) 164 | } 165 | } 166 | 167 | export default Erc677GameContainer 168 | -------------------------------------------------------------------------------- /frontend/src/containers/GameContainer/GameContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Contract } from 'ethers' 3 | import { ContractEnum } from '../../ContractEnum' 4 | import DoubleGameContainer from '../DoubleGameContainer/DoubleGameContainer' 5 | import Erc677GameContainer from '../Erc677GameContainer/Erc677GameContainer' 6 | 7 | interface IGameContainerProps { 8 | contracts: { 9 | [ContractEnum.DoubleOrNothing]: Contract 10 | [ContractEnum.TTUsdt]: Contract 11 | } 12 | address: string 13 | } 14 | 15 | interface IGameContainerState { 16 | currentContract: ContractEnum 17 | } 18 | 19 | export class GameContainer extends React.PureComponent< 20 | IGameContainerProps, 21 | IGameContainerState 22 | > { 23 | state = { 24 | currentContract: ContractEnum.DoubleOrNothing, 25 | } 26 | 27 | changeContract = (contract: ContractEnum) => { 28 | this.setState({ currentContract: contract }) 29 | } 30 | 31 | render() { 32 | const { currentContract } = this.state 33 | const { address, contracts } = this.props 34 | if (currentContract === ContractEnum.DoubleOrNothing) { 35 | return ( 36 | 41 | ) 42 | } else { 43 | return ( 44 | 51 | ) 52 | 53 | } 54 | } 55 | } 56 | 57 | export default GameContainer 58 | -------------------------------------------------------------------------------- /frontend/src/contexts/ContractContext/ContractContext.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Contract, Signer } from 'ethers' 3 | 4 | interface IContractContextProps { 5 | contracts: IContractData[] 6 | } 7 | 8 | interface IContractData { 9 | signer: Signer 10 | checkOnLoad?: boolean 11 | address: string 12 | abi: any[] 13 | } 14 | 15 | interface IContractState { 16 | contract: Contract 17 | loading: boolean 18 | error: boolean 19 | load(): void 20 | } 21 | 22 | interface IContractContextState { 23 | [key: string]: IContractState 24 | } 25 | 26 | export type IContractContext = IContractContextState 27 | 28 | const { Consumer, Provider } = React.createContext({}) 29 | 30 | export class ContractProvider extends React.PureComponent< 31 | IContractContextProps, 32 | IContractContextState 33 | > { 34 | constructor(props: IContractContextProps) { 35 | super(props) 36 | const contractInfo = props.contracts.reduce( 37 | (agg, contractData) => { 38 | agg[contractData.address] = { 39 | contract: new Contract( 40 | contractData.address, 41 | contractData.abi, 42 | contractData.signer 43 | ), 44 | loading: !!contractData.checkOnLoad, 45 | error: false, 46 | load: () => { 47 | this.loadContract(contractData.address) 48 | } 49 | } 50 | return agg 51 | }, 52 | {} as { 53 | [k: string]: IContractState 54 | } 55 | ) 56 | this.state = contractInfo 57 | 58 | props.contracts.forEach(contractData => { 59 | if (contractData.checkOnLoad) { 60 | this.loadContract(contractData.address, true) 61 | } 62 | }) 63 | } 64 | 65 | private loadContract = (address: string, initializing?: boolean) => { 66 | const contractData = this.state[address] 67 | if (!contractData) { 68 | return 69 | } 70 | if (!initializing) { 71 | this.setState({ 72 | [address]: { ...contractData, loading: true, error: false } 73 | }) 74 | } 75 | contractData.contract 76 | .deployed() 77 | .then(() => { 78 | this.setState({ 79 | [address]: { ...contractData, loading: false } 80 | }) 81 | }) 82 | .catch(() => { 83 | this.setState({ 84 | [address]: { ...contractData, loading: false, error: true } 85 | }) 86 | }) 87 | } 88 | 89 | render() { 90 | return {this.props.children} 91 | } 92 | } 93 | 94 | export default ContractProvider 95 | 96 | export const ContractConsumer = Consumer 97 | -------------------------------------------------------------------------------- /frontend/src/contexts/Web3Context/Web3Context.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Signer } from 'ethers' 3 | import { Web3Provider as EthersProvider } from 'ethers/providers' 4 | 5 | interface IWeb3ContextProps { 6 | enableOnLoad?: boolean 7 | } 8 | 9 | interface IWeb3ContextState { 10 | signer?: Signer 11 | enabled: boolean 12 | enabling: boolean 13 | address: string 14 | } 15 | 16 | export interface IWeb3Context { 17 | enable(): void 18 | signer?: Signer 19 | enabled: boolean 20 | enabling: boolean 21 | address: string 22 | } 23 | 24 | const { Consumer, Provider } = React.createContext({ 25 | enable: () => {}, 26 | address: '', 27 | signer: undefined, 28 | enabling: false, 29 | enabled: false 30 | }) 31 | 32 | export class Web3Provider extends React.PureComponent< 33 | IWeb3ContextProps, 34 | IWeb3ContextState 35 | > { 36 | constructor(props: IWeb3ContextProps) { 37 | super(props) 38 | const web3Capable = !!window.ethereum 39 | this.state = { 40 | address: '', 41 | signer: web3Capable && new EthersProvider(window.ethereum).getSigner(), 42 | enabled: false, 43 | enabling: web3Capable && !!props.enableOnLoad 44 | } 45 | } 46 | 47 | componentDidMount(): void { 48 | if (this.props.enableOnLoad) { 49 | this.enable() 50 | } 51 | } 52 | 53 | enable = () => { 54 | if (this.state.signer) { 55 | this.setState({ enabling: true }) 56 | this.state.signer 57 | //@ts-ignore 58 | .provider!._web3Provider.enable() 59 | .then(([address]: [string]) => { 60 | this.setState({ enabling: false, enabled: true, address }) 61 | }) 62 | .catch(() => { 63 | this.setState({ 64 | enabling: false, 65 | enabled: false 66 | }) 67 | }) 68 | } 69 | } 70 | 71 | render() { 72 | return ( 73 | 74 | {this.props.children} 75 | 76 | ) 77 | } 78 | } 79 | 80 | export default Web3Provider 81 | 82 | export const Web3Consumer = Consumer 83 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './index.css' 4 | import App from './components/App/App' 5 | import * as serviceWorker from './serviceWorker' 6 | 7 | ReactDOM.render(, document.getElementById('root')) 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: https://bit.ly/CRA-PWA 12 | serviceWorker.unregister() 13 | -------------------------------------------------------------------------------- /frontend/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/src/serviceWorker.ts: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ) 22 | 23 | type Config = { 24 | onSuccess?: (registration: ServiceWorkerRegistration) => void 25 | onUpdate?: (registration: ServiceWorkerRegistration) => void 26 | } 27 | 28 | export function register(config?: Config) { 29 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 30 | // The URL constructor is available in all browsers that support SW. 31 | const publicUrl = new URL( 32 | (process as { env: { [key: string]: string } }).env.PUBLIC_URL, 33 | window.location.href 34 | ) 35 | if (publicUrl.origin !== window.location.origin) { 36 | // Our service worker won't work if PUBLIC_URL is on a different origin 37 | // from what our page is served on. This might happen if a CDN is used to 38 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 39 | return 40 | } 41 | 42 | window.addEventListener('load', () => { 43 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` 44 | 45 | if (isLocalhost) { 46 | // This is running on localhost. Let's check if a service worker still exists or not. 47 | checkValidServiceWorker(swUrl, config) 48 | 49 | // Add some additional logging to localhost, pointing developers to the 50 | // service worker/PWA documentation. 51 | navigator.serviceWorker.ready.then(() => { 52 | console.log( 53 | 'This web app is being served cache-first by a service ' + 54 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 55 | ) 56 | }) 57 | } else { 58 | // Is not localhost. Just register service worker 59 | registerValidSW(swUrl, config) 60 | } 61 | }) 62 | } 63 | } 64 | 65 | function registerValidSW(swUrl: string, config?: Config) { 66 | navigator.serviceWorker 67 | .register(swUrl) 68 | .then(registration => { 69 | registration.onupdatefound = () => { 70 | const installingWorker = registration.installing 71 | if (installingWorker == null) { 72 | return 73 | } 74 | installingWorker.onstatechange = () => { 75 | if (installingWorker.state === 'installed') { 76 | if (navigator.serviceWorker.controller) { 77 | // At this point, the updated precached content has been fetched, 78 | // but the previous service worker will still serve the older 79 | // content until all client tabs are closed. 80 | console.log( 81 | 'New content is available and will be used when all ' + 82 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 83 | ) 84 | 85 | // Execute callback 86 | if (config && config.onUpdate) { 87 | config.onUpdate(registration) 88 | } 89 | } else { 90 | // At this point, everything has been precached. 91 | // It's the perfect time to display a 92 | // "Content is cached for offline use." message. 93 | console.log('Content is cached for offline use.') 94 | 95 | // Execute callback 96 | if (config && config.onSuccess) { 97 | config.onSuccess(registration) 98 | } 99 | } 100 | } 101 | } 102 | } 103 | }) 104 | .catch(error => { 105 | console.error('Error during service worker registration:', error) 106 | }) 107 | } 108 | 109 | function checkValidServiceWorker(swUrl: string, config?: Config) { 110 | // Check if the service worker can be found. If it can't reload the page. 111 | fetch(swUrl) 112 | .then(response => { 113 | // Ensure service worker exists, and that we really are getting a JS file. 114 | const contentType = response.headers.get('content-type') 115 | if ( 116 | response.status === 404 || 117 | (contentType != null && contentType.indexOf('javascript') === -1) 118 | ) { 119 | // No service worker found. Probably a different app. Reload the page. 120 | navigator.serviceWorker.ready.then(registration => { 121 | registration.unregister().then(() => { 122 | window.location.reload() 123 | }) 124 | }) 125 | } else { 126 | // Service worker found. Proceed as normal. 127 | registerValidSW(swUrl, config) 128 | } 129 | }) 130 | .catch(() => { 131 | console.log( 132 | 'No internet connection found. App is running in offline mode.' 133 | ) 134 | }) 135 | } 136 | 137 | export function unregister() { 138 | if ('serviceWorker' in navigator) { 139 | navigator.serviceWorker.ready.then(registration => { 140 | registration.unregister() 141 | }) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "noEmit": true, 20 | "jsx": "preserve" 21 | }, 22 | "include": [ 23 | "src", 24 | "typings" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /frontend/typings/abi.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.json' { 2 | export const abi: Abi 3 | } 4 | 5 | declare type Abi = Array<{ 6 | constant: any 7 | inputs: any 8 | name: any 9 | outputs: any 10 | payable: any 11 | stateMutability: any 12 | type: any 13 | }> 14 | -------------------------------------------------------------------------------- /frontend/typings/env.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NodeJS { 2 | export interface ProcessEnv { 3 | REACT_APP_RPC_URL: string 4 | REACT_APP_DOUBLE_CONTRACT_ADDRESS: string 5 | REACT_APP_TT_USDT_CONTRACT: string 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/typings/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' 2 | declare module '*.png' 3 | declare module '*.jpg' 4 | declare module '*.gif' 5 | -------------------------------------------------------------------------------- /frontend/typings/sounds.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.wav' 2 | declare module '*.ogg' 3 | declare module '*.mp3' 4 | -------------------------------------------------------------------------------- /frontend/typings/web3.d.ts: -------------------------------------------------------------------------------- 1 | interface IWeb3Provider { 2 | sendAsync(payload: any, callback: (e: Error, val: any) => void): any 3 | enable(): Promise 4 | } 5 | 6 | interface Window { 7 | ethereum: IWeb3Provider 8 | } 9 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | ./frontend/build/index.html -------------------------------------------------------------------------------- /smart-contracts/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | conda-env 3 | .private-keys 4 | .mnemonic 5 | local.jsonc 6 | -------------------------------------------------------------------------------- /smart-contracts/GNUmakefile: -------------------------------------------------------------------------------- 1 | CONDA := $(HOME)/miniconda3/bin/conda 2 | 3 | TOP_DIR := $(patsubst %/,%,$(dir $(realpath $(lastword $(MAKEFILE_LIST))))) 4 | CONDA_ENV_DIR := $(TOP_DIR)/conda-env 5 | 6 | # This can be used to customized local builds. 7 | -include $(TOP_DIR)/Local.mk 8 | 9 | PATH := $(CONDA_ENV_DIR)/bin:$(TOP_DIR)/node_modules/.bin:$(PATH) 10 | export PATH 11 | 12 | PREFERRED_INTERACTIVE_SHELL ?= bash 13 | PS1_NAME ?= 'double-or-nothing' 14 | MAKE_SHELL_PS1 ?= '$(PS1_NAME) $$ ' 15 | .PHONY: shell 16 | ifeq ($(PREFERRED_INTERACTIVE_SHELL),bash) 17 | shell: 18 | @INIT_FILE=$(shell mktemp); \ 19 | printf '[ -e $$HOME/.bashrc ] && source $$HOME/.bashrc\n' > $$INIT_FILE; \ 20 | printf '[ -e Local.env ] && source Local.env\n' >> $$INIT_FILE; \ 21 | printf 'PS1='"$(MAKE_SHELL_PS1) "'\n' >> $$INIT_FILE; \ 22 | $(PREFERRED_INTERACTIVE_SHELL) --init-file $$INIT_FILE || true 23 | else ifeq ($(PREFERRED_INTERACTIVE_SHELL),fish) 24 | shell: 25 | @INIT_FILE=$(shell mktemp); \ 26 | printf 'if functions -q fish_right_prompt\n' > $$INIT_FILE; \ 27 | printf ' functions -c fish_right_prompt __fish_right_prompt_original\n' >> $$INIT_FILE; \ 28 | printf ' functions -e fish_right_prompt\n' >> $$INIT_FILE; \ 29 | printf 'else\n' >> $$INIT_FILE; \ 30 | printf ' function __fish_right_prompt_original\n' >> $$INIT_FILE; \ 31 | printf ' end\n' >> $$INIT_FILE; \ 32 | printf 'end\n' >> $$INIT_FILE; \ 33 | printf 'function fish_right_prompt\n' >> $$INIT_FILE; \ 34 | printf ' echo -n "($(PS1_NAME)) "\n' >> $$INIT_FILE; \ 35 | printf ' __fish_right_prompt_original\n' >> $$INIT_FILE; \ 36 | printf 'end\n' >> $$INIT_FILE; \ 37 | $(PREFERRED_INTERACTIVE_SHELL) --init-command="source $$INIT_FILE" || true 38 | else 39 | shell: 40 | @$(PREFERRED_INTERACTIVE_SHELL) || true 41 | endif 42 | 43 | .PHONY: conda-env 44 | conda-env: 45 | if [ ! -d $(CONDA_ENV_DIR) ]; then \ 46 | $(CONDA) env create -f environment.yml -p $(CONDA_ENV_DIR); \ 47 | else \ 48 | $(CONDA) env update -f environment.yml -p $(CONDA_ENV_DIR); \ 49 | fi 50 | yarn install 51 | -------------------------------------------------------------------------------- /smart-contracts/build/contracts/ThunderRandomLibraryInterface.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "ThunderRandomLibraryInterface", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [], 7 | "name": "rand", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "uint256" 12 | } 13 | ], 14 | "payable": false, 15 | "stateMutability": "nonpayable", 16 | "type": "function" 17 | } 18 | ], 19 | "metadata": "", 20 | "bytecode": "0x", 21 | "deployedBytecode": "0x", 22 | "sourceMap": "", 23 | "deployedSourceMap": "", 24 | "source": "contract ThunderRandomLibraryInterface {\n function rand() public returns (uint256);\n}\n", 25 | "sourcePath": "/home/scottt/git/tt/DoubleOrNothing/smart-contracts/contracts/ThunderRandomLibraryInterface.sol", 26 | "ast": { 27 | "absolutePath": "/home/scottt/git/tt/DoubleOrNothing/smart-contracts/contracts/ThunderRandomLibraryInterface.sol", 28 | "exportedSymbols": { 29 | "ThunderRandomLibraryInterface": [ 30 | 666 31 | ] 32 | }, 33 | "id": 667, 34 | "nodeType": "SourceUnit", 35 | "nodes": [ 36 | { 37 | "baseContracts": [], 38 | "contractDependencies": [], 39 | "contractKind": "contract", 40 | "documentation": null, 41 | "fullyImplemented": false, 42 | "id": 666, 43 | "linearizedBaseContracts": [ 44 | 666 45 | ], 46 | "name": "ThunderRandomLibraryInterface", 47 | "nodeType": "ContractDefinition", 48 | "nodes": [ 49 | { 50 | "body": null, 51 | "documentation": null, 52 | "id": 665, 53 | "implemented": false, 54 | "kind": "function", 55 | "modifiers": [], 56 | "name": "rand", 57 | "nodeType": "FunctionDefinition", 58 | "parameters": { 59 | "id": 661, 60 | "nodeType": "ParameterList", 61 | "parameters": [], 62 | "src": "58:2:3" 63 | }, 64 | "returnParameters": { 65 | "id": 664, 66 | "nodeType": "ParameterList", 67 | "parameters": [ 68 | { 69 | "constant": false, 70 | "id": 663, 71 | "name": "", 72 | "nodeType": "VariableDeclaration", 73 | "scope": 665, 74 | "src": "77:7:3", 75 | "stateVariable": false, 76 | "storageLocation": "default", 77 | "typeDescriptions": { 78 | "typeIdentifier": "t_uint256", 79 | "typeString": "uint256" 80 | }, 81 | "typeName": { 82 | "id": 662, 83 | "name": "uint256", 84 | "nodeType": "ElementaryTypeName", 85 | "src": "77:7:3", 86 | "typeDescriptions": { 87 | "typeIdentifier": "t_uint256", 88 | "typeString": "uint256" 89 | } 90 | }, 91 | "value": null, 92 | "visibility": "internal" 93 | } 94 | ], 95 | "src": "76:9:3" 96 | }, 97 | "scope": 666, 98 | "src": "45:41:3", 99 | "stateMutability": "nonpayable", 100 | "superFunction": null, 101 | "visibility": "public" 102 | } 103 | ], 104 | "scope": 667, 105 | "src": "0:88:3" 106 | } 107 | ], 108 | "src": "0:89:3" 109 | }, 110 | "legacyAST": { 111 | "absolutePath": "/home/scottt/git/tt/DoubleOrNothing/smart-contracts/contracts/ThunderRandomLibraryInterface.sol", 112 | "exportedSymbols": { 113 | "ThunderRandomLibraryInterface": [ 114 | 666 115 | ] 116 | }, 117 | "id": 667, 118 | "nodeType": "SourceUnit", 119 | "nodes": [ 120 | { 121 | "baseContracts": [], 122 | "contractDependencies": [], 123 | "contractKind": "contract", 124 | "documentation": null, 125 | "fullyImplemented": false, 126 | "id": 666, 127 | "linearizedBaseContracts": [ 128 | 666 129 | ], 130 | "name": "ThunderRandomLibraryInterface", 131 | "nodeType": "ContractDefinition", 132 | "nodes": [ 133 | { 134 | "body": null, 135 | "documentation": null, 136 | "id": 665, 137 | "implemented": false, 138 | "kind": "function", 139 | "modifiers": [], 140 | "name": "rand", 141 | "nodeType": "FunctionDefinition", 142 | "parameters": { 143 | "id": 661, 144 | "nodeType": "ParameterList", 145 | "parameters": [], 146 | "src": "58:2:3" 147 | }, 148 | "returnParameters": { 149 | "id": 664, 150 | "nodeType": "ParameterList", 151 | "parameters": [ 152 | { 153 | "constant": false, 154 | "id": 663, 155 | "name": "", 156 | "nodeType": "VariableDeclaration", 157 | "scope": 665, 158 | "src": "77:7:3", 159 | "stateVariable": false, 160 | "storageLocation": "default", 161 | "typeDescriptions": { 162 | "typeIdentifier": "t_uint256", 163 | "typeString": "uint256" 164 | }, 165 | "typeName": { 166 | "id": 662, 167 | "name": "uint256", 168 | "nodeType": "ElementaryTypeName", 169 | "src": "77:7:3", 170 | "typeDescriptions": { 171 | "typeIdentifier": "t_uint256", 172 | "typeString": "uint256" 173 | } 174 | }, 175 | "value": null, 176 | "visibility": "internal" 177 | } 178 | ], 179 | "src": "76:9:3" 180 | }, 181 | "scope": 666, 182 | "src": "45:41:3", 183 | "stateMutability": "nonpayable", 184 | "superFunction": null, 185 | "visibility": "public" 186 | } 187 | ], 188 | "scope": 667, 189 | "src": "0:88:3" 190 | } 191 | ], 192 | "src": "0:89:3" 193 | }, 194 | "compiler": { 195 | "name": "solc", 196 | "version": "0.5.0+commit.1d4f565a.Emscripten.clang" 197 | }, 198 | "networks": {}, 199 | "schemaVersion": "3.1.0", 200 | "updatedAt": "2020-05-06T12:23:04.663Z", 201 | "devdoc": { 202 | "methods": {} 203 | }, 204 | "userdoc": { 205 | "methods": {} 206 | } 207 | } -------------------------------------------------------------------------------- /smart-contracts/contracts/DoubleOrNothing.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.0; 2 | 3 | import '@thundercore/referral-solidity/contracts/Referral.sol'; 4 | import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; 5 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 6 | import "./ERC677Interface.sol"; 7 | import "./ThunderRandomLibraryInterface.sol"; 8 | 9 | contract DoubleOrNothing is Ownable, Referral, ERC677Receiver { 10 | 11 | TokenData[] internal tokens; 12 | ThunderRandomLibraryInterface internal RNGLibrary; 13 | struct TokenData { 14 | IBurnableMintableERC677Token instance; 15 | uint256 lastBalance; // Don't trust this; see onTokenTransfer 16 | } 17 | 18 | event BetSettled(address player, uint256 winnings); 19 | 20 | constructor( 21 | uint _decimals, 22 | uint _referralBonus, 23 | uint _secondsUntilInactive, 24 | bool _onlyRewardActiveReferrers, 25 | uint256[] memory _levelRate, 26 | uint256[] memory _refereeBonusRateMap, 27 | address[] memory _tokenAddresses, 28 | address _randomNumberContractAddress 29 | ) Referral( 30 | _decimals, 31 | _referralBonus, 32 | _secondsUntilInactive, 33 | _onlyRewardActiveReferrers, 34 | _levelRate, 35 | _refereeBonusRateMap 36 | ) public { 37 | for (uint i = 0; i < _tokenAddresses.length; i++) { 38 | tokens.push(generateTokenData(_tokenAddresses[i])); 39 | } 40 | RNGLibrary = ThunderRandomLibraryInterface(_randomNumberContractAddress); 41 | } 42 | 43 | function generateTokenData(address _tokenAddress) internal view returns (TokenData memory) { 44 | IBurnableMintableERC677Token token = IBurnableMintableERC677Token(_tokenAddress); 45 | return TokenData(token, token.balanceOf(address(this))); 46 | } 47 | 48 | // Return a TokenData value passed by reference so we can modify it directly. 49 | function getToken(address _tokenAddress) internal view returns (TokenData storage) { 50 | for (uint i = 0; i < tokens.length; i++) { 51 | if (address(tokens[i].instance) == _tokenAddress) { 52 | return tokens[i]; 53 | } 54 | } 55 | revert("Token not found."); 56 | } 57 | 58 | function addToken(address _tokenAddress) external onlyOwner { 59 | for (uint i = 0; i < tokens.length; i++) { 60 | if (address(tokens[i].instance) == _tokenAddress) { 61 | revert('A token with the provided address already exists.'); 62 | } 63 | } 64 | tokens.push(generateTokenData(_tokenAddress)); 65 | } 66 | 67 | function deleteToken(address _tokenAddress) external onlyOwner { 68 | for (uint i = 0; i < tokens.length; i++) { 69 | if (address(tokens[i].instance) == _tokenAddress) { 70 | uint256 lastIdx = tokens.length - 1; 71 | tokens[i] = tokens[lastIdx]; 72 | delete lastIdx; 73 | break; 74 | } 75 | } 76 | revert('Token targeted for deletion not found.'); 77 | } 78 | 79 | function bet(address payable _referrer) payable external { 80 | if(!hasReferrer(msg.sender)) { 81 | addReferrer(_referrer); 82 | } 83 | bet(); 84 | } 85 | 86 | // value transfer tx based bet. 87 | function bet() payable public { 88 | // msg.value is added to the balance to begin with so you need to double it 89 | require(msg.value * 2 <= address(this).balance, 'Balance too low!'); 90 | 91 | // prevent "revert txn unless I won" attacks, see 92 | // https://developers.thundercore.com/docs/random-number-generator/ 93 | require(msg.sender == tx.origin); 94 | 95 | uint256 winnings = 0; 96 | 97 | if(RNGLibrary.rand() % 2 == 0) { 98 | // 3% is deducted to cover the referral bonus 99 | winnings = msg.value * 197/100; 100 | address(msg.sender).transfer(winnings); 101 | } 102 | 103 | payReferral(msg.value); 104 | emit BetSettled(msg.sender, winnings); 105 | } 106 | 107 | // This function handles ERC677 token bets. 108 | // This function does _not_ pay out referral bonuses. 109 | function betTokens(IBurnableMintableERC677Token _token, uint256 _amount) internal { 110 | // The smart contract needs to be able to pay double the value sent. 111 | require(_amount * 2 <= _token.balanceOf(address(this)), 'Contract balance too low!'); 112 | 113 | uint256 winnings = 0; 114 | 115 | if(RNGLibrary.rand() % 2 == 0) { 116 | winnings = _amount * 2; 117 | 118 | // This transaction can fail due to not enough gas being sent 119 | // with the call, so we specify the amount of gas to forward. 120 | _token.transfer.gas(50000)(tx.origin, winnings); 121 | } 122 | 123 | emit BetSettled(tx.origin, winnings); 124 | } 125 | 126 | // With no data sent, the contract token balance is simply updated. 127 | // Any data provided indicates that a user wants to make a bet. 128 | function onTokenTransfer(address /*_from*/, uint _value, bytes calldata _data) external returns(bool) { 129 | TokenData storage token = getToken(msg.sender); 130 | uint256 updatedBalance = token.instance.balanceOf(address(this)); 131 | 132 | if (_data.length == 0) { 133 | token.lastBalance = updatedBalance; 134 | } else { 135 | // It doesn't matter if the current stored `lastTokenBalance` is correct. 136 | // The balance increase needs to be _at least_ as much as the 137 | // stated _value. 138 | require(updatedBalance - token.lastBalance >= _value, "onTokenTransfer was called but no balance increase was detected."); 139 | token.lastBalance = updatedBalance; 140 | betTokens(token.instance, _value); 141 | } 142 | return true; 143 | } 144 | 145 | function withdraw(uint256 _amount) external onlyOwner { 146 | require(_amount <= address(this).balance, 'Balance too low!'); 147 | address payable owner = address(uint160(owner())); 148 | owner.transfer(_amount); 149 | } 150 | 151 | function withdrawTokens(address _tokenAddress, uint256 _amount) external onlyOwner { 152 | TokenData storage token = getToken(_tokenAddress); 153 | uint256 currentTokenBalance = token.instance.balanceOf(address(this)); 154 | 155 | require(_amount <= currentTokenBalance, 'Token balance too low!'); 156 | 157 | token.instance.transfer(owner(), _amount); 158 | token.lastBalance = currentTokenBalance - _amount; 159 | } 160 | 161 | // This fallback function eats all funds and gas sent to it. 162 | // The owner can withdraw from the contract balance via `withdraw` above. 163 | function() external payable {} 164 | } 165 | -------------------------------------------------------------------------------- /smart-contracts/contracts/ERC677Interface.sol: -------------------------------------------------------------------------------- 1 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 2 | 3 | contract ERC677 is ERC20 { 4 | event Transfer(address indexed from, address indexed to, uint value, bytes data); 5 | function transferAndCall(address, uint, bytes calldata) external returns (bool); 6 | } 7 | 8 | contract IBurnableMintableERC677Token is ERC677 { 9 | function mint(address, uint256) public returns (bool); 10 | function burn(uint256 _value) public; 11 | function claimTokens(address _token, address _to) public; 12 | } 13 | 14 | contract ERC677Receiver { 15 | function onTokenTransfer(address _from, uint _value, bytes calldata _data) external returns(bool); 16 | } 17 | -------------------------------------------------------------------------------- /smart-contracts/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /smart-contracts/contracts/ThunderRandomLibraryInterface.sol: -------------------------------------------------------------------------------- 1 | contract ThunderRandomLibraryInterface { 2 | function rand() public returns (uint256); 3 | } 4 | -------------------------------------------------------------------------------- /smart-contracts/environment.yml: -------------------------------------------------------------------------------- 1 | name: double-or-nothing 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - nodejs=10.16.3 # hub-analytics-frontend 6 | - yarn=1.22.0 7 | -------------------------------------------------------------------------------- /smart-contracts/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require('./Migrations.sol') 2 | var Double = artifacts.require('./DoubleOrNothing.sol') 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(Migrations) 6 | deployer.deploy( 7 | Double, 8 | 1000, 9 | 30, 10 | 86400, 11 | true, 12 | [600, 200, 100], 13 | [1, 500, 5, 750, 25, 1000], 14 | // [ 15 | // "0x42532085e51e5618575005f626589ff57d280d68", // tt-usdt testnet token address 16 | // "0xd60db41a718a73da844a4c454c8bd6e07173d722" // tt-dai testnet token address 17 | // ] 18 | [ 19 | '0x4f3C8E20942461e2c3Bdd8311AC57B0c222f2b82', // tt-usdt mainnet token address 20 | '0x2b31e3b88847f03c1335E99A0d1274A2c72059DE' // tt-dai mainnet token address 21 | ], 22 | '0xfe20903772D6df6DE5a42E00D011f1893bB0B772' 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /smart-contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DoubleOrNothingContract", 3 | "version": "1.0.0", 4 | "description": "Smart Contract for double or nothing", 5 | "license": "MIT", 6 | "scripts": { 7 | "migrate": "truffle migrate" 8 | }, 9 | "dependencies": { 10 | "@thundercore/referral-solidity": "^1.0.1", 11 | "openzeppelin-solidity": "^2.3.0", 12 | "truffle": "^5.1.22", 13 | "@truffle/hdwallet-provider": "^1.0.34" 14 | }, 15 | "devDependencies": { 16 | "truffle-flattener": "^1.4.2", 17 | "truffle-plugin-save-per-network-deployment-record": "https://github.com/thundercore/truffle-plugin-save-per-network-deployment-record.git" 18 | }, 19 | "engines": { 20 | "node": ">=8.0.0 <11.0.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /smart-contracts/truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | */ 12 | 13 | const HDWalletProvider = require("@truffle/hdwallet-provider"); 14 | const fs = require("fs"); 15 | 16 | const TESTNET_PROVIDER = "https://testnet-rpc.thundercore.com"; 17 | const MAINNET_PROVIDER = "https://mainnet-rpc-partner.thundercore.com"; 18 | 19 | let privateKeys = null; 20 | let mnemonic = null; 21 | try { 22 | privateKeys = fs 23 | .readFileSync(".private-keys", { encoding: "ascii" }) 24 | .split("\n") 25 | .filter(x => x.length > 0); 26 | } catch (err) { 27 | if (err.code !== "ENOENT") { 28 | throw err; 29 | } 30 | } 31 | 32 | if (!privateKeys) { 33 | try { 34 | mnemonic = fs.readFileSync(".mnemonic", { encoding: "ascii" }).trim(); 35 | } catch (err) { 36 | if (err.code !== "ENOENT") { 37 | throw err; 38 | } 39 | } 40 | } 41 | 42 | module.exports = { 43 | networks: { 44 | // For `truffle develop` 45 | development: { 46 | host: "127.0.0.1", // Localhost (default: none) 47 | port: 9545, // Standard Ethereum port (default: none) 48 | network_id: "*" // Any network (default: none) 49 | }, 50 | "thunder-testnet": { 51 | provider: () => { 52 | if (privateKeys === null && mnemonic === null) { 53 | throw new Error("Please create a .private-keys or .mnemonic file"); 54 | } 55 | return privateKeys 56 | ? new HDWalletProvider( 57 | privateKeys, 58 | TESTNET_PROVIDER, 59 | 0, // <- change address_index if you want to default to an address other than the first one 60 | privateKeys.length 61 | ) 62 | : new HDWalletProvider( 63 | mnemonic, 64 | TESTNET_PROVIDER, 65 | 0 // <- change address_index if you want to use an address other than the first one 66 | ); 67 | }, 68 | network_id: "18" 69 | }, 70 | "thunder-mainnet": { 71 | provider: () => { 72 | if (privateKeys === null && mnemonic === null) { 73 | throw new Error("Please create a .private-keys or .mnemonic file"); 74 | } 75 | 76 | return privateKeys 77 | ? new HDWalletProvider( 78 | privateKeys, 79 | MAINNET_PROVIDER, 80 | 0, // <- change address_index if you want to use non-first address 81 | privateKeys.length 82 | ) 83 | : new HDWalletProvider( 84 | mnemonic, 85 | MAINNET_PROVIDER, 86 | 0 // <- change address_index if you want to use non-first address 87 | ); 88 | }, 89 | network_id: "108" 90 | } 91 | }, 92 | 93 | // Set default mocha options here, use special reporters etc. 94 | mocha: { 95 | // timeout: 100000 96 | }, 97 | 98 | // Configure your compilers 99 | compilers: { 100 | solc: { 101 | version: "0.5.0", // Fetch exact version from solc-bin (default: truffle's version) 102 | settings: { 103 | // see the solidity docs for advice about optimization and evmversion 104 | optimizer: { 105 | enabled: true, 106 | runs: 200 107 | }, 108 | evmVersion: "byzantium" // ThunderCore supports the "byzantium" hardfork as of PaLa release 2 109 | } 110 | } 111 | } 112 | }; 113 | --------------------------------------------------------------------------------