├── 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 You need to enable JavaScript to run this app.
--------------------------------------------------------------------------------
/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,iVBORw0KGgoAAAANSUhEUgAAATAAAAB8CAMAAADZyBxiAAAC/VBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaXwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLdQAxGU0AAAAAAAAAAAD59u2rZQC0igCASwAoGAAfHx8cDi7+xAH+xADrtQLw7+rEcgDcqgDExMTFxcW4uLi8vLy9uq6TVwCZXwCObQCHh4dHNwBOTk5IJXL/xAAyGU//nQD///8vLy//7bP/3Uc1G1U6HVxGJG84HFj/1jT/shcsF0eHXS/IcQAiETdpTYtYOH5tUY7/xwvRydyun8H/7bH9/f376rH/66pNKnX/3Wn/0jzLwddcPYL/zST/yhj8+/z49/qjmXk/Pjn/zzL/xQXu6/LAtM7/7K7/6qX/6Z17Ypn/5ZH/4X5VNXxDImpAIGb/00FEQzwfDzH/yRH6+fuVga3o2aX/6aJ2W5VxVpL/33VJJnOYkHI9H2F6dF87Ojc3NzTGutOSfatkR4hiRIZSMHmFfmZwa1kzGlL/1kwkEjv/0TczMzL/yx7/yRXYfQDt6vHp5O7k3+qzpMSrm76ikLjy4qvXyZr/5I6vpIBaO4BKKHT/2Vv/1lFcWUxVUkdkOi//zivMdADy8PXh2+je2Obc1eTVzd+ah7KIcaPez57/55nUxpj/5pP/5Im8sIn/44amnHv/3W+Lg2n/2mD/2FZpZVRjX1BZVkrw7fO7rsq3qcifjLX25a3t3ajj1KJ/Zpx5YJjPwpXFuY7BtYz/22Z1b1sxGE3/1EYpFEFJR0A1NTP18/fZ0eLOxNnw4KqMd6eFbqGCap7LvZK+sopQL3iQiG1+d2FPTUP/20Kol7yKc6RpTItmSYm4rYZfQISpn32elXZ8VDLuvDHYkBT/99z/8MLJvJHzxTf90CrpsSqBWimlm3qSim1IOlFRQU0sHTxcNDFlOy8dDipuTCbjmRWQVRDRgwzOfgkF7OygAAAAQnRSTlNNAIKPP4ugm42kogV3eD3RiYULakM4clNKl5Mrf1pOGHsyIBMD+euDYCX6493Kpph//v729fDs4N/a2NbW0su9uKcJpCePAAAKmElEQVR42uzUyUrDUBSA4dOkbTqGNG3atE2NbaXWUqgTjuCUEMRaUFy6deVOUNC1+yL4ED6MiA+iG0FduPLeTIorI9zEC/d7gsPPOQdiPrkuloAstaTMyDGq+cFkBULSzMYo5gXTK8WcxoVDawBV7Lv4EaxV5sJEWbHvdwFOL40LVwWoo7a/guk5DpuWEinCEhJny08AdVTdCyY3OKyQ4kOQKnBYF+ijym4wsWz3qlUFIUnQ6vLK2ubALTYJFIpP2cH0itNLEDaW5g1y7i1kcZuXaP37AC07mNLF/ytVFfoGWc8W0hvw9ooVgUIlHCwLRTS/VBO2DMKunixk3VmxPNCojYLpUMYLVsv0DdJucbEen+AQDWhUR8HqkEMfjBfSCwZxJ/gq3y+PsAeTGp1ZcMVRsCYOJqFgcwZ5p2fH1it1wcwOuFQUTHGCJdNGKO523+gLZoIHBRNxsASfzBgh+aA5WBZi8bCDvfwl2Nix5xq5huSNow9284gNrz0XvnPfvmcnaqPIgx0emFj0KVgwjHwwkQVjwViw32PBAmLBAmLBAmLBAmLBAmLBAmLBAmLBAvrHwT7Zr7OeJqIwjOPf7Uxy+nwAa2vporYuUFoUkpJitUhkb2NaiEVtQS3EoCIUoYogahBUMAY3FLeoGL3yxk/gO2cWS50aYyZFw/yvynD3y3u2gL+29qI/aoH9QdHIjWshKHkGV3bXWWC/qS5SRFken98Cq5BjNgyRO/ft4fLrhzEoHY5YYEZFBNfC55nhDptS+63EN8gVAxZYef1FUIsz7bbNrbbFAIRmLbDN1YYB5OZsBqUTWQCHoxZYSREA7ra0zbjmaQCFqAWml3IBE8O2yiWzQEO/BaZWGwKWO0pHam4umZx/UvJl/gWJBSwwkd8DrOs6T969jkHknvg+oouN3AMKDguMqisAk+3abH19gdImH2li70ms1QKjZoHFg6rKCYWr0Opb8RXDkFtutikNu4HHFpjU7wHU68TBaVDF3drKC9w8CiCbVMXeAmGHBdYITKsX+xyAqT6ptDxxurVl+QC4ue3B/MDCquDoII9QXiorMAW4TqiLEgj1b3cwH9CmcCwTx0WDM6ERcKun5WfgwjYHqwsDyoA9Aly1kmQslksrtzHg6DYHSwEPlAUZA05KhjmO6lOYA1JmgfU41eo/rG2wP+lfAGsFEoKiDbhW8SUAZJWHQALwmQW2g/+spvMT+8ua9lK9VQPzwK3cwWKAwQbWl9ot16CxrgIN4kvK7zATjMhesr9rD6d2VQssAEwKiVuGA3YDehM20SK0QhFTwfj+T/8DWAoYEhBDQN7oyqEXU8AOQK/BFLC1pVdHnFxu7H8AmwVmtMmJ/rogAXw5IPo6ol5u314XrQMFU8DsjLrLqZbzTO189zlWmren21u2cW14twasVX0WdRjfFwbF8WhQOgfkzQPby+V2MDn73cstnI86jzGlN2czNfTP4J0epjb+/BTn+wZ2vSG4YLBFrOdgcGdVwEhkVb1gNRofjwvNRmAJAnaYB3Z8H6cE0X3CENWcFkMUD+rHwgcF8A5Xy8RZE9eLVwXsMCAOyRPASoWH5pCB18EsEJFMAtN/yutwqYbrnaW/z5Gf3hFGPeN6t5u2EMz4Wd3ngmvkV7AhYEoyDcy7dIVTnfLuNcDlgoJt/17GdnHqUlfXGKeeHmfsI5drGeVyp3udTvEr43RuVBvsQqWn5rqtvHnA1WcS2JWxZ/uVBUY8rEu4xFmPADqjzlNc2+W6mTfDqXqvd41T+3pLNv1/YsIkhwdIloNNAj5Tb/pUpzgYnYJDk6OZExPXRR+OHaKa2H0VjjGxVndWG2wQaFbvrY2SYXlgIr3Z6x0QdpgMNnq1l1FBsVXZ7fZDnBpgrF4MUv244NQgM3bqOafGt+pa0f6DnfPvSSqKw/h7u251XkBqIlhTM3UomFtO3Ji3UWjOsaxRSGPmjzUBYUU112YicxLV3CpLZsWyDXsBvYHOee7hci5wJbbr9Y/O85f3evjns/Pj+T7nC/ChjTTsgVUTdHsXUbWVwECHLsk54yufonT4+N+JRdiKLuOI3HkaV5No8CohXwz9AyeExKwrvtNe7/EOXMXnOobX6KjDbf2pizrboHFE9PxKI/NokEau1wVea07iQAeUhbYizY1BuR6YMhdN4EE7BLImM8z24nuNOtFh0xDbWaoCe4sd31pgykPNZqk4MH92VMRHLn11Yw52tys5+C99wJK9wBDvOCaacZjGNQlXADu+1cAO+ARKwmkIIeMUFbOkHSDmVfbwoWJt8R2xCRgCnO9avuOAeW+kByOEbAk7fqjNcmBBPk0W8S6lsppyKsrHxNmIuAas/RNOAHYAqP4IsxcRnBg9dgF7iqSLR64OE2LLNNS/qMc7Y23WA4N7yNINK6zVPBtJavZ944oKPtlDP0h2U+uR0na3+MajAcxJ/mI9bkNpBD0jhLftFCixfdNQ/wfGlJwIZi0HhmlymR2KFwSlFKUo1JZYeE8SwottOrF+8RFFW4DBWBQ0YHcKxOyo3KcBIkJ9GoNttp0BsJlK7aik16sZbI5NIJ/+7FYR/wjOIllGmAbN2ARs0sVmD7TAOgWmG+7oGRaM4SrONXkWwHpg8XcAxB0GrXh0HP8quwewHA/8CtdxAhDDwbwWN+YwIGoDMChEyOMJTuyEUHcR6jQLxnAVZ8O95Ljf36sKz73+/F3s6tVI1nvpm5DIzu7lZ1WbgMGYHunBoJMwZp5Rl2d5uC4Y+01I5r/vraDmdUSw8m+ek4re1wRjJMB2fAkMixJmTNP8S7rwnDRSdXQagzGmadkfxvSaGBOJhY/oOxkyWItRwnZ8CYz7faxKUbdqM5whmlbfky2b1XKRvBs03AvVebK+lT7ZRW1YlbsfxM58WozL70ueotAIa6AI6N3nqzS0lsBO0/0Yvsx29Gd+tTQxOLglgTVVyEMEySX5D7r5ykF0ufolsObqHFrZvPFibCwTu9Ivf1WgVvJnGCQwCUyQBNaiJLAWJYG1KAmsRUlgLUoC+9ve3eQkDIRhHH9bIYUiiv2Ctlj5aoQQ2LnTVXFRF2iGBQfQQ+gtWOgVDLfqVlgAOzV+xOmURE3EhMVMMpP+j/DLvLBp8mxZCrZlDME2fJeTgm0CGwdMGj+JAnYfMOlGGLBlwKShMGCLu4BB19GLKGCriMFRLsPFoyhg8zCMhpSLwnAuDNh0FjJohsQBQwzEVkgkMPQxv6Ta2ycSCwyhc6o9oBQsBaMZAXvmHsxKwHxGYKPRJO6CkwYbwBT1hA3Y9JaM2U0GPPUTzAQ9GeTssQF75xDs1yBnHQ5jMFtVfCZgr9gLdzXgp+/JVwODdcCr4o1cR1H7Pn0wv+8kU/Jl4DETgzUhvskcfmL5/Gl3n2Zn3Z5iZ4mXBVzWwGCtCpTjGWYiRjlVUXIyv0PyABoGk1zyxLI7O46tUM52sBe3O/LxRcZgGoBXk4+xGP1KMqnmAZc1YzDyxMpVfJWlLOVKB2svPn/xwZUSsIKBxYoysyxOvYwWAcNpWMzTqzKTam3gM0OTCBgRywAma+tWkW67ls7p3yOAWZASMFKrU4G0fzIaxImArcmOXDOT9ld7dbdJjBKwtK36AjzMY01U7+9+AAAAAElFTkSuQmCC)}.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 | You need to enable JavaScript to run this app.
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 |
20 |
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 |
changeContract(button.name)}
34 | disabled={active === button.name}
35 | className={`coin-picker-button ${
36 | active === button.name ? 'active' : ''
37 | }`}
38 | >
39 |
44 | {button.text}
45 |
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 |
79 |
80 |
81 |
86 |
91 |
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 |
92 | copy
93 |
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 |
--------------------------------------------------------------------------------