├── .gitignore
├── README.md
├── client
├── .dockerignore
├── .env.example
├── .gitignore
├── Dockerfile
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.png
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ ├── robots.txt
│ └── web.config
├── scripts
│ └── postbuild.js
└── src
│ ├── actions
│ ├── index.js
│ └── types.js
│ ├── assets
│ ├── img
│ │ ├── Indsoft_logo.png
│ │ ├── XinFin_dark.png
│ │ ├── XinFin_white.png
│ │ ├── blockdegree_dark.png
│ │ ├── blockdegree_favicon.png
│ │ ├── blockdegree_icon_white.png
│ │ ├── blockdegree_white.png
│ │ ├── dummy-certi.png
│ │ ├── funders.png
│ │ ├── xdcFavicons
│ │ │ ├── android-icon-144x144.png
│ │ │ ├── android-icon-192x192.png
│ │ │ ├── android-icon-36x36.png
│ │ │ ├── android-icon-48x48.png
│ │ │ ├── android-icon-72x72.png
│ │ │ ├── android-icon-96x96.png
│ │ │ ├── apple-icon-114x114.png
│ │ │ ├── apple-icon-120x120.png
│ │ │ ├── apple-icon-144x144.png
│ │ │ ├── apple-icon-152x152.png
│ │ │ ├── apple-icon-180x180.png
│ │ │ ├── apple-icon-57x57.png
│ │ │ ├── apple-icon-60x60.png
│ │ │ ├── apple-icon-72x72.png
│ │ │ ├── apple-icon-76x76.png
│ │ │ ├── apple-icon-precomposed.png
│ │ │ ├── apple-icon.png
│ │ │ ├── browserconfig.xml
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon-96x96.png
│ │ │ ├── favicon.ico
│ │ │ ├── manifest.json
│ │ │ ├── ms-icon-144x144.png
│ │ │ ├── ms-icon-150x150.png
│ │ │ ├── ms-icon-310x310.png
│ │ │ └── ms-icon-70x70.png
│ │ └── xdc_logo.png
│ └── scss
│ │ ├── abstracts
│ │ ├── _functions.scss
│ │ ├── _mixins.scss
│ │ └── _variables.scss
│ │ ├── base
│ │ ├── _animation.scss
│ │ ├── _base.scss
│ │ ├── _typography.scss
│ │ └── _utilities.scss
│ │ ├── components
│ │ ├── _accordion.scss
│ │ ├── _banner.scss
│ │ ├── _button.scss
│ │ ├── _card.scss
│ │ ├── _center-form.scss
│ │ ├── _chart.scss
│ │ ├── _custom-card.scss
│ │ ├── _highlighted.scss
│ │ ├── _icon-card.scss
│ │ ├── _modal.scss
│ │ ├── _orderbook.scss
│ │ ├── _render-input.scss
│ │ ├── _select.scss
│ │ ├── _table.scss
│ │ └── _toast.scss
│ │ ├── layouts
│ │ ├── _footer.scss
│ │ ├── _header.scss
│ │ ├── _main-panel.scss
│ │ └── _sidebar.scss
│ │ ├── main.scss
│ │ └── pages
│ │ ├── _best-price.scss
│ │ ├── _crons.scss
│ │ ├── _dashboard.scss
│ │ ├── _faq.scss
│ │ ├── _home.scss
│ │ ├── _management.scss
│ │ ├── _market-maker.scss
│ │ ├── _message-page.scss
│ │ ├── _monitor.scss
│ │ ├── _profile.scss
│ │ └── _signup.scss
│ ├── components
│ ├── App.js
│ ├── Charts
│ │ └── LineChart.js
│ ├── DataTable.js
│ ├── EditCurrencyCard.js
│ ├── Exchange.js
│ ├── Footer.js
│ ├── FormHelper.js
│ ├── IconCard.js
│ ├── Liquidity.js
│ ├── LiquidityDetails.js
│ ├── ManageKeys.js
│ ├── StaticTable.js
│ ├── SuperAdminComponent.js
│ └── Wallet.js
│ ├── containers
│ ├── AdminManagement.js
│ ├── AdminProfile.js
│ ├── DailyStats.js
│ ├── Dashboard.js
│ ├── Header.js
│ ├── Login.js
│ ├── Management.js
│ ├── Monitor.js
│ ├── Sidebar.js
│ └── Signup.js
│ ├── helpers
│ ├── Notification.js
│ ├── PaymentModal.js
│ ├── ResponseHelper.js
│ ├── constant.js
│ └── withRouter.js
│ ├── hooks
│ ├── RouteButton.js
│ └── ScrollToTop.js
│ ├── index.js
│ ├── middleware
│ ├── RequireLogin.js
│ └── RequireLogout.js
│ ├── reducers
│ ├── AdminProfileReducer.js
│ ├── AdminReducer.js
│ ├── ArbitrageReducer.js
│ ├── Auth.js
│ ├── DailyStatsReducer.js
│ ├── Exchange.js
│ ├── LiquidityBotReducer.js
│ ├── LiquidityDetailsBotReducer.js
│ ├── ManageKeysReducer.js
│ ├── MonitorReducer.js
│ ├── SocketReducer.js
│ └── index.js
│ ├── redux
│ └── store.js
│ ├── serviceWorker.js
│ └── setupTests.js
├── docker-compose.yml
├── getLogins.sh
├── install_docker.sh
├── logos
├── bitfinex.png
├── bitrue.png
├── bittrex.png
├── gateio.png
├── huobi.png
└── kucoin.png
└── server
├── .dockerignore
├── .env.example
├── .gitignore
├── Dockerfile
├── app.js
├── bin
└── www
├── controllers
├── adminController.js
├── cronController.js
├── indexController.js
├── spreadBotController-Old.js
└── spreadBotController.js
├── crons
├── scheduledCrons.js
└── walletBalanceCron.js
├── helpers
├── MAIL.js
├── RESPONSE.js
├── axiosHelper.js
├── commonHelper.js
├── constant.js
├── creds.json
├── crypto.js
├── data.json
├── databaseHelpers
│ └── adminHelper.js
├── decryptedEnv.js
├── errors.js
├── exchangeHelpers
│ ├── bitfinex.js
│ ├── bitrue.js
│ ├── bittrex.js
│ ├── gateio.js
│ ├── huobi.js
│ └── kucoin.js
├── exchangeSocket
│ └── bitfinex.js
├── globals.js
├── initialSetup.js
├── logger.js
├── networkLogger.js
├── orderPlacement.js
├── socketClass
│ └── wsClass.js
└── socket_io.js
├── middlewares
├── errorHandler.js
├── requireAdmin.js
├── requireSuperAdmin.js
└── validateRequest.js
├── models
├── admin.js
├── arbitrageOperations.js
├── completedOrders.js
├── dailyData.js
├── dailyStats.js
├── dailyWalletBalances.js
├── exchangeCurrencies.js
├── exchangeData.js
├── exchangePair.js
├── exchangeWalletSnapshot.js
├── spreadBotDetails.js
├── spreadBotGeneratedOrders.js
├── spreadBotMaintainOrders.js
└── spreadBotOrders.js
├── package-lock.json
├── package.json
├── public
└── stylesheets
│ └── style.css
├── routes
├── admin.js
├── index.js
└── spreadBot.js
├── services
└── redis.js
└── views
├── error.jade
├── index.jade
└── layout.jade
/.gitignore:
--------------------------------------------------------------------------------
1 | /mongodb-data
2 | .env
--------------------------------------------------------------------------------
/client/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/client/.env.example:
--------------------------------------------------------------------------------
1 | REACT_APP_URL=http://localhost:5000/api/
2 | REACT_APP_WSS=ws://localhost:3002
3 | REACT_APP_NAME=MMBot
--------------------------------------------------------------------------------
/client/.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 | # production
12 | /build
13 |
14 | # misc
15 | .env
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | serving-build
27 |
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Node.js runtime as the base image
2 | FROM node:14
3 |
4 | # Set the working directory in the container
5 | WORKDIR /app
6 |
7 | # Copy package.json and package-lock.json to the container
8 | COPY package*.json ./
9 |
10 | # Install app dependencies
11 | RUN npm install
12 |
13 | # Copy the rest of the application code to the container
14 | COPY . .
15 |
16 | # Build the React app
17 | # RUN npm run build
18 |
19 | # Command to start the app
20 | CMD ["npm", "start"]
21 |
--------------------------------------------------------------------------------
/client/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:300](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 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "corporate-view",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
7 | "@fortawesome/fontawesome-svg-core": "^1.2.28",
8 | "@fortawesome/free-solid-svg-icons": "^5.13.0",
9 | "@fortawesome/react-fontawesome": "^0.1.9",
10 | "@testing-library/jest-dom": "^4.2.4",
11 | "@testing-library/react": "^9.5.0",
12 | "@testing-library/user-event": "^7.2.1",
13 | "axios": "^0.21.1",
14 | "bootstrap": "^4.5.0",
15 | "dotenv": "^8.2.0",
16 | "form-data": "^3.0.0",
17 | "fs-extra": "^9.0.1",
18 | "lodash": "^4.17.20",
19 | "mdbreact": "^4.26.1",
20 | "namor": "^2.0.2",
21 | "node-sass": "^4.14.1",
22 | "qrcode.react": "^1.0.0",
23 | "react": "^16.13.1",
24 | "react-animated-css": "^1.2.1",
25 | "react-bootstrap": "^1.3.0",
26 | "react-bootstrap-table-next": "^4.0.3",
27 | "react-bootstrap-table2-filter": "^1.3.3",
28 | "react-bootstrap-table2-paginator": "^2.1.2",
29 | "react-bootstrap-table2-toolkit": "^2.1.3",
30 | "react-datepicker": "^3.3.0",
31 | "react-dom": "^16.13.1",
32 | "react-hot-loader": "^4.12.21",
33 | "react-logger": "^1.1.0",
34 | "react-notifications-component": "^2.4.0",
35 | "react-redux": "^7.2.0",
36 | "react-router-dom": "^5.2.0",
37 | "react-scripts": "^4.0.1",
38 | "react-switch": "^5.0.1",
39 | "react-table": "^7.1.0",
40 | "react-toastify": "^6.0.5",
41 | "react-tooltip": "^4.2.10",
42 | "redux": "^4.0.5",
43 | "redux-logger": "^3.0.6",
44 | "redux-thunk": "^2.3.0",
45 | "socket.io-client": "^2.3.0",
46 | "winston": "^3.3.3",
47 | "ws": "^7.3.1"
48 | },
49 | "scripts": {
50 | "start": "react-scripts start",
51 | "build": "react-scripts build",
52 | "test": "react-scripts test",
53 | "eject": "react-scripts eject",
54 | "postbuild": "node ./scripts/postbuild"
55 | },
56 | "eslintConfig": {
57 | "extends": "react-app"
58 | },
59 | "browserslist": {
60 | "production": [
61 | ">0.2%",
62 | "not dead",
63 | "not op_mini all"
64 | ],
65 | "development": [
66 | "last 1 chrome version",
67 | "last 1 firefox version",
68 | "last 1 safari version"
69 | ]
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/client/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/public/favicon.png
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/public/logo512.png
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/public/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/client/scripts/postbuild.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const fse = require("fs-extra");
3 | const path = require("path");
4 |
5 | const buildFolder = "serving-build";
6 | const source = "build";
7 |
8 | const buildFolderPath = path.join(__dirname, "../", buildFolder);
9 | const sourcePath = path.join(__dirname, "../", source);
10 |
11 | fse.ensureDirSync(buildFolderPath);
12 |
13 | fse.emptyDirSync(buildFolderPath);
14 |
15 | fse
16 | .copy(sourcePath, buildFolderPath)
17 | .then(console.log(">>>> successfully builed the code"))
18 | .catch((err) => {
19 | console.log("error in post-build script", err);
20 | process.exit(1);
21 | });
22 |
--------------------------------------------------------------------------------
/client/src/assets/img/Indsoft_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/Indsoft_logo.png
--------------------------------------------------------------------------------
/client/src/assets/img/XinFin_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/XinFin_dark.png
--------------------------------------------------------------------------------
/client/src/assets/img/XinFin_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/XinFin_white.png
--------------------------------------------------------------------------------
/client/src/assets/img/blockdegree_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/blockdegree_dark.png
--------------------------------------------------------------------------------
/client/src/assets/img/blockdegree_favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/blockdegree_favicon.png
--------------------------------------------------------------------------------
/client/src/assets/img/blockdegree_icon_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/blockdegree_icon_white.png
--------------------------------------------------------------------------------
/client/src/assets/img/blockdegree_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/blockdegree_white.png
--------------------------------------------------------------------------------
/client/src/assets/img/dummy-certi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/dummy-certi.png
--------------------------------------------------------------------------------
/client/src/assets/img/funders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/funders.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/android-icon-144x144.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/android-icon-192x192.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/android-icon-36x36.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/android-icon-48x48.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/android-icon-72x72.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/android-icon-96x96.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-114x114.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-120x120.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-144x144.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-152x152.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-180x180.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-57x57.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-60x60.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-72x72.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-76x76.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/apple-icon.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/favicon-16x16.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/favicon-32x32.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/favicon-96x96.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/favicon.ico
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdcFavicons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdcFavicons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/client/src/assets/img/xdc_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/img/xdc_logo.png
--------------------------------------------------------------------------------
/client/src/assets/scss/abstracts/_functions.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/scss/abstracts/_functions.scss
--------------------------------------------------------------------------------
/client/src/assets/scss/abstracts/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin clearFix {
2 | &::after {
3 | content:'';
4 | clear:both;
5 | display:table;
6 | }
7 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/abstracts/_variables.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | --sidebar-width: 20rem;
3 | }
4 |
5 | $color-primary: #343a40;
6 | $color-primary-light: lighten($color-primary, 10%);
7 | $color-primary-lighter: lighten($color-primary, 50%);
8 |
9 | $color-background-primary: #ebebeb;
10 | $color-primary-border: #c0c0c0;
11 |
12 | $color-header: #343a40;
13 | $color-header-light: lighten($color-header, 10%);
14 | $color-header-lighter: lighten($color-header, 20%);
15 | $color-header-dark: darken($color-header, 10%);
16 |
17 | $color-light-grey: lightgrey;
18 | $color-light-grey-light: #cdcdcd;
19 | $color-grey-light-1: #f7f7f7;
20 | $color-grey-dark: #777;
21 | $color-white: #ffffff;
22 | $color-black: #000;
23 |
24 | $color-new-blue: #177bff;
25 | $color-new-green: #25ac37;
26 | $color-new-red: #ff0000;
27 | $color-new-orange: #ff8c00;
28 |
29 | $typo-scale-ratio: 8/9;
30 |
31 | $overall-font-primary: 1.5rem;
32 | $overall-font-secondary: #{$overall-font-primary * $typo-scale-ratio};
33 |
34 | $table-one-font-primary: 1.6rem;
35 | $table-one-font-secondary: #{$table-one-font-primary * $typo-scale-ratio};
36 |
37 | $modal-font-primary: 2rem;
38 | $modal-font-secondary: #{$modal-font-primary * $typo-scale-ratio};
39 | $modal-padding: 2rem;
40 | $modal-width: 50rem;
41 | $modal-height: 20rem;
42 | $modal-margin: 1rem;
43 |
44 | $footer-primary: 2.2rem;
45 | $footer-links: 1.6rem;
46 | $footer-secondary: 1.4rem;
47 |
48 | $sidebar-width: var(--sidebar-width);
49 | $sidebar-width-transaition: 0.5s;
50 | $sidebar-scroller-width: 0.75rem;
51 | $header-height: 5.5rem;
52 |
53 | $lg-width: 992px;
54 | $md-width: 762px;
55 | $sm-width: 580px;
56 |
--------------------------------------------------------------------------------
/client/src/assets/scss/base/_animation.scss:
--------------------------------------------------------------------------------
1 | @keyframes moveInLeft {
2 | 0% {
3 | opacity: 0;
4 | transform: translateX(-10rem);
5 | }
6 |
7 | 80% {
8 | transform: translateX(1rem);
9 | }
10 |
11 | 100% {
12 | opacity: 1;
13 | transform: translate((0));
14 | }
15 | }
16 |
17 | @keyframes moveInRight {
18 | 0% {
19 | opacity: 0;
20 | transform: translateX(10rem);
21 | }
22 |
23 | 80% {
24 | transform: translateX(-1rem);
25 | }
26 |
27 | 100% {
28 | opacity: 1;
29 | transform: translate((0));
30 | }
31 | }
32 |
33 | @keyframes moveInBottom {
34 | 0% {
35 | opacity: 0;
36 | transform: translateY(3rem);
37 | }
38 |
39 | 100% {
40 | opacity: 1;
41 | transform: translateY((0));
42 | }
43 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/base/_base.scss:
--------------------------------------------------------------------------------
1 | *::after,
2 | ::before {
3 | /* Basic Reset */
4 | margin: 0px;
5 | padding: 0px;
6 | }
7 |
8 | html {
9 | // defines what 1 rem is
10 | font-size: 62.5%;
11 | }
12 |
13 | body {
14 | margin: 0;
15 | overflow-x: hidden;
16 | background-color: $color-background-primary;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/assets/scss/base/_typography.scss:
--------------------------------------------------------------------------------
1 | .primary-text {
2 | font-size: 3rem;
3 | font-weight: 500;
4 | }
5 |
6 | .secondary-text {
7 | font-size: 1.8rem;
8 | }
9 |
--------------------------------------------------------------------------------
/client/src/assets/scss/base/_utilities.scss:
--------------------------------------------------------------------------------
1 | .u-tex-center {
2 | text-align: center;
3 | }
4 |
5 | .u-right {
6 | text-align: right;
7 | }
8 |
9 | .u-pad-right-1 {
10 | padding-right: 1rem;
11 | }
12 |
13 | .justify-center {
14 | justify-content: center;
15 | }
16 |
17 | .u-margin-bottom-8 {
18 | margin-bottom: 8rem;
19 | }
20 |
21 | .u-float-left {
22 | float: left;
23 | }
24 |
25 | .u-float-right {
26 | float: right;
27 | }
28 |
29 | .u-border-btm {
30 | border-bottom: 1px solid $color-light-grey;
31 | }
32 |
33 | .lg-hori-1 {
34 | @media screen and (max-width: 992px) {
35 | padding-bottom: 1rem;
36 | }
37 | }
38 |
39 | .u-back-light {
40 | &:hover {
41 | background-color: $color-primary-light;
42 | }
43 | }
44 |
45 | .u-text-right {
46 | text-align: right;
47 | }
48 |
49 | .u-scroll-x {
50 | width: 100%;
51 | overflow-x: auto;
52 | }
53 |
54 | .u-border-top {
55 | border-top: 1px solid $color-light-grey;
56 | }
57 |
58 | .u-justify-center {
59 | justify-content: center;
60 | }
61 |
62 | .u-text-left {
63 | text-align: left !important;
64 | }
65 |
66 | .u-no-pad-r {
67 | padding-right: 0 !important;
68 | }
69 |
70 | .u-no-pad-l {
71 | padding-left: 0 !important;
72 | }
73 |
74 | .u-no-pad-r--lg {
75 | @media screen and (min-width: $lg-width) {
76 | padding-right: 0 !important;
77 | }
78 | }
79 |
80 | .u-no-pad-l--lg {
81 | @media screen and (min-width: $lg-width) {
82 | padding-left: 0 !important;
83 | }
84 | }
85 |
86 | .u-no-pad-r--md {
87 | @media screen and (min-width: $md-width) {
88 | padding-right: 0 !important;
89 | }
90 | }
91 |
92 | .u-no-pad-l--md {
93 | @media screen and (min-width: $md-width) {
94 | padding-left: 0 !important;
95 | }
96 | }
97 |
98 | .u-no-list {
99 | list-style-type: none;
100 | padding-left: 0;
101 | }
102 |
103 | .u-pad-1 {
104 | padding: 1rem;
105 | }
106 |
107 | .u-margin-top-1 {
108 | margin-top: 1rem;
109 | }
110 |
111 | .u-position-sticky {
112 | position: -webkit-sticky; /* Safari */
113 | position: sticky;
114 | top: 0;
115 | }
116 |
117 | .u-align-right {
118 | width: 100%;
119 | text-align: right;
120 | }
121 |
122 | .u-width-full {
123 | width: 100%;
124 | }
125 |
126 | .noselect {
127 | -webkit-touch-callout: none; /* iOS Safari */
128 | -webkit-user-select: none; /* Safari */
129 | -khtml-user-select: none; /* Konqueror HTML */
130 | -moz-user-select: none; /* Old versions of Firefox */
131 | -ms-user-select: none; /* Internet Explorer/Edge */
132 | user-select: none; /* Non-prefixed version, currently */
133 | }
134 |
135 | .blue {
136 | color: $color-new-blue;
137 | }
138 |
139 | .red {
140 | color: $color-new-red;
141 | }
142 |
143 | .green {
144 | color: $color-new-green;
145 | }
146 |
147 | .orange {
148 | color: $color-new-orange;
149 | }
150 |
151 | .lighten {
152 | color: $color-light-grey;
153 | }
154 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_accordion.scss:
--------------------------------------------------------------------------------
1 | .accordion {
2 | .card-header {
3 | font-size: 2rem;
4 |
5 | svg {
6 | color: $color-new-blue;
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_banner.scss:
--------------------------------------------------------------------------------
1 | .banner {
2 | &__title {
3 | text-align: center;
4 | color: $color-primary;
5 | }
6 |
7 | &__hero {
8 | text-align: center;
9 | img {
10 | width: 100%;
11 | }
12 | }
13 |
14 | &__content {
15 | padding: 0.5rem;
16 | text-align: center;
17 | color: $color-primary;
18 |
19 | ul {
20 | li {
21 | margin: 1rem 0 1rem 0;
22 | }
23 | }
24 | }
25 |
26 | &__footer {
27 | padding: 2rem;
28 | color: $color-primary;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_button.scss:
--------------------------------------------------------------------------------
1 | .btn-custom {
2 | &:link,
3 | :visited {
4 | display: inline-block;
5 | text-transform: uppercase;
6 | text-decoration: none;
7 | padding: 1.5rem 4rem;
8 | border-radius: 10rem;
9 | transition: all 0.2s;
10 | position: relative;
11 | font-size: 1.6rem;
12 | }
13 |
14 | &--white {
15 | background-color: $color-white;
16 | color: $color-grey-dark;
17 |
18 | &::after {
19 | background-color: white;
20 | }
21 | }
22 |
23 | &:hover {
24 | transform: translateY(-0.3rem);
25 | box-shadow: 0 1rem 2rem rgba($color-black, 0.2);
26 |
27 | &::after {
28 | transform: scaleX(1.4) scaleY(1.6);
29 | opacity: 0;
30 | }
31 | }
32 |
33 | &:active {
34 | transform: translate(-0.1rem);
35 | box-shadow: 0 0.5rem 1rem rgba($color-black, 0.2);
36 | }
37 |
38 | &::after {
39 | content: "";
40 | display: inline-block;
41 | height: 100%;
42 | width: 100%;
43 | border-radius: 100px;
44 | position: absolute;
45 | top: 0;
46 | left: 0;
47 | z-index: -1;
48 | transition: all 0.3s;
49 | }
50 |
51 | &--animated {
52 | animation: moveInBottom 0.5s ease-out 0.5s;
53 | animation-fill-mode: backwards;
54 | }
55 | }
56 |
57 | .std-btn {
58 | font-size: $overall-font-primary;
59 | margin: 0.5rem;
60 | right: 0;
61 | }
62 |
63 | .route-btn {
64 | display: inline;
65 | margin: 0;
66 | border: 0;
67 | padding: 0;
68 | cursor: pointer;
69 | }
70 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_card.scss:
--------------------------------------------------------------------------------
1 | .simple-card {
2 | padding: 1rem;
3 | margin: 1rem;
4 |
5 | &--header {
6 | text-align: center;
7 | font-weight: 500;
8 | font-size: $overall-font-primary;
9 | }
10 |
11 | &--body {
12 | padding: 1rem;
13 | margin: 1rem;
14 | font-size: $overall-font-secondary;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_center-form.scss:
--------------------------------------------------------------------------------
1 | .center-form {
2 | margin-top: 2rem;
3 | border: 1px solid $color-primary-lighter;
4 | padding: 1rem;
5 | border-radius: 1rem;
6 | background-color: $color-white;
7 |
8 | .custom-file-label {
9 | font-size: 1.5rem;
10 | }
11 |
12 | .form-control {
13 | font-size: 1.5rem;
14 | }
15 |
16 | .btn {
17 | font-size: 1.5rem;
18 | }
19 |
20 | &__title {
21 | text-align: center;
22 | font-size: 3rem;
23 | }
24 |
25 | &__content {
26 | padding: 1rem;
27 | font-size: 1.8rem;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_chart.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/client/src/assets/scss/components/_chart.scss
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_custom-card.scss:
--------------------------------------------------------------------------------
1 | .custom-card {
2 | background-color: $color-white;
3 | padding: 1rem;
4 | border-radius: 1rem;
5 | color: $color-primary;
6 | height: 286px;
7 |
8 | &__title {
9 | font-size: 3rem;
10 | b {
11 | color: $color-new-blue;
12 | }
13 | text-align: center;
14 | border-bottom: 1px solid $color-light-grey;
15 | }
16 |
17 | &__content {
18 | text-align: center;
19 | font-size: 1.8rem;
20 | img {
21 | width: 20rem;
22 | height: 20rem;
23 | }
24 |
25 | &--text {
26 | padding: 1rem;
27 | }
28 | }
29 |
30 | @media screen and (max-width:762px) {
31 | margin-bottom: 2rem;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_highlighted.scss:
--------------------------------------------------------------------------------
1 | .highlighted-note {
2 | width: 100%;
3 | background: #354c60;
4 | margin-bottom: 20px;
5 | margin-top: 20px;
6 | padding: 15px;
7 | color: white;
8 | font-weight: 400;
9 | border: 1px solid #82baf6;
10 |
11 | &--body {
12 | .highlighted-note--body {
13 | margin-top: 10px;
14 | }
15 |
16 | a {
17 | color: #04cdfc;
18 | text-decoration: none;
19 | }
20 | }
21 | &--header {
22 | font-size: large;
23 | z-index: 2;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_icon-card.scss:
--------------------------------------------------------------------------------
1 | .icon-card {
2 | padding: 1rem;
3 | background-color: $color-white;
4 | border-radius: 0.5rem;
5 | height: 8rem;
6 |
7 | &__icon {
8 | padding-left: 2.5rem;
9 | text-align: center;
10 | }
11 |
12 | &__body {
13 | padding-left: 1rem;
14 | width: 100%;
15 | &--title {
16 | font-size: $overall-font-primary;
17 | font-weight: 500;
18 | }
19 | &--text {
20 | font-size: $overall-font-secondary;
21 | padding: 0.5rem;
22 | }
23 | }
24 |
25 | @media screen and (max-width: 987px) {
26 | margin-bottom: 1rem;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_modal.scss:
--------------------------------------------------------------------------------
1 | .blockdegree-modal {
2 | max-width: $modal-width;
3 |
4 | .modal-content {
5 | max-width: $modal-width;
6 | height: $modal-height;
7 | border-radius: 0.5rem;
8 | }
9 |
10 | @media only screen and (max-width: 580px) {
11 | .blockdegree-modal {
12 | left: 50%;
13 | }
14 |
15 | .blockdegree-modal {
16 | transform: translateX(-50%);
17 | }
18 | }
19 | }
20 |
21 | .description-modal {
22 | &__header {
23 | padding: $modal-padding !important;
24 | background-color: $color-primary;
25 | color: $color-white;
26 | &--title {
27 | font-size: $modal-font-primary;
28 | }
29 |
30 | .close {
31 | color: $color-white;
32 | }
33 | }
34 |
35 | &__body {
36 | padding: $modal-padding;
37 | font-size: $modal-font-secondary;
38 | background-color: $color-light-grey;
39 | color: $color-primary;
40 | border-radius: 0.5rem;
41 | }
42 | }
43 |
44 | .qr-modal {
45 | max-width: $modal-width;
46 | &__header {
47 | padding: $modal-padding !important;
48 | background-color: $color-primary;
49 | color: $color-white;
50 | &--title {
51 | font-size: $modal-font-primary;
52 | }
53 |
54 | .close {
55 | color: $color-white;
56 | }
57 | }
58 |
59 | &__body {
60 | padding: $modal-padding;
61 | font-size: $modal-font-secondary;
62 | background-color: $color-light-grey;
63 | color: $color-primary;
64 | border-radius: 0.5rem;
65 | text-align: center;
66 |
67 | &--img {
68 | canvas {
69 | height: 20rem !important;
70 | width: 20rem !important;
71 | padding: 0.5rem;
72 | }
73 | }
74 |
75 | &--wrap {
76 | margin-top: 2rem;
77 | padding: 2rem;
78 | border-radius: 1rem;
79 | background-color: $color-white;
80 | text-align: center;
81 | input {
82 | width: 100%;
83 | }
84 |
85 | .address {
86 | padding: 0.5rem;
87 | overflow: hidden;
88 | background-color: $color-light-grey;
89 | border-radius: 0.5rem;
90 | }
91 |
92 | .copy-btn {
93 | margin: 0.5rem;
94 | font-size: $modal-font-secondary;
95 | }
96 | }
97 | }
98 | }
99 |
100 | .payment-modal {
101 | &__header {
102 | padding: $modal-padding !important;
103 | background-color: $color-primary;
104 | color: $color-white;
105 | &--title {
106 | font-size: $modal-font-primary;
107 | }
108 |
109 | .close {
110 | color: $color-white;
111 | }
112 | }
113 |
114 | &__body {
115 | display: flex;
116 | flex-direction: column;
117 | justify-content: center;
118 | padding: $modal-padding;
119 | font-size: $modal-font-secondary;
120 | background-color: $color-light-grey;
121 | color: $color-primary;
122 | border-radius: 0.5rem;
123 | vertical-align: middle;
124 |
125 | text-align: center;
126 |
127 | button {
128 | width: 100%;
129 | font-size: $modal-font-secondary;
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_orderbook.scss:
--------------------------------------------------------------------------------
1 | .table-two {
2 | margin: 1rem 0;
3 | justify-content: center;
4 | overflow-x: scroll;
5 | height: fit-content;
6 |
7 | #search-bar-0 {
8 | font-size: $overall-font-secondary;
9 | }
10 |
11 | .react-bootstrap-table-page-btns-ul {
12 | font-size: $overall-font-secondary;
13 | }
14 |
15 | .react-bootstrap-table-pagination {
16 | margin-right: 0;
17 | margin-left: 0;
18 | }
19 |
20 | &__loader {
21 | padding: 1rem;
22 | text-align: center;
23 |
24 | &--text {
25 | padding: 0.5rem;
26 | }
27 | }
28 |
29 | table {
30 | border-collapse: separate;
31 | border-spacing: 0 1px;
32 | border: solid $color-light-grey 1px;
33 | border-radius: 6px;
34 | }
35 |
36 | thead {
37 | background-color: $color-primary;
38 | color: $color-white;
39 | text-align: center;
40 | // font-size: $table-one-font-primary;
41 | font-size: 15px;
42 |
43 | th {
44 | border-bottom: none;
45 | }
46 | }
47 |
48 | tbody {
49 | background-color: $color-white;
50 | color: $color-primary;
51 | // font-size: $table-one-font-secondary;
52 | font-size: 15px;
53 | text-align: center;
54 | }
55 |
56 | tr,
57 | td,
58 | th {
59 | padding: 1.2rem;
60 | border: none;
61 | width: 10rem;
62 | outline: none;
63 |
64 | button {
65 | font-size: $table-one-font-secondary;
66 | }
67 | }
68 |
69 | tr {
70 | border-bottom: 1px solid $color-light-grey;
71 | }
72 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_render-input.scss:
--------------------------------------------------------------------------------
1 | .render-input {
2 | margin: 0.5rem;
3 | font-size: $overall-font-primary;
4 |
5 | input {
6 | font-size: $overall-font-primary;
7 | }
8 |
9 | .render-input {
10 | font-size: $overall-font-primary * $typo-scale-ratio;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_select.scss:
--------------------------------------------------------------------------------
1 | .select {
2 | display: flex;
3 | justify-content: space-between;
4 | margin-bottom: 12px;
5 | select {
6 | width: 40%;
7 | font-size: 15px;
8 | padding: 4px 8px;
9 | outline: none;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_table.scss:
--------------------------------------------------------------------------------
1 | .table-one {
2 | // padding: 1rem;
3 | justify-content: center;
4 | width: 95%;
5 | margin: 0 auto;
6 | margin-top: 2rem;
7 | height: fit-content;
8 | overflow-x: auto;
9 |
10 | ::-webkit-scrollbar {
11 | display: none;
12 | }
13 |
14 | .action-btn {
15 | padding: 0.5rem;
16 | margin: 0.5rem;
17 | }
18 |
19 | .table--footer {
20 | padding: 1rem;
21 | margin: 1rem;
22 | padding-top: 0;
23 | margin-top: 0;
24 | font-size: $overall-font-secondary;
25 |
26 | .footer-btn {
27 | float: right;
28 | font-size: $overall-font-secondary;
29 | }
30 |
31 | .note {
32 | float: left;
33 | }
34 | }
35 |
36 | #search-bar-0 {
37 | font-size: $overall-font-secondary;
38 | }
39 |
40 | .react-bootstrap-table-page-btns-ul {
41 | font-size: $overall-font-secondary;
42 | }
43 |
44 | .react-bootstrap-table-pagination {
45 | margin-right: 0;
46 | margin-left: 0;
47 | }
48 |
49 | &__loader {
50 | padding: 1rem;
51 | text-align: center;
52 |
53 | &--text {
54 | padding: 0.5rem;
55 | }
56 | }
57 |
58 | table {
59 | border-collapse: separate;
60 | border-spacing: 0 1px;
61 | border: solid $color-light-grey 1px;
62 | border-radius: 0px;
63 | }
64 |
65 | thead {
66 | background-color: $color-primary;
67 | color: $color-white;
68 | font-size: $table-one-font-primary;
69 |
70 | th {
71 | border-bottom: none;
72 | }
73 | }
74 |
75 | tbody {
76 | background-color: $color-white;
77 | color: $color-primary;
78 | font-size: $table-one-font-secondary;
79 | }
80 |
81 | tr,
82 | td,
83 | th {
84 | padding: 1rem;
85 | border: none;
86 | width: 10rem;
87 | outline: none;
88 |
89 | button {
90 | font-size: $table-one-font-secondary;
91 | }
92 | }
93 |
94 | tr {
95 | border-bottom: 1px solid $color-light-grey;
96 | }
97 | }
98 |
99 | .static-table {
100 | th,
101 | tr,
102 | td,
103 | table,
104 | thead,
105 | tbody {
106 | border: none !important;
107 | font-size: 15px;
108 | }
109 |
110 | thead {
111 | border-bottom: 1px solid $color-primary !important;
112 | }
113 | }
114 |
115 | .table-width {
116 | td,
117 | th {
118 | width: 16rem;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/client/src/assets/scss/components/_toast.scss:
--------------------------------------------------------------------------------
1 | .custom-toast {
2 | .Toastify__toast-body {
3 | font-size: $overall-font-secondary !important;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/layouts/_footer.scss:
--------------------------------------------------------------------------------
1 | .footer {
2 | background-color: $color-primary;
3 | color: $color-light-grey;
4 | min-height: 15rem;
5 | display: flex;
6 | justify-content: center;
7 |
8 | hr {
9 | color: $color-light-grey;
10 | }
11 |
12 | .container {
13 | margin: 0;
14 | }
15 | .row {
16 | padding: 0.5rem;
17 | .one,
18 | .two,
19 | .three,
20 | .four {
21 | height: 10rem;
22 | }
23 |
24 | .one,
25 | .two,
26 | .three,
27 | .four {
28 | .title {
29 | padding: 0.5rem;
30 | display: inline-block;
31 | font-size: $footer-primary;
32 | vertical-align: bottom;
33 | color: $color-white;
34 | }
35 |
36 | .desc {
37 | font-size: $footer-secondary;
38 | color: $color-light-grey;
39 | }
40 | }
41 | ul,
42 | li {
43 | list-style-type: none;
44 | padding: 0;
45 | padding: 0.5rem;
46 |
47 | .link {
48 | cursor: pointer;
49 | &:hover {
50 | color: $color-white;
51 | }
52 | }
53 | }
54 | }
55 |
56 | &__bottom {
57 | text-align: center;
58 | padding: 1rem;
59 | margin: 1rem;
60 | margin-top: 2rem;
61 | border-top: 0.5px solid $color-grey-dark;
62 | font-size: $footer-secondary;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/client/src/assets/scss/layouts/_header.scss:
--------------------------------------------------------------------------------
1 | .navbar {
2 | position: fixed;
3 | top: 0;
4 | width: 100%;
5 | padding: 0.5rem;
6 | z-index: 4;
7 |
8 | height: $header-height;
9 |
10 | #responsive-navbar-nav {
11 | background-color: $color-header;
12 | }
13 |
14 | a {
15 | outline: 0;
16 | }
17 |
18 | &__brand {
19 | vertical-align: bottom;
20 | padding-top: 0.5rem;
21 | }
22 |
23 | &-brand {
24 | font-size: 2.5rem;
25 | }
26 | &__links {
27 | a {
28 | outline: 0;
29 | box-sizing: content-box;
30 | color: $color-white !important;
31 | display: inline-block;
32 | margin: 0.25rem;
33 | padding: 0.75rem;
34 | font-size: 1.6rem;
35 | font-weight: 400;
36 | &:hover {
37 | transform: none;
38 | }
39 | }
40 |
41 | .nav-link {
42 | &:active,
43 | &:focus {
44 | color: $color-white !important;
45 | }
46 | }
47 | }
48 |
49 | &__dropdown {
50 | margin: 1rem;
51 | font-size: 1.6rem;
52 | font-weight: 400;
53 |
54 | #basic-nav-dropdown {
55 | color: $color-white;
56 | }
57 |
58 | .dropdown-menu {
59 | background-color: $color-header-light;
60 | padding: 1rem;
61 | margin: 0;
62 | a {
63 | outline: 0;
64 | font-size: 1.4rem;
65 | font-weight: 400;
66 | color: $color-light-grey;
67 | padding: 1rem;
68 | border-radius: 0.5rem;
69 |
70 | &:hover {
71 | background-color: $color-header-lighter;
72 | color: $color-white;
73 | }
74 | }
75 |
76 | .active {
77 | background-color: $color-header-lighter;
78 | color: $color-white;
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/client/src/assets/scss/layouts/_main-panel.scss:
--------------------------------------------------------------------------------
1 | .main-panel {
2 | padding: 1rem;
3 | // width: 100%;
4 | background-color: $color-background-primary;
5 | // min-height: 100vh;
6 | padding-top: $header-height;
7 | padding-left: $sidebar-width;
8 | overflow-x: hidden;
9 | overflow-y: auto;
10 |
11 | .banner-wrapper {
12 | .container {
13 | margin: 0;
14 | padding: 0;
15 | max-width: 100%;
16 |
17 | .banner-left,
18 | .banner-right {
19 | background-color: $color-white;
20 | padding: 1rem;
21 | border-radius: 0.5rem;
22 | overflow: hidden;
23 |
24 | @media screen and (min-width: $md-width) {
25 | height: 56rem;
26 | }
27 | }
28 |
29 | .banner-left {
30 | a,
31 | .btn-sign-up {
32 | color: $color-new-blue;
33 | font-weight: 600;
34 | }
35 | }
36 |
37 | .banner-right {
38 | &__tuple {
39 | margin: 0.5rem;
40 | &--title {
41 | font-size: 2.5rem;
42 | font-weight: 500;
43 | }
44 |
45 | &--content {
46 | margin: 0.5rem;
47 | font-size: 1.8rem;
48 | }
49 | }
50 | margin-left: 0;
51 | }
52 | }
53 |
54 | .funding-benefits {
55 | margin: 1.5rem;
56 | padding: 1rem;
57 | background-color: white;
58 | border-radius: 0.5rem;
59 |
60 | &__title {
61 | color: $color-primary;
62 | font-size: 3rem;
63 | font-weight: 500;
64 | text-align: center;
65 | }
66 |
67 | &__content {
68 | &--card {
69 | margin: 1rem;
70 | padding: 1rem;
71 | font-size: $overall-font-secondary;
72 | }
73 |
74 | &--img {
75 | img {
76 | width: 100%;
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
83 | @media screen and (max-width: 580px) {
84 | padding-top: $header-height;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/client/src/assets/scss/layouts/_sidebar.scss:
--------------------------------------------------------------------------------
1 | .sidebar {
2 | position: fixed;
3 | left: 0;
4 | z-index: 3;
5 | width: $sidebar-width;
6 | transition: width $sidebar-width-transaition;
7 | height: 100%;
8 | font-size: $overall-font-primary;
9 | background-color: $color-primary;
10 | color: white;
11 | padding-top: $header-height;
12 |
13 | &__nav-wrapper {
14 | overflow-y: auto;
15 | overflow-x: hidden;
16 | height: 90%;
17 |
18 | /**
19 |
20 | For mozilla scrollbar
21 |
22 | */
23 | scrollbar-color: $color-primary $color-primary;
24 | scrollbar-width: thin;
25 | }
26 |
27 | &__nav-wrapper::-webkit-scrollbar {
28 | width: $sidebar-scroller-width;
29 | }
30 |
31 | &__nav-wrapper::-webkit-scrollbar-track {
32 | background: $color-primary;
33 | }
34 |
35 | &__nav-wrapper:hover {
36 | scrollbar-color: $color-primary-lighter $color-primary;
37 | scrollbar-width: $sidebar-scroller-width;
38 | &::-webkit-scrollbar-thumb {
39 | background-color: $color-primary-lighter; /* color of the scroll thumb */
40 | }
41 | }
42 |
43 | &-nav {
44 | margin: 1rem;
45 | height: 5rem;
46 | text-align: center;
47 | padding: 1rem;
48 | border-radius: 0.5rem;
49 |
50 | &--text {
51 | visibility: hidden;
52 | }
53 | }
54 |
55 | &-nav:hover {
56 | background-color: $white !important;
57 | color: $color-primary !important;
58 | }
59 |
60 | &-nav__active {
61 | background-color: $white !important;
62 | color: $color-primary !important;
63 | pointer-events: none;
64 | }
65 |
66 | &-none {
67 | .sidebar-nav {
68 | display: none !important;
69 | }
70 | }
71 |
72 | &-toggle,
73 | &-toggle:active {
74 | position: absolute;
75 | bottom: 0;
76 | margin-bottom: 1rem;
77 | margin-left: 2rem;
78 | border: 0;
79 | background-color: $white !important;
80 | color: $color-primary !important;
81 | outline: none;
82 | box-shadow: none !important;
83 | }
84 | }
85 |
86 | .sidebar-open {
87 | width: 20rem;
88 | transition: width $sidebar-width-transaition;
89 |
90 | .sidebar-nav {
91 | text-align: left;
92 | .sidebar-nav--icon {
93 | display: inline-block !important;
94 | width: 3rem;
95 | transform: translateX(1rem);
96 | }
97 | .sidebar-nav--text {
98 | display: inline-block !important;
99 | visibility: visible;
100 | margin-left: $overall-font-primary;
101 | transition-duration: 0s;
102 | transition-property: visibility;
103 | transition-delay: calc(#{$sidebar-width-transaition}/ (3 / 2));
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/client/src/assets/scss/main.scss:
--------------------------------------------------------------------------------
1 | @import "~bootstrap/scss/bootstrap";
2 |
3 | @import "abstracts/functions";
4 | @import "abstracts/mixins";
5 | @import "abstracts/variables";
6 |
7 | @import "base/base";
8 | @import "base/animation";
9 | @import "base/typography";
10 | @import "base/utilities";
11 |
12 | @import "pages/home";
13 | @import "pages/signup";
14 | @import "pages/profile";
15 | @import "pages/dashboard";
16 | @import "pages/message-page";
17 | @import "pages/faq";
18 | @import "pages/monitor";
19 | @import "pages/crons";
20 | @import "pages/best-price";
21 | @import "pages/management";
22 | @import "pages/market-maker";
23 |
24 | @import "components/modal";
25 | @import "components/button";
26 | @import "components/banner";
27 | @import "components/center-form";
28 | @import "components/table";
29 | @import "components/highlighted";
30 | @import "components/toast";
31 | @import "components/accordion";
32 | @import "components/custom-card";
33 | @import "components/orderbook";
34 | @import "components/chart";
35 | @import "components/card";
36 | @import "components/select";
37 | @import "components/icon-card";
38 | @import "components/render-input";
39 |
40 | @import "layouts/header";
41 | @import "layouts/main-panel";
42 | @import "layouts/footer";
43 | @import "layouts/sidebar";
44 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_best-price.scss:
--------------------------------------------------------------------------------
1 | .best-price {
2 | .table-footer {
3 | font-size: $overall-font-secondary;
4 | float: right;
5 | padding: 0 1rem;
6 | text-transform: uppercase;
7 | }
8 |
9 | .table-header {
10 | margin-left: 1rem;
11 | margin-top: 2rem;
12 | font-weight: 500;
13 | font-size: $overall-font-primary;
14 | text-align: center;
15 | border-bottom: 0.5px solid $color-primary-lighter;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_crons.scss:
--------------------------------------------------------------------------------
1 | .crons {
2 | .table-footer {
3 | font-size: $overall-font-secondary;
4 | float: right;
5 | padding: 0 1rem;
6 | text-transform: uppercase;
7 | }
8 |
9 | .table-header {
10 | margin-left: 1rem;
11 | margin-top: 2rem;
12 | font-weight: 500;
13 | font-size: $overall-font-primary;
14 | text-align: center;
15 | border-bottom: 0.5px solid $color-primary-lighter;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_dashboard.scss:
--------------------------------------------------------------------------------
1 | .dashboard {
2 | .note-text {
3 | background-color: $color-white;
4 | margin: 2rem;
5 | padding: 1rem;
6 | border-radius: 1rem;
7 | font-size: $overall-font-secondary;
8 | color: $color-primary;
9 | a {
10 | outline: none;
11 | }
12 |
13 | &__link {
14 | color: $color-new-blue;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_faq.scss:
--------------------------------------------------------------------------------
1 | .faq-page {
2 | &__title {
3 | color: $color-primary;
4 | padding: 2rem 0 0 2rem;
5 | font-size: 3rem;
6 | font-weight: 600;
7 | }
8 |
9 | &__content {
10 | min-height: 40rem;
11 | font-size: $overall-font-secondary;
12 | margin: 1rem;
13 | padding: 1rem;
14 | border-radius: 1rem;
15 | background-color: $color-white;
16 |
17 | &--accordion {
18 | padding: 2rem;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_home.scss:
--------------------------------------------------------------------------------
1 | .section-about {
2 | background-color: $color-grey-light-1;
3 | padding: 25rem 0;
4 | margin-top: -20vh;
5 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_management.scss:
--------------------------------------------------------------------------------
1 | .management {
2 | .section-title {
3 | font-size: $overall-font-primary;
4 | font-weight: 500;
5 | text-align: center;
6 | color: $color-primary;
7 | margin: 1rem;
8 | border-bottom: 1px solid $color-primary-lighter;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_market-maker.scss:
--------------------------------------------------------------------------------
1 | .market-maker {
2 | padding: 1rem;
3 | }
4 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_message-page.scss:
--------------------------------------------------------------------------------
1 | .message-page {
2 | display: flex;
3 | justify-content: center;
4 | padding: 1rem;
5 |
6 | .message {
7 | background-color: $color-white;
8 | width: 60%;
9 | padding: 2rem;
10 | margin-top: 3rem;
11 | border-radius: 1rem;
12 |
13 | &__icon {
14 | margin-top: 2rem;
15 | margin-bottom: 2rem;
16 |
17 | display: flex;
18 | justify-content: center;
19 | &.success {
20 | color: $color-new-green;
21 | }
22 | &.error {
23 | color: $color-new-red;
24 | }
25 | }
26 |
27 | &__body {
28 | color: $color-primary;
29 | &--title {
30 | font-size: $overall-font-primary;
31 | font-weight: 600;
32 | }
33 | &--content {
34 | font-size: $overall-font-secondary;
35 | }
36 | }
37 |
38 | @media screen and (max-width: 580px) {
39 | width: 100%;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_monitor.scss:
--------------------------------------------------------------------------------
1 | .monitor {
2 | padding: 1rem;
3 |
4 | .heap-status {
5 | font-size: $overall-font-secondary;
6 | font-weight: 500;
7 | }
8 |
9 | .bordered-form {
10 | margin-left: 2rem;
11 | }
12 |
13 | table {
14 | .profit {
15 | background-color: lighten($color-new-green, 30%);
16 | color: $color-primary;
17 | }
18 |
19 | .loss {
20 | background-color: lighten($color-new-red, 30%);
21 | color: $color-primary;
22 | }
23 |
24 | .neutral {
25 | background-color: lighten($color-light-grey, 10%);
26 | color: $color-primary;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_profile.scss:
--------------------------------------------------------------------------------
1 | .profile-page {
2 |
3 | button, a {
4 | outline: none;
5 | }
6 |
7 | &__title {
8 | color: $color-primary;
9 | padding: 2rem 0 0 2rem;
10 | font-size: 3rem;
11 | font-weight: 600;
12 | }
13 |
14 | &__content {
15 | font-size: $overall-font-secondary;
16 |
17 | &--note {
18 | background-color: $color-white;
19 | margin: 1rem;
20 | padding: 1rem;
21 | border-radius: 1rem;
22 | font-size: $overall-font-secondary;
23 | color: $color-primary;
24 |
25 | a {
26 | outline: none;
27 | }
28 | }
29 |
30 | .card-left,
31 | .card-right {
32 | .title {
33 | font-size: $overall-font-primary;
34 | padding: 0.5rem;
35 | padding-bottom: 1rem;
36 | font-weight: 600;
37 | }
38 | background-color: $color-white;
39 | margin: 1rem;
40 | padding: 1rem;
41 | border-radius: 2rem;
42 | }
43 |
44 | .card-left {
45 | .row {
46 | padding: 0;
47 | margin: 0.5rem;
48 | input {
49 | border-radius: 0.5rem;
50 | border: 1px solid $color-light-grey;
51 | padding: 0.5rem;
52 | margin: 0.5rem 0 0.5rem 0;
53 | width: 100%;
54 | }
55 |
56 | .logo-wrapper {
57 | .logo {
58 | width: 13rem;
59 | height: 13rem;
60 | }
61 | }
62 | }
63 | .field-key {
64 | font-weight: 600;
65 | padding-top: 1rem;
66 | }
67 | }
68 |
69 | .card-right {
70 | img {
71 | width: 100%;
72 | height: 100%;
73 | }
74 | }
75 | }
76 |
77 | @media screen and (max-width: 580px) {
78 | padding: 0rem;
79 |
80 | .col,
81 | .col-lg-6 {
82 | padding: 0rem;
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/client/src/assets/scss/pages/_signup.scss:
--------------------------------------------------------------------------------
1 | .sign-up {
2 | background-color: whitesmoke;
3 | // width: 100%;
4 | padding: 1rem;
5 | min-height: 95vh;
6 | }
7 |
--------------------------------------------------------------------------------
/client/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { connect } from "react-redux";
3 | import { Redirect, Switch, Route } from "react-router-dom";
4 | import "../assets/scss/main.scss";
5 | import Header from "../containers/Header";
6 | import Dashboard from "../containers/Dashboard";
7 | import SignUp from "../containers/Signup";
8 | import Login from "../containers/Login";
9 | import ReactNotification from "react-notifications-component";
10 | import Footer from "./Footer";
11 | import { ToastContainer } from "react-toastify";
12 |
13 | import "react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator.min.css";
14 | import "react-bootstrap-table-next/dist/react-bootstrap-table2.min.css";
15 |
16 | import "react-notifications-component/dist/theme.css";
17 | import "react-toastify/dist/ReactToastify.css";
18 |
19 | import ReactTooltip from "react-tooltip";
20 |
21 | // import LineChart from "./Charts/LineChart";
22 | // import ResistanceCard from "./ResistanceCard";
23 |
24 | import Management from "../containers/Management";
25 | import Monitor from "../containers/Monitor";
26 | import Sidebar from "../containers/Sidebar";
27 | import AdminManagement from "../containers/AdminManagement";
28 | import AdminProfile from "../containers/AdminProfile";
29 | import DailyStats from "../containers/DailyStats";
30 | import Liquidity from "./Liquidity";
31 | import ManageKeys from "./ManageKeys";
32 | import LiquidityDetails from "./LiquidityDetails";
33 | // import OrderBookSharing from "../containers/OrderBookSharing";
34 |
35 | class App extends React.Component {
36 | renderSwitch() {
37 | if (this.props.auth.isLoggedIn) {
38 | return (
39 |
40 |
41 | {/* */}
42 |
43 | {/* */}
44 |
45 |
46 | {/* */}
47 | {/* */}
48 |
49 |
50 |
51 |
55 |
56 |
57 | );
58 | } else {
59 | return (
60 | <>
61 |
62 |
63 | {/* */}
64 |
65 |
66 |
67 | >
68 | );
69 | }
70 | }
71 |
72 | render() {
73 | return (
74 |
75 |
76 |
77 |
78 |
79 |
80 | {this.renderSwitch()}
81 | {/* */}
82 | {/* */}
83 |
84 | );
85 | }
86 | }
87 |
88 | function mapStateToProps({ auth }) {
89 | return { auth };
90 | }
91 |
92 | export default connect(mapStateToProps, null)(App);
93 |
--------------------------------------------------------------------------------
/client/src/components/Charts/LineChart.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import ChartistGraph from "react-chartist";
3 |
4 | let initalState = {
5 | // data: 0
6 | data: {
7 | labels: [1, 2, 3, 4, 5, 6, 7, 8],
8 | series: [[5, 9, 7, 8, 5, 3, 5, 11]],
9 | },
10 | options: {
11 | height: "50vh",
12 | showArea: true,
13 | },
14 | type: "Line",
15 | };
16 |
17 | class Chart extends Component {
18 | constructor(props) {
19 | super(props);
20 | this.state = initalState;
21 | }
22 |
23 | /**
24 | *
25 | */
26 |
27 | componentDidMount() {
28 | setInterval(() => {
29 | this.setState({
30 | data: {
31 | ...this.state.data,
32 | series: [
33 | this.state.data.series[0].map((e) => {
34 | return e + Math.sign(0.5 * Math.random()) * Math.random();
35 | }),
36 | ],
37 | },
38 | });
39 | }, 2000);
40 | }
41 |
42 | render() {
43 | return (
44 |
45 |
50 |
51 | );
52 | }
53 | }
54 |
55 | export default Chart;
56 |
--------------------------------------------------------------------------------
/client/src/components/EditCurrencyCard.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Form, Col, Button, InputGroup, FormControl } from "react-bootstrap";
3 |
4 | const EditCurrencyCard = (props) => {
5 | const [exchange, setExchange] = useState(props.exchange);
6 | const [symbol, setSymbol] = useState(props.symbol);
7 | const [name, setName] = useState(props.name);
8 | const [currencyId, setCurrencyId] = useState(props.currencyId);
9 | const [exchangeSymbol, setExchangeSymbol] = useState(props.exchangeSymbol);
10 | const [minimumBalance, setMinimumBalance] = useState(props.minimumBalance);
11 |
12 | return (
13 |
14 |
15 |
17 |
18 | setExchange(value)}
23 | />
24 |
25 |
26 | Exchange
27 |
28 |
29 |
30 |
31 | setSymbol(value)}
36 | />
37 |
38 |
39 | Symbol
40 |
41 |
42 |
43 |
44 | setName(value)}
49 | />
50 |
51 |
52 | Name
53 |
54 |
55 |
56 |
57 | setCurrencyId(value)}
62 | disabled
63 | />
64 |
65 |
66 | Currency Id
67 |
68 |
69 |
70 |
71 | setExchangeSymbol(value)}
76 | />
77 |
78 |
79 | Exchange Symbol
80 |
81 |
82 |
83 |
84 | setMinimumBalance(value)}
89 | />
90 |
91 |
92 | Min Balance
93 |
94 |
95 |
96 |
97 |
98 |
115 |
116 |
117 |
118 |
119 |
120 | );
121 | };
122 | export default EditCurrencyCard;
123 |
--------------------------------------------------------------------------------
/client/src/components/Exchange.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { connect } from "react-redux";
3 | import { RemoveExpo, CurrencyDecimalsAmount } from "../helpers/constant";
4 |
5 | class PairPriceClass extends Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | render() {
11 | let n = this.props.value;
12 | let pair = this.props.pair;
13 | let exchange = this.props.exchange;
14 |
15 | if (
16 | this.props.exchangeReducer.status &&
17 | this.props.exchangeReducer.status.exchangePairDecimals[exchange] &&
18 | this.props.exchangeReducer.status.exchangePairDecimals[exchange][pair]
19 | ) {
20 | n = parseFloat(n).toFixed(
21 | this.props.exchangeReducer.status.exchangePairDecimals[exchange][pair]
22 | .decimalsPrice
23 | );
24 | }
25 | return <>{RemoveExpo(n)}>;
26 | }
27 | }
28 |
29 | class PairAmountClass extends Component {
30 | constructor(props) {
31 | super(props);
32 | }
33 |
34 | render() {
35 | let n = this.props.value;
36 | let pair = this.props.pair;
37 | let exchange = this.props.exchange;
38 |
39 | let className = "";
40 |
41 | if (
42 | this.props.exchangeReducer.status &&
43 | this.props.exchangeReducer.status.exchangePairDecimals[exchange] &&
44 | this.props.exchangeReducer.status.exchangePairDecimals[exchange][pair]
45 | ) {
46 | n = parseFloat(n).toFixed(
47 | this.props.exchangeReducer.status.exchangePairDecimals[exchange][pair]
48 | .decimalsAmount
49 | );
50 | if (
51 | n <
52 | this.props.exchangeReducer.status.exchangePairDecimals[exchange][pair]
53 | .minAmount
54 | )
55 | className = "lighten";
56 | }
57 |
58 | return {RemoveExpo(n)};
59 | }
60 | }
61 |
62 | class CurrencyAmountClass extends Component {
63 | constructor(props) {
64 | super(props);
65 | }
66 |
67 | render() {
68 | let n = this.props.value;
69 | let currency = this.props.currency;
70 |
71 | let className = "";
72 |
73 | if (
74 | CurrencyDecimalsAmount[currency] !== null ||
75 | CurrencyDecimalsAmount[currency] !== undefined
76 | ) {
77 | n = parseFloat(n).toFixed(CurrencyDecimalsAmount[currency]);
78 | } else {
79 | n = parseFloat(n).toFixed(2);
80 | }
81 |
82 | return {RemoveExpo(n)};
83 | }
84 | }
85 |
86 | function mapStateToProps({ exchangeReducer }) {
87 | return { exchangeReducer };
88 | }
89 |
90 | const components = [PairAmountClass, PairPriceClass];
91 | const connectedComponents = components.map(connect(mapStateToProps));
92 | const [ConnectedPairAmount, ConnectedPairPrice] = connectedComponents;
93 |
94 | export const PairAmount = ConnectedPairAmount;
95 | export const PairPrice = ConnectedPairPrice;
96 | export const CurrencyAmount = CurrencyAmountClass;
97 |
--------------------------------------------------------------------------------
/client/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Container, Row, Col } from "react-bootstrap";
3 |
4 | function Footer() {
5 | return (
6 |
7 |
8 |
9 |
10 | About
11 |
12 |
13 | -
14 | CrypBot is a bot.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
26 | export default Footer;
27 |
--------------------------------------------------------------------------------
/client/src/components/FormHelper.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Row, Col, Card, Button, FormControl } from "react-bootstrap";
4 |
5 | export const RenderInput = (props) => {
6 | let labelCol = props.labelCol || 4;
7 | let labelColLg = props.labelColLg || labelCol;
8 | let labelColMd = props.labelColMd || labelColLg;
9 | let labelColSm = props.labelColSm || labelColMd;
10 |
11 | return (
12 |
13 |
14 | {props.label}
15 |
16 |
17 | {props.element}
18 |
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/client/src/components/IconCard.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Row, Col } from "react-bootstrap";
4 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5 | import { faCogs } from "@fortawesome/free-solid-svg-icons";
6 |
7 | export default function IconCard(props) {
8 | const className = "icon-card " + props.className || "";
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | {props.title}
17 | {props.text}
18 |
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/components/StaticTable.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import BootstrapTable from "react-bootstrap-table-next"; // React Bootstrap Table Next
4 | import paginationFactory, {
5 | PaginationProvider,
6 | PaginationListStandalone,
7 | } from "react-bootstrap-table2-paginator";
8 |
9 | class DataTable extends Component {
10 | constructor(props) {
11 | super(props);
12 | this.renderData = this.props.renderData.bind(this);
13 | }
14 |
15 | render() {
16 | let tableData = [];
17 | if (!this.props.data) {
18 | tableData = this.props.prepopulatedData;
19 | } else if (this.props.data && this.props.data.length === 0) {
20 | tableData = this.props.emptyData || [];
21 | } else {
22 | tableData =
23 | this.renderData(this.props.data) || this.props.prepopulatedData;
24 | }
25 | let columns = this.props.columns;
26 |
27 | return (
28 |
29 |
30 |
48 | {({ paginationProps, paginationTableProps }) => (
49 |
50 |
51 | {/*
*/}
52 |
53 |
60 |
61 |
{this.props.tableFooter || <>>}
62 |
63 | )}
64 |
65 |
66 |
67 | );
68 | }
69 | }
70 |
71 | export default DataTable;
72 |
--------------------------------------------------------------------------------
/client/src/components/SuperAdminComponent.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { connect } from "react-redux";
3 |
4 | class SuperAdminComponent extends Component {
5 | constructor(props) {
6 | super(props);
7 | }
8 |
9 | render() {
10 | let element = <>>;
11 | if (
12 | this.props.auth.isLoggedIn == true &&
13 | this.props.auth.data.level === 2
14 | ) {
15 | element = <>{this.props.element}>;
16 | }
17 | return <>{element}>;
18 | }
19 | }
20 |
21 | function mapStateToProps({ auth }) {
22 | return { auth };
23 | }
24 |
25 | export default connect(mapStateToProps, null)(SuperAdminComponent);
26 |
--------------------------------------------------------------------------------
/client/src/components/Wallet.js:
--------------------------------------------------------------------------------
1 | import { faCogs } from "@fortawesome/free-solid-svg-icons";
2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3 | import React, { Component } from "react";
4 | import { Card, Button } from "react-bootstrap";
5 | import { connect } from "react-redux";
6 |
7 | import * as actions from "../actions/index";
8 | import {
9 | AddDelimiter,
10 | GetDateLocalFormat,
11 | PairDecimalsAmount,
12 | } from "../helpers/constant";
13 | import StaticTable from "./StaticTable";
14 | import DataTable from "./DataTable";
15 |
16 | const initialState = { balances: { data: [], ts: null } };
17 |
18 | const rooms = ["wallet"];
19 |
20 | const columns = [
21 | {
22 | dataField: "exchange",
23 | text: "Exchange",
24 | },
25 | {
26 | dataField: "currency",
27 | text: "Currency",
28 | },
29 | // {
30 | // dataField: "account",
31 | // text: "Account",
32 | // },
33 | {
34 | dataField: "balance",
35 | text: "Balance",
36 | headerStyle: () => {
37 | return { width: "100px", textAlign: "left" };
38 | },
39 | },
40 | {
41 | dataField: "inTrade",
42 | text: "In Trade",
43 | headerStyle: () => {
44 | return { width: "100px", textAlign: "left" };
45 | },
46 | },
47 | {
48 | dataField: "total",
49 | text: "Total",
50 | headerStyle: () => {
51 | return { width: "100px", textAlign: "left" };
52 | },
53 | },
54 | ];
55 |
56 | const prepopulatedExchange = [
57 | {
58 | id: 1,
59 | exchange: (
60 |
64 | ),
65 | },
66 | ];
67 |
68 | const EmptyData = [
69 | {
70 | id: 1,
71 | exchange: (
72 |
75 | ),
76 | },
77 | ];
78 |
79 | class Wallet extends Component {
80 | constructor(props) {
81 | super(props);
82 |
83 | this.state = initialState;
84 | }
85 |
86 | componentDidMount() {
87 | this.props.connectSocket(rooms);
88 | }
89 |
90 | componentWillReceiveProps(nextProps) {
91 | if (nextProps.socketReducer.status !== "connected") {
92 | this.props.connectSocket(rooms);
93 | } else {
94 | if (this.props.socketReducer.socket)
95 | this.props.socketReducer.socket.removeAllListeners();
96 |
97 | nextProps.socketReducer.socket.emit("joinRooms", rooms);
98 |
99 | nextProps.socketReducer.socket.on("balances", (balances) => {
100 | const exchanges = Object.keys(balances);
101 | let data = [],
102 | ts;
103 | for (let exchange of exchanges) {
104 | data = data.concat(balances[exchange].data);
105 | ts = balances[exchange].ts;
106 | }
107 | this.setState({ balances: { data, ts } });
108 | });
109 | }
110 | }
111 |
112 | renderBalances(balances) {
113 | return balances.map((balance, i) => {
114 | return {
115 | id: i,
116 | // account: balance.botName,
117 | exchange: balance.exchange,
118 | currency: balance.currency,
119 | inTrade: AddDelimiter(
120 | parseFloat(balance.inTrade).toFixed(
121 | PairDecimalsAmount[`${balance.currency}-USDT`]
122 | )
123 | ),
124 | balance:
125 | balance.balance >= balance.minBalance ? (
126 |
127 | {AddDelimiter(
128 | parseFloat(balance.balance).toFixed(
129 | PairDecimalsAmount[`${balance.currency}-USDT`]
130 | )
131 | )}
132 |
133 | ) : (
134 |
135 | {AddDelimiter(
136 | parseFloat(balance.balance).toFixed(
137 | PairDecimalsAmount[`${balance.currency}-USDT`]
138 | )
139 | )}
140 |
141 | ),
142 | total: AddDelimiter(
143 | parseFloat(balance.total).toFixed(
144 | PairDecimalsAmount[`${balance.currency}-USDT`]
145 | )
146 | ),
147 | };
148 | });
149 | }
150 |
151 | render() {
152 | return (
153 | <>
154 |
155 | {this.props.header || ""}
156 |
157 |
165 |
166 |
167 |
168 |
169 | Last Updatded:{" "}
170 | {this.state.balances.ts
171 | ? GetDateLocalFormat(this.state.balances.ts)
172 | : "loading"}
173 |
174 |
175 |
182 |
183 |
184 | >
185 | );
186 | }
187 | }
188 |
189 | function mapStateToProps({ socketReducer, exchangeReducer }) {
190 | return { socketReducer, exchangeReducer };
191 | }
192 |
193 | function mapDispatchToProps(dispatch) {
194 | return {
195 | connectSocket: () => dispatch(actions.ConnectSocket()),
196 | };
197 | }
198 | export default connect(mapStateToProps, mapDispatchToProps)(Wallet);
199 |
--------------------------------------------------------------------------------
/client/src/containers/AdminManagement.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Row, Card, Col, Form, Button } from "react-bootstrap";
3 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4 | import { faCogs } from "@fortawesome/free-solid-svg-icons";
5 | import StaticTable from "../components/StaticTable";
6 | import { RenderInput } from "../components/FormHelper";
7 | import * as actions from "../actions/index";
8 | import { connect } from "react-redux";
9 | import { AddNoti } from "../helpers/Notification";
10 | import { Capitalize } from "../helpers/constant";
11 |
12 | const columns = [
13 | {
14 | dataField: "email",
15 | text: "Email",
16 | headerStyle: () => {
17 | return { width: "150px" };
18 | },
19 | },
20 | {
21 | dataField: "name",
22 | text: "Name",
23 | },
24 | {
25 | dataField: "level",
26 | text: "Level",
27 | },
28 | {
29 | dataField: "alert",
30 | text: "Alert",
31 | },
32 | ];
33 |
34 | const prepopulatedAdmin = [
35 | {
36 | id: 1,
37 | level: (
38 |
42 | ),
43 | },
44 | ];
45 |
46 | const EmptyData = [
47 | {
48 | id: 1,
49 | level: (
50 |
53 | ),
54 | },
55 | ];
56 |
57 | const initialState = {
58 | addAdmin: null,
59 | removeAdmin: null,
60 | };
61 | class AdminManagement extends Component {
62 | constructor(props) {
63 | super(props);
64 | this.state = initialState;
65 | }
66 |
67 | componentDidMount() {
68 | this.props.getAdmin();
69 | }
70 |
71 | componentDidUpdate(prevProps) {
72 | let data = Object.keys(this.props.adminReducer);
73 | for (let i = 0; i < data.length; i++) {
74 | let adminData = this.props.adminReducer[data[i]];
75 | if (
76 | adminData.success &&
77 | prevProps.adminReducer[data[i]].v !== adminData.v
78 | ) {
79 | AddNoti(adminData.success, { type: "info", position: "bottom-right" });
80 | if (data[i] !== "status") this.props.getAdmin();
81 | }
82 | if (adminData.error && prevProps.adminReducer[data[i]].v !== adminData.v) {
83 | AddNoti(adminData.error, { type: "error", position: "bottom-right" });
84 | if (data[i] !== "status") this.props.getAdmin();
85 | }
86 | }
87 | }
88 |
89 | renderAdminData(allData) {
90 | if (!allData || allData.length === 0) {
91 | return EmptyData;
92 | }
93 | return allData.map((e, i) => {
94 | return {
95 | id: i,
96 | email: e.email,
97 | name: Capitalize(e.name),
98 | level: e.level,
99 | alert: e.alerts || 0,
100 | };
101 | });
102 |
103 | }
104 |
105 | render() {
106 | return (
107 |
108 |
Admin Management
109 |
110 |
111 |
112 | Admin Info
113 |
114 |
120 |
121 |
122 |
123 |
124 |
125 | Add Admin
126 |
154 |
155 |
156 | Remove Admin
157 |
187 |
188 |
189 |
190 |
191 | );
192 | }
193 | }
194 |
195 | function mapStateToProps({ adminReducer }) {
196 | return { adminReducer };
197 | }
198 |
199 | function mapDispathToProps(dispatch) {
200 | return {
201 | getAdmin: () => dispatch(actions.GetAdmin()),
202 | addAdmin: (data) => dispatch(actions.AddAdmin(data)),
203 | removeAdmin: (data) => dispatch(actions.RemoveAdmin(data)),
204 | };
205 | }
206 | export default connect(mapStateToProps, mapDispathToProps)(AdminManagement);
207 |
--------------------------------------------------------------------------------
/client/src/containers/AdminProfile.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import * as actions from "../actions/index";
3 | import { connect } from "react-redux";
4 | import { AddNoti } from "../helpers/Notification";
5 | import { Row, Card, Col, Form, Button, FormControl } from "react-bootstrap";
6 | import { RenderInput } from "../components/FormHelper";
7 | import { alertLevel } from "../helpers/constant";
8 |
9 | const initialState = {
10 | alertLevel: null,
11 | name: null,
12 | email: null,
13 | };
14 |
15 | class AdminProfile extends Component {
16 | constructor(props) {
17 | super(props);
18 | this.state = initialState;
19 | }
20 |
21 | componentDidUpdate(prevProps) {
22 | let data = this.props.adminProfileReducer.updateProfile;
23 | if (
24 | data.success &&
25 | prevProps.adminProfileReducer.updateProfile.v !== data.v
26 | ) {
27 | AddNoti(data.success, { type: "info", position: "bottom-right" });
28 | }
29 | if (
30 | data.error &&
31 | prevProps.adminProfileReducer.updateProfile.v !== data.v
32 | ) {
33 | AddNoti(data.error, { type: "error", position: "bottom-right" });
34 | }
35 | // if (this.props.auth.success && prevProps.auth.v !== this.props.auth.v) {
36 | // AddNoti(this.props.auth.success, { type: "info", position: "bottom-right" });
37 | // }
38 | // if (this.props.auth.error && prevProps.auth.v !== this.props.auth.v) {
39 | // AddNoti(this.props.auth.error, { type: "info", position: "bottom-right" });
40 | // }
41 | }
42 |
43 | render() {
44 |
45 | if (
46 | this.props.auth &&
47 | this.props.auth.data
48 | ) {
49 | var name = this.props.auth.data.name;
50 | var email = this.props.auth.data.email;
51 | var alerts = this.props.auth.data.alerts;
52 | var level = this.props.auth.data.level;
53 | }
54 |
55 | return (
56 |
57 |
58 |
59 |
60 | Admin Alert Level
61 |
93 |
94 |
95 |
96 |
97 | Admin Profile Info
98 |
99 |
145 |
146 |
147 |
148 |
149 |
150 | );
151 | }
152 | }
153 |
154 | function mapStateToProps({ auth, adminProfileReducer }) {
155 | return { auth, adminProfileReducer };
156 | }
157 |
158 | function mapDispathToProps(dispatch) {
159 | return {
160 | updateMailProfile: (data) => dispatch(actions.UpdateMailProfile(data)),
161 | };
162 | }
163 | export default connect(mapStateToProps, mapDispathToProps)(AdminProfile);
164 |
--------------------------------------------------------------------------------
/client/src/containers/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { connect } from "react-redux";
3 | import { Redirect, Switch, Route } from "react-router-dom";
4 |
5 | class DashboardContainer extends Component {
6 | componentWillMount() {}
7 |
8 | render() {
9 | if (this.props.auth.isLoggedIn === true) {
10 | return ;
11 | } else {
12 | return ;
13 | }
14 | }
15 | }
16 |
17 | function mapStateToProps({ auth, siteStats }) {
18 | return { auth, siteStats };
19 | }
20 |
21 | export default connect(mapStateToProps, null)(DashboardContainer);
22 |
--------------------------------------------------------------------------------
/client/src/containers/Header.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { connect } from "react-redux";
3 | import * as actions from "../actions/index";
4 | import { Navbar, Nav, NavDropdown } from "react-bootstrap";
5 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
6 | import {
7 | faUser,
8 | faPowerOff,
9 | faDesktop,
10 | faRobot,
11 | } from "@fortawesome/free-solid-svg-icons";
12 | import RouteButton from "../hooks/RouteButton";
13 |
14 | const initialAuth = localStorage.getItem("corp-auth-status");
15 |
16 | const AppName = process.env.REACT_APP_NAME || "CrypBot";
17 |
18 | class Header extends Component {
19 | constructor(props) {
20 | super(props);
21 |
22 | this.renderAccount = this.renderAccount.bind(this);
23 | this.renderLogin = this.renderLogin.bind(this);
24 | }
25 |
26 | componentWillMount() {
27 | this.props.fetchUserStatus();
28 | }
29 |
30 | componentDidUpdate() {
31 | if (this.props.auth.isLoggedIn === true) this.props.connectSocket();
32 | }
33 |
34 | renderLogin() {
35 | return (
36 |
37 |
49 |
50 | );
51 | }
52 |
53 | renderAccount() {
54 | return (
55 |
56 |
87 |
88 | );
89 | }
90 |
91 | render() {
92 | const vert_align = {
93 | display: "flex",
94 | flexDirection: "column",
95 | };
96 |
97 | return (
98 |
99 |
100 |
105 |
106 |
107 | {AppName}
108 |
109 | >
110 | }
111 | />
112 |
113 |
114 |
118 | {this.props.auth
119 | ? this.props.auth.isLoggedIn === true
120 | ? this.renderAccount()
121 | : this.renderLogin()
122 | : initialAuth == "true"
123 | ? this.renderAccount()
124 | : this.renderLogin()}
125 |
126 |
127 |
128 | );
129 | }
130 | }
131 |
132 | function mapStateToProps({ auth }) {
133 | return { auth };
134 | }
135 |
136 | function mapDispatchToProps(dispatch) {
137 | return {
138 | logout: () => dispatch(actions.logout()),
139 | fetchUserStatus: () => dispatch(actions.fetchUserStatus()),
140 | connectSocket: () => dispatch(actions.ConnectSocket()),
141 | };
142 | }
143 |
144 | export default connect(mapStateToProps, mapDispatchToProps)(Header);
145 |
--------------------------------------------------------------------------------
/client/src/containers/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { connect } from "react-redux";
3 | import { Redirect } from "react-router-dom";
4 | import { Form, Button, Container, Row, Col } from "react-bootstrap";
5 | import { AddNoti } from "../helpers/Notification";
6 | import RequireLogin from "../middleware/RequireLogin";
7 | import { GetParamValue } from "../helpers/constant";
8 | import RequireLogout from "../middleware/RequireLogout";
9 |
10 | import * as actions from "../actions/index";
11 |
12 | const initialState = {
13 | email: "",
14 | password: "",
15 | redirect: false,
16 | redirectTo: "/",
17 | error: null,
18 | success: null,
19 | };
20 |
21 | class SignUp extends Component {
22 | constructor(props) {
23 | super(props);
24 | this.state = initialState;
25 | this.companyLogoInput = React.createRef();
26 |
27 | this.handleLogInPost = this.handleLogInPost.bind(this);
28 | this.renderRedirect = this.renderRedirect.bind(this);
29 | }
30 |
31 | setRedirect = () => {
32 | this.setState({
33 | redirect: true,
34 | });
35 | };
36 |
37 | renderRedirect = () => {
38 | if (this.state.redirect) {
39 | return ;
40 | }
41 | };
42 |
43 | handleLogInPost() {
44 | this.props.login({
45 | email: this.state.email,
46 | password: this.state.password,
47 | });
48 | }
49 |
50 | componentWillReceiveProps(nextProps) {
51 | let { success, error, v } = nextProps.auth;
52 |
53 | // console.log(":login :auth", v, this.props.auth.v, error);
54 |
55 | if (success && v !== this.props.auth.v) {
56 | AddNoti("Welcome", { type: "success" });
57 | }
58 |
59 | if (error && v !== this.props.auth.v) {
60 | AddNoti(error, { type: "error" });
61 | }
62 | }
63 |
64 | render() {
65 | let { loading, isLoggedIn } = this.props.auth;
66 | let btnMsg = "Submit";
67 |
68 | if (loading) {
69 | btnMsg = "loading";
70 | }
71 |
72 | if (isLoggedIn) {
73 | this.setState({ redirect: true, redirectTo: "/liquidity" });
74 | }
75 |
76 | return (
77 |
78 | {/*
*/}
79 | {this.renderRedirect()}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
Log In
87 |
88 |
89 |
91 | Email address
92 | {
97 | this.setState({ email: e.target.value });
98 | }}
99 | />
100 |
101 |
102 |
103 | Password
104 | {
109 | this.setState({ password: e.target.value });
110 | }}
111 | />
112 |
113 |
114 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | );
131 | }
132 | }
133 |
134 | function mapStateToProps({ auth }) {
135 | return { auth };
136 | }
137 |
138 | function mapDispathToProps(dispatch) {
139 | return {
140 | login: (data) => dispatch(actions.login(data)),
141 | };
142 | }
143 |
144 | export default connect(mapStateToProps, mapDispathToProps)(SignUp);
145 |
--------------------------------------------------------------------------------
/client/src/containers/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { connect } from "react-redux";
3 | import { Button } from "react-bootstrap";
4 |
5 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
6 | import {
7 | faBookOpen,
8 | faGlobe,
9 | faChartArea,
10 | faGripLines,
11 | faUserShield,
12 | faAnkh,
13 | faPoll,
14 | faUserLock,
15 | faUserCog,
16 | faPercent,
17 | faCalendarDay,
18 | faBahai,
19 | faDollarSign,
20 | faKey,
21 | } from "@fortawesome/free-solid-svg-icons";
22 |
23 | import SuperAdminComponent from "../components/SuperAdminComponent";
24 |
25 | import RouteButton from "../hooks/RouteButton";
26 |
27 | class Sidebar extends React.Component {
28 | constructor() {
29 | super();
30 |
31 | this.state = {
32 | sidebarCollapsed: false,
33 | activeLink: null,
34 | };
35 | }
36 |
37 | renderRouteButton(title, icon, to, onClick = null) {
38 | let className = "sidebar-nav";
39 |
40 | const url = document.location.pathname;
41 |
42 | if (url === to) {
43 | className += " sidebar-nav__active";
44 | }
45 |
46 | return (
47 |
50 |
51 |
52 |
53 | {title}
54 |
55 | }
56 | to={to}
57 | onClick={onClick}
58 | />
59 | );
60 | }
61 |
62 | render() {
63 | let sidebarClass = "sidebar";
64 |
65 | if (!this.state.sidebarCollapsed) {
66 | sidebarClass += " sidebar-open";
67 | }
68 |
69 | if (!this.props.auth.isLoggedIn) sidebarClass += " sidebar-none";
70 | return (
71 |
72 |
73 | {this.renderRouteButton(
74 | "Add Liquidity",
75 | faDollarSign,
76 | "/liquidity",
77 | () => {
78 | this.setState({ activeLink: "/liquidity" });
79 | }
80 | )}
81 |
82 | {this.renderRouteButton(
83 | "Management",
84 | faUserShield,
85 | "/management",
86 | () => {
87 | this.setState({ activeLink: "/management" });
88 | }
89 | )}
90 |
91 | {this.renderRouteButton("Manage Keys", faKey, "/manage-keys", () =>
92 | this.setState({ activeLink: "/manage-keys" })
93 | )}
94 |
95 | {/* {this.renderRouteButton(
96 | "Admin Profile",
97 | faUserCog,
98 | "/admin-profile",
99 | () => {
100 | this.setState({ activeLink: "/admin-profile" });
101 | }
102 | )} */}
103 |
104 | {this.renderRouteButton(
105 | "Daily Stats",
106 | faCalendarDay,
107 | "/daily-stats",
108 | () => {
109 | this.setState({ activeLink: "/daily-stats" });
110 | }
111 | )}
112 |
113 | {/* {
119 | this.setState({ activeLink: "/admin-management" });
120 | }
121 | )}
122 | /> */}
123 |
124 | {this.renderRouteButton("Monitor", faChartArea, "/monitor", () => {
125 | this.setState({ activeLink: "/monitor" });
126 | })}
127 |
128 |
129 |
130 |
149 |
150 |
151 | );
152 | }
153 | }
154 |
155 | function mapStateToProps({ auth }) {
156 | return { auth };
157 | }
158 |
159 | export default connect(mapStateToProps, null)(Sidebar);
160 |
--------------------------------------------------------------------------------
/client/src/containers/Signup.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Formdata from "form-data";
3 | import { Redirect } from "react-router-dom";
4 | import { Form, Button, Container, Row, Col } from "react-bootstrap";
5 | import RequireLogout from "../middleware/RequireLogout";
6 |
7 | import { AxiosInstance, PostConfig } from "../helpers/constant";
8 |
9 | import { AddNoti } from "../helpers/Notification";
10 | import ScrollToTop from "../hooks/ScrollToTop";
11 | import { ParseError } from "../helpers/ResponseHelper";
12 |
13 | const initialState = {
14 | name: "",
15 | email: "",
16 | password: "",
17 | confirmPassword: "",
18 | redirect: false,
19 | redirectTo: "/",
20 | };
21 |
22 | class SignUp extends Component {
23 | constructor(props) {
24 | super(props);
25 | this.state = initialState;
26 | this.companyLogoInput = React.createRef();
27 |
28 | this.handleSignUpPost = this.handleSignUpPost.bind(this);
29 | this.renderRedirect = this.renderRedirect.bind(this);
30 | }
31 |
32 | handleSignUpPost() {
33 | const email = this.state.email;
34 | const password = this.state.password;
35 |
36 | const newForm = {
37 | name: this.state.name,
38 | email,
39 | password,
40 | };
41 |
42 | AxiosInstance.post("/admin/sign-up", newForm, PostConfig)
43 | .then((resp) => {
44 | resp = resp.data;
45 | if (resp.statusCode === 201) {
46 | AddNoti("Please login to continue!", {
47 | type: "success",
48 | });
49 | this.setState({
50 | ...initialState,
51 | redirect: true,
52 | redirectTo: "/login",
53 | });
54 | } else {
55 | AddNoti(resp.error || resp.message, {
56 | type: "error",
57 | });
58 | }
59 | })
60 | .catch((e) => {
61 | AddNoti(ParseError(e), {
62 | type: "error",
63 | });
64 | });
65 | }
66 |
67 | renderRedirect = () => {
68 | if (this.state.redirect) {
69 | return ;
70 | }
71 | };
72 |
73 | render() {
74 | return (
75 |
76 |
77 | {/*
*/}
78 | {this.renderRedirect()}
79 |
80 |
81 |
82 |
83 |
84 |
85 |
Sign Up
86 |
87 |
88 |
90 | Name
91 | {
96 | this.setState({ name: e.target.value });
97 | }}
98 | />
99 |
100 |
101 |
102 | Email address
103 | {
108 | this.setState({ email: e.target.value });
109 | }}
110 | />
111 |
112 |
113 |
114 | Password
115 | {
120 | this.setState({ password: e.target.value });
121 | }}
122 | />
123 |
124 |
125 |
126 | Confirm Password
127 | {
132 | this.setState({ confirmPassword: e.target.value });
133 | }}
134 | />
135 |
136 |
137 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | );
154 | }
155 | }
156 |
157 | export default SignUp;
158 |
--------------------------------------------------------------------------------
/client/src/helpers/Notification.js:
--------------------------------------------------------------------------------
1 | import { store } from "react-notifications-component";
2 | import { toast } from "react-toastify";
3 |
4 | export const AddNoti = (
5 | msg,
6 | {
7 | type = "info",
8 | position = "top-right",
9 | duration = 2000,
10 | hideProgressBar = false,
11 | closeOnClick = true,
12 | closeButton=true
13 | }
14 | ) => {
15 | return toast(msg, {
16 | type: type,
17 | position,
18 | autoClose: duration,
19 | className: "custom-toast",
20 | hideProgressBar,
21 | closeOnClick,
22 | closeButton
23 | });
24 |
25 | // store.addNotification({
26 | // id: id,
27 | // title: title,
28 | // message: msg,
29 | // type: type,
30 | // insert: "top",
31 | // container: container,
32 | // animationIn: ["animated", "fadeIn"],
33 | // animationOut: ["animated", "fadeOut"],
34 | // dismiss: dismiss,
35 | // });
36 | };
37 |
38 | export const RemoveNoti = (id) => {
39 | toast.dismiss(id);
40 | };
41 |
--------------------------------------------------------------------------------
/client/src/helpers/PaymentModal.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Modal from "react-bootstrap/Modal";
3 | import { Row, Col, Container, Button } from "react-bootstrap";
4 |
5 | function PaymentModal(props) {
6 | return (
7 |
15 |
16 |
17 | Select Payment Mode
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 |
36 | export default PaymentModal;
37 |
--------------------------------------------------------------------------------
/client/src/helpers/ResponseHelper.js:
--------------------------------------------------------------------------------
1 | const DefaulErrortMsg = "Something went wrong";
2 | const DefaultSuccessMsg = "Success";
3 |
4 | export const ParseError = (e) => {
5 | if (e.errors) {
6 | return e.errors[0].field
7 | ? `${e.errors[0].field}: ${e.errors[0].message}`
8 | : e.errors[0].message;
9 | }
10 | return e
11 | ? e.response
12 | ? e.response.data
13 | ? e.response.data.errors
14 | ? e.response.data.errors[0].field
15 | ? `${e.response.data.errors[0].field}: ${e.response.data.errors[0].message}`
16 | : e.response.data.errors[0].message
17 | : DefaulErrortMsg
18 | : DefaulErrortMsg
19 | : e.message
20 | ? e.message
21 | : DefaulErrortMsg
22 | : DefaulErrortMsg;
23 | };
24 |
25 | export const ParseSuccess = (e) => {
26 | return e.response
27 | ? e.response.data
28 | ? e.response.data.message
29 | : DefaultSuccessMsg
30 | : DefaultSuccessMsg;
31 | };
32 |
--------------------------------------------------------------------------------
/client/src/helpers/withRouter.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useParams } from "react-router-dom";
3 |
4 | const withRouter = (WrappedComponent) => (props) => {
5 | const params = useParams();
6 |
7 | return ;
8 | };
9 |
10 | export default withRouter;
11 |
--------------------------------------------------------------------------------
/client/src/hooks/RouteButton.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useHistory } from "react-router-dom";
3 |
4 | function RouteButton(props) {
5 | const history = useHistory();
6 | let finalClassName = "";
7 |
8 | function handleClick() {
9 | history.push(props.to);
10 | }
11 |
12 | if (props.className !== undefined) {
13 | finalClassName = `route-btn ${props.className}`;
14 | } else {
15 | finalClassName = "route-btn";
16 | }
17 |
18 | return (
19 | {
22 | handleClick();
23 | if (props.onClick) props.onClick();
24 | }}
25 | >
26 | {props.value}
27 |
28 | );
29 | }
30 |
31 | export default RouteButton;
32 |
33 | export const RedirectTo = (to) => {
34 | const history = useHistory();
35 | history.push(to);
36 | };
37 |
--------------------------------------------------------------------------------
/client/src/hooks/ScrollToTop.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useLocation } from "react-router-dom";
3 |
4 | export default function ScrollToTop() {
5 | const { pathname } = useLocation();
6 |
7 | useEffect(() => {
8 | window.scrollTo(0, 0);
9 | }, [pathname]);
10 |
11 | return null;
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import { Provider } from "react-redux";
4 | import { BrowserRouter as Router } from "react-router-dom";
5 |
6 | import App from "./components/App";
7 | import * as serviceWorker from "./serviceWorker";
8 | import reduxStore from "./redux/store";
9 | import { createBrowserHistory } from "history";
10 | import { AppContainer } from "react-hot-loader";
11 |
12 | import "react-datepicker/dist/react-datepicker.css";
13 |
14 | const customHistory = createBrowserHistory();
15 |
16 | const store = reduxStore();
17 |
18 | ReactDOM.render(
19 |
20 |
21 |
22 |
23 |
24 |
25 | ,
26 | document.getElementById("root")
27 | );
28 |
29 | if (module.hot) {
30 | module.hot.accept("./components/App", () => {
31 | const NextApp = require("./components/App").default;
32 |
33 | ReactDOM.render(
34 |
35 |
36 | ,
37 | document.getElementById("root")
38 | );
39 | });
40 | }
41 | serviceWorker.unregister();
42 |
--------------------------------------------------------------------------------
/client/src/middleware/RequireLogin.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Redirect } from "react-router-dom";
3 |
4 | function RequireLogin() {
5 | const currPath = document.location.pathname;
6 | const toLink = `/login?from=${currPath.slice(1)}`;
7 | const initialAuth = localStorage.getItem("corp-auth-status") == "true";
8 |
9 | // console.log("INSIDE RequireLogin: ", currPath, toLink, initialAuth);
10 |
11 | if (initialAuth === false) {
12 | return (
13 | <>
14 |
15 | >
16 | );
17 | } else {
18 | return <>>;
19 | }
20 | }
21 |
22 | export default RequireLogin;
23 |
--------------------------------------------------------------------------------
/client/src/middleware/RequireLogout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Redirect } from "react-router-dom";
3 |
4 | function RequireLogout() {
5 | const currPath = document.location.pathname;
6 | const toLink = `/`;
7 | const initialAuth = localStorage.getItem("corp-auth-status") == "true";
8 |
9 | if (initialAuth === true) {
10 | return (
11 | <>
12 |
13 | >
14 | );
15 | } else {
16 | return <>>;
17 | }
18 | }
19 |
20 | export default RequireLogout;
21 |
--------------------------------------------------------------------------------
/client/src/reducers/AdminProfileReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialState = {
4 | updateProfile: {
5 | success: null,
6 | error: null,
7 | loading: false,
8 | data: null,
9 | ts: null,
10 | v: 0,
11 | }
12 | }
13 |
14 | export default function (state = initialState, action) {
15 | switch (action.type) {
16 | case types.UPDATE_ADMIN_PROFILE_START: {
17 | return {
18 | ...state,
19 | updateProfile: {
20 | ...state.updateProfile,
21 | loading: true,
22 | success: null,
23 | error: null
24 | }
25 | }
26 | }
27 |
28 | case types.UPDATE_ADMIN_PROFILE_SUCCESS: {
29 | return {
30 | ...state,
31 | updateProfile: {
32 | ...state.updateProfile,
33 | loading: false,
34 | success: action.success,
35 | data: action.data,
36 | v: state.updateProfile.v + 1
37 | }
38 | }
39 | }
40 |
41 | case types.UPDATE_ADMIN_PROFILE_FAIL: {
42 | return {
43 | ...state,
44 | updateProfile: {
45 | ...state.updateProfile,
46 | data: null,
47 | error: action.error,
48 | v: state.updateProfile.v + 1
49 | }
50 | }
51 | }
52 |
53 | case types.UPDATE_ADMIN_PROFILE_FINISH: {
54 | return {
55 | ...state,
56 | updateProfile: {
57 | ...state.updateProfile,
58 | ts: Date.now(),
59 | }
60 | }
61 | }
62 | default:
63 | return state;
64 | }
65 | }
--------------------------------------------------------------------------------
/client/src/reducers/AdminReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialState = {
4 | status: {
5 | success: null,
6 | error: null,
7 | loading: false,
8 | data: null,
9 | ts: null,
10 | v: 0,
11 | },
12 | addAdmin: {
13 | success: null,
14 | error: null,
15 | loading: false,
16 | data: null,
17 | ts: null,
18 | v: 0,
19 | },
20 | removeAdmin: {
21 | success: null,
22 | error: null,
23 | loading: false,
24 | data: null,
25 | ts: null,
26 | v: 0,
27 | },
28 | };
29 |
30 | export default function (state = initialState, action) {
31 | switch (action.type) {
32 | case types.GET_ADMIN_START: {
33 | return {
34 | ...state,
35 | status: {
36 | ...state.status,
37 | loading: true,
38 | success: null,
39 | error: null,
40 | },
41 | };
42 | }
43 | case types.GET_ADMIN_SUCCESS: {
44 | return {
45 | ...state,
46 | status: {
47 | ...state.status,
48 | loading: false,
49 | success: action.success,
50 | data: action.data,
51 | v: state.status.v + 1,
52 | },
53 | };
54 | }
55 | case types.GET_ADMIN_FAIL: {
56 | return {
57 | ...state,
58 | status: {
59 | ...state.status,
60 | data: null,
61 | success: null,
62 | error: action.error,
63 | v: state.status.v + 1,
64 | },
65 | };
66 | }
67 | case types.GET_ADMIN_FINISH: {
68 | return {
69 | ...state,
70 | status: {
71 | ...state.status,
72 | ts: Date.now(),
73 | },
74 | };
75 | }
76 | case types.ADD_ADMIN_START: {
77 | return {
78 | ...state,
79 | addAdmin: {
80 | ...state.addAdmin,
81 | loading: true,
82 | success: null,
83 | error: null,
84 | },
85 | };
86 | }
87 | case types.ADD_ADMIN_SUCCESS: {
88 | return {
89 | ...state,
90 | addAdmin: {
91 | ...state.addAdmin,
92 | loading: false,
93 | success: action.success,
94 | data: action.data,
95 | v: state.addAdmin.v + 1,
96 | },
97 | };
98 | }
99 | case types.ADD_ADMIN_FAIL: {
100 | return {
101 | ...state,
102 | addAdmin: {
103 | ...state.addAdmin,
104 | data: null,
105 | success: null,
106 | error: action.error,
107 | v: state.addAdmin.v + 1,
108 | },
109 | };
110 | }
111 | case types.ADD_ADMIN_FINISH: {
112 | return {
113 | ...state,
114 | addAdmin: {
115 | ...state.addAdmin,
116 | ts: Date.now(),
117 | },
118 | };
119 | }
120 | case types.REMOVE_ADMIN_START: {
121 | return {
122 | ...state,
123 | removeAdmin: {
124 | ...state.removeAdmin,
125 | loading: true,
126 | success: null,
127 | data: null,
128 | },
129 | };
130 | }
131 | case types.REMOVE_ADMIN_SUCCESS: {
132 | return {
133 | ...state,
134 | removeAdmin: {
135 | ...state.removeAdmin,
136 | success: action.success,
137 | data: action.data,
138 | v: state.removeAdmin.v + 1,
139 | },
140 | };
141 | }
142 | case types.REMOVE_ADMIN_FAIL: {
143 | return {
144 | ...state,
145 | removeAdmin: {
146 | ...state.removeAdmin,
147 | data: null,
148 | success: null,
149 | error: action.error,
150 | v: state.removeAdmin.v + 1,
151 | },
152 | };
153 | }
154 | case types.REMOVE_ADMIN_FINISH: {
155 | return {
156 | ...state,
157 | removeAdmin: {
158 | ...state.removeAdmin,
159 | ts: Date.now(),
160 | },
161 | };
162 | }
163 | default:
164 | return state;
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/client/src/reducers/ArbitrageReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialData = {
4 | status: {
5 | success: null,
6 | error: null,
7 | data: null,
8 | loading: false,
9 | ts: null,
10 | v: 0,
11 | },
12 | };
13 |
14 | export default function (state = initialData, action) {
15 | switch (action.type) {
16 | case types.GET_ARBITRAGE_START: {
17 | return {
18 | ...state,
19 | status: {
20 | ...state.status,
21 | loading: true,
22 | success: null,
23 | error: null,
24 | },
25 | };
26 | }
27 |
28 | case types.GET_ARBITRAGE_SUCCESS: {
29 | return {
30 | ...state,
31 | status: {
32 | ...state.status,
33 | loading: false,
34 | success: action.success,
35 | data: action.data,
36 | v: state.status.v + 1,
37 | },
38 | };
39 | }
40 |
41 | case types.GET_ARBITRAGE_FAIL: {
42 | return {
43 | ...state,
44 | status: {
45 | ...state.status,
46 | data: null,
47 | error: action.error,
48 | v: state.status.v + 1,
49 | },
50 | };
51 | }
52 |
53 | case types.GET_ARBITRAGE_FINISH: {
54 | return {
55 | ...state,
56 | status: {
57 | ...state.status,
58 | ts: Date.now(),
59 | },
60 | };
61 | }
62 |
63 | /**
64 | *
65 | *
66 | *
67 | *
68 | *
69 | *
70 | */
71 |
72 | default:
73 | return state;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/client/src/reducers/Auth.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialData = {
4 | success: null,
5 | error: null,
6 | data: null,
7 | loading: false,
8 | ts: null,
9 | isLoggedIn: localStorage.getItem("crypbot_auth") || false,
10 | v: 0,
11 | };
12 |
13 | export default function (state = initialData, action) {
14 | switch (action.type) {
15 | case types.LOGIN_START: {
16 | return {
17 | ...state,
18 | loading: true,
19 | success: null,
20 | error: null,
21 | ts: Date.now(),
22 | };
23 | }
24 | case types.LOGIN_SUCCESS: {
25 | localStorage.setItem("crypbot_auth", true);
26 | return {
27 | ...state,
28 | success: action.success || null,
29 | data: action.data,
30 | error: null,
31 | isLoggedIn: true,
32 | v: state.v + 1,
33 | };
34 | }
35 |
36 | case types.LOGIN_FAIL: {
37 | return {
38 | ...state,
39 | success: null,
40 | error: action.error,
41 | v: state.v + 1,
42 | };
43 | }
44 |
45 | case types.LOGIN_FINISH: {
46 | return {
47 | ...state,
48 | loading: false,
49 | ts: Date.now(),
50 | error: null,
51 | success: null,
52 | };
53 | }
54 |
55 | case types.LOGOUT_SUCCESS: {
56 | localStorage.setItem("crypbot_auth", false);
57 | return {
58 | ...state,
59 | isLoggedIn: false,
60 | ts: Date.now(),
61 | };
62 | }
63 |
64 | default:
65 | return state;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/client/src/reducers/DailyStatsReducer.js:
--------------------------------------------------------------------------------
1 | import { actions } from "react-table";
2 | import * as types from "../actions/types";
3 |
4 | const initialState = {
5 | getStatsTime: {
6 | success: null,
7 | error: null,
8 | loading: false,
9 | data: null,
10 | ts: null,
11 | v: 0,
12 | },
13 | getStatsData: {
14 | success: null,
15 | error: null,
16 | loading: false,
17 | data: null,
18 | ts: null,
19 | v: 0,
20 | },
21 | };
22 |
23 | export default function (state = initialState, action) {
24 | switch (action.type) {
25 | case types.GET_DAILY_STATS_TIME_START: {
26 | return {
27 | ...state,
28 | getStatsTime: {
29 | ...state.getStatsTime,
30 | success: null,
31 | error: null,
32 | loading: true
33 | }
34 | };
35 | }
36 | case types.GET_DAILY_STATS_TIME_SUCCESS: {
37 | return {
38 | ...state,
39 | getStatsTime: {
40 | ...state.getStatsTime,
41 | loading: false,
42 | success: action.success,
43 | data: action.data,
44 | v: state.getStatsTime.v + 1
45 | }
46 | };
47 | }
48 | case types.GET_DAILY_STATS_TIME_FAIL: {
49 | return {
50 | ...state,
51 | getStatsTime: {
52 | data: null,
53 | error: action.error,
54 | v: state.getStatsTime.v + 1
55 | }
56 | };
57 | }
58 | case types.GET_DAILY_STATS_TIME_FINISH: {
59 | return {
60 | ...state,
61 | getStatsTime: {
62 | ...state.getStatsTime,
63 | ts: Date.now()
64 | }
65 | };
66 | }
67 | case types.GET_DAILY_STATS_DATA_START: {
68 | return {
69 | ...state,
70 | getStatsData: {
71 | ...state.getStatsData,
72 | success: null,
73 | error: null,
74 | loading: true
75 | }
76 | };
77 | }
78 | case types.GET_DAILY_STATS_DATA_SUCCESS: {
79 | return {
80 | ...state,
81 | getStatsData: {
82 | ...state.getStatsData,
83 | loading: false,
84 | success: action.success,
85 | data: action.data,
86 | v: state.getStatsData.v + 1
87 | }
88 | };
89 | }
90 | case types.GET_DAILY_STATS_DATA_FAIL: {
91 | return {
92 | ...state,
93 | getStatsData: {
94 | data: null,
95 | error: action.error,
96 | v: state.getStatsData.v + 1
97 | }
98 | };
99 | }
100 | case types.GET_DAILY_STATS_DATA_FINISH: {
101 | return {
102 | ...state,
103 | getStatsData: {
104 | ...state.getStatsData,
105 | ts: Date.now()
106 | }
107 | };
108 | }
109 | default:
110 | return state;
111 | }
112 | }
--------------------------------------------------------------------------------
/client/src/reducers/LiquidityBotReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialState = {
4 | status: {
5 | data: null,
6 | success: null,
7 | v: 0,
8 | ts: Date.now(),
9 | error: null,
10 | loading: true,
11 | },
12 | cancel: {
13 | data: null,
14 | success: null,
15 | v: 0,
16 | ts: Date.now(),
17 | error: null,
18 | loading: true,
19 | },
20 | };
21 |
22 | export default (state = initialState, action) => {
23 | switch (action.type) {
24 | case types.GET_LIQUIDITY_BOT_START: {
25 | return {
26 | ...state,
27 | status: {
28 | ...state.status,
29 | success: null,
30 | data: null,
31 | error: null,
32 | loading: true,
33 | },
34 | };
35 | }
36 | case types.GET_LIQUIDITY_BOT_SUCCESS: {
37 | return {
38 | ...state,
39 | status: {
40 | ...state.status,
41 | success: action.success,
42 | data: action.data,
43 | v: state.status.v + 1,
44 | },
45 | };
46 | }
47 |
48 | case types.GET_LIQUIDITY_BOT_FAIL: {
49 | return {
50 | ...state,
51 | status: {
52 | ...state.status,
53 | error: action.error,
54 | v: state.status.v + 1,
55 | },
56 | };
57 | }
58 |
59 | case types.GET_LIQUIDITY_BOT_FINISH: {
60 | return {
61 | ...state,
62 | status: {
63 | ...state.status,
64 | loading: false,
65 | success: null,
66 | error: null,
67 | ts: Date.now(),
68 | },
69 | };
70 | }
71 |
72 | case types.CANCEL_ORDER_LIQUIDITY_BOT_START: {
73 | return {
74 | ...state,
75 | cancel: {
76 | ...state.cancel,
77 | success: null,
78 | data: null,
79 | error: null,
80 | loading: true,
81 | },
82 | };
83 | }
84 | case types.CANCEL_ORDER_LIQUIDITY_BOT_SUCCESS: {
85 | return {
86 | ...state,
87 | cancel: {
88 | ...state.cancel,
89 | success: action.success,
90 | data: action.data,
91 | v: state.cancel.v + 1,
92 | },
93 | };
94 | }
95 |
96 | case types.CANCEL_ORDER_LIQUIDITY_BOT_FAIL: {
97 | return {
98 | ...state,
99 | cancel: {
100 | ...state.cancel,
101 | error: action.error,
102 | v: state.cancel.v + 1,
103 | },
104 | };
105 | }
106 |
107 | case types.CANCEL_ORDER_LIQUIDITY_BOT_FINISH: {
108 | return {
109 | ...state,
110 | cancel: {
111 | ...state.cancel,
112 | loading: false,
113 | success: null,
114 | error: null,
115 | ts: Date.now(),
116 | },
117 | };
118 | }
119 |
120 | default:
121 | return state;
122 | }
123 | };
124 |
--------------------------------------------------------------------------------
/client/src/reducers/LiquidityDetailsBotReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialState = {
4 | status: {
5 | data: null,
6 | success: null,
7 | v: 0,
8 | ts: Date.now(),
9 | error: null,
10 | loading: true,
11 | },
12 | };
13 |
14 | export default (state = initialState, action) => {
15 | switch (action.type) {
16 | case types.GET_LIQUIDITY_DETAILS_START: {
17 | return {
18 | ...state,
19 | status: {
20 | ...state.status,
21 | success: null,
22 | data: null,
23 | error: null,
24 | loading: true,
25 | },
26 | };
27 | }
28 |
29 | case types.GET_LIQUIDITY_DETAILS_SUCCESS: {
30 | return {
31 | ...state,
32 | status: {
33 | ...state.status,
34 | success: action.success,
35 | data: action.data,
36 | v: state.status.v + 1,
37 | },
38 | };
39 | }
40 |
41 | case types.GET_LIQUIDITY_DETAILS_FAIL: {
42 | return {
43 | ...state,
44 | status: {
45 | ...state.status,
46 | error: action.error,
47 | v: state.status.v + 1,
48 | },
49 | };
50 | }
51 |
52 | case types.GET_LIQUIDITY_DETAILS_FINISH: {
53 | return {
54 | ...state,
55 | status: {
56 | ...state.status,
57 | loading: false,
58 | success: null,
59 | error: null,
60 | ts: Date.now(),
61 | },
62 | };
63 | }
64 |
65 | default:
66 | return state;
67 | }
68 | };
69 |
--------------------------------------------------------------------------------
/client/src/reducers/ManageKeysReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialState = {
4 | status: {
5 | data: null,
6 | success: null,
7 | v: 0,
8 | ts: Date.now(),
9 | error: null,
10 | loading: true,
11 | },
12 | delete: {
13 | data: null,
14 | success: null,
15 | v: 0,
16 | ts: Date.now(),
17 | error: null,
18 | loading: true,
19 | },
20 | };
21 |
22 | export default (state = initialState, action) => {
23 | switch (action.type) {
24 | case types.GET_KEYS_BOT_START: {
25 | return {
26 | ...state,
27 | status: {
28 | ...state.status,
29 | success: null,
30 | data: null,
31 | error: null,
32 | loading: true,
33 | },
34 | };
35 | }
36 | case types.GET_KEYS_BOT_SUCCESS: {
37 | return {
38 | ...state,
39 | status: {
40 | ...state.status,
41 | success: action.success,
42 | data: action.data,
43 | v: state.status.v + 1,
44 | },
45 | };
46 | }
47 |
48 | case types.GET_KEYS_BOT_FAIL: {
49 | return {
50 | ...state,
51 | status: {
52 | ...state.status,
53 | error: action.error,
54 | v: state.status.v + 1,
55 | },
56 | };
57 | }
58 |
59 | case types.GET_KEYS_BOT_FINISH: {
60 | return {
61 | ...state,
62 | status: {
63 | ...state.status,
64 | loading: false,
65 | success: null,
66 | error: null,
67 | ts: Date.now(),
68 | },
69 | };
70 | }
71 |
72 | case types.DELETE_KEYS_BOT_START: {
73 | return {
74 | ...state,
75 | delete: {
76 | ...state.delete,
77 | success: null,
78 | data: null,
79 | error: null,
80 | loading: true,
81 | },
82 | };
83 | }
84 | case types.DELETE_KEYS_BOT_SUCCESS: {
85 | return {
86 | ...state,
87 | delete: {
88 | ...state.delete,
89 | success: action.success,
90 | data: action.data,
91 | v: state.delete.v + 1,
92 | },
93 | };
94 | }
95 |
96 | case types.DELETE_KEYS_BOT_FAIL: {
97 | return {
98 | ...state,
99 | delete: {
100 | ...state.delete,
101 | error: action.error,
102 | v: state.delete.v + 1,
103 | },
104 | };
105 | }
106 |
107 | case types.DELETE_KEYS_BOT_FINISH: {
108 | return {
109 | ...state,
110 | delete: {
111 | ...state.delete,
112 | loading: false,
113 | success: null,
114 | error: null,
115 | ts: Date.now(),
116 | },
117 | };
118 | }
119 |
120 | default:
121 | return state;
122 | }
123 | };
124 |
--------------------------------------------------------------------------------
/client/src/reducers/MonitorReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialData = {
4 | status: {
5 | success: null,
6 | error: null,
7 | data: null,
8 | loading: false,
9 | ts: null,
10 | v: 0,
11 | },
12 | form: {
13 | success: null,
14 | error: null,
15 | data: null,
16 | loading: false,
17 | ts: null,
18 | v: 0,
19 | },
20 | };
--------------------------------------------------------------------------------
/client/src/reducers/SocketReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from "../actions/types";
2 |
3 | const initialState = {
4 | socket: null,
5 | status: "not initiated",
6 | rooms: [],
7 | v: 0,
8 | };
9 |
10 | const SocketChange = (state = initialState, action) => {
11 | switch (action.type) {
12 | case types.SOCKET_CONNECTED: {
13 | return {
14 | ...state,
15 | socket: action.instance,
16 | status: "connected",
17 | v: state.v + 1,
18 | };
19 | }
20 | case types.SOCKET_DISCONNECTED: {
21 | return { ...state, status: "disconnected" };
22 | }
23 | default: {
24 | return state;
25 | }
26 | }
27 | };
28 |
29 | export default SocketChange;
30 |
--------------------------------------------------------------------------------
/client/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import Auth from "./Auth";
2 | import SocketReducer from "./SocketReducer";
3 | import ExchangeReducer from "./Exchange";
4 | import ArbitrageReducer from "./ArbitrageReducer";
5 | import AdminReducer from "./AdminReducer";
6 | import AdminProfileReducer from "./AdminProfileReducer";
7 | import DailyStatsReducer from "./DailyStatsReducer";
8 | import LiquidityBotReducer from "./LiquidityBotReducer";
9 | import ManageKeysReducer from "./ManageKeysReducer";
10 | import LiquidityDetailsBotReducer from "./LiquidityDetailsBotReducer";
11 |
12 | export default {
13 | auth: Auth,
14 | socketReducer: SocketReducer,
15 | exchangeReducer: ExchangeReducer,
16 | arbitrageReducer: ArbitrageReducer,
17 | adminReducer: AdminReducer,
18 | adminProfileReducer: AdminProfileReducer,
19 | dailyStatsReducer: DailyStatsReducer,
20 | LiquidityBotReducer: LiquidityBotReducer,
21 | ManageKeysReducer: ManageKeysReducer,
22 | LiquidityDetailsBotReducer: LiquidityDetailsBotReducer,
23 | };
24 |
--------------------------------------------------------------------------------
/client/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, combineReducers, applyMiddleware } from "redux";
2 | import reducers from "../reducers";
3 | import thunk from "redux-thunk";
4 | import createLogger from "redux-logger";
5 |
6 | const ENV = process.env.REACT_APP_ENV;
7 |
8 | export default function configureStore() {
9 | return createStore(
10 | combineReducers({
11 | ...reducers,
12 | }),
13 | {},
14 | ENV === "dev"
15 | ? applyMiddleware(thunk, createLogger)
16 | : applyMiddleware(thunk)
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/serviceWorker.js:
--------------------------------------------------------------------------------
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.0/8 are 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 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | // console.log(
45 | // 'This web app is being served cache-first by a service ' +
46 | // 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | // );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | // console.log(
73 | // 'New content is available and will be used when all ' +
74 | // 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | // );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | // console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/client/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 | services:
3 | mongodb:
4 | image: mongo:latest
5 | container_name: mongodb-container
6 | ports:
7 | - "127.0.0.1:27017:27017" # Port mapping to localhost
8 | volumes:
9 | - mongodb-data:/data/db # Mount a local directory into the container
10 | logging:
11 | driver: none
12 |
13 | redis:
14 | image: redis:latest
15 | container_name: redis-container
16 | ports:
17 | - "127.0.0.1:6379:6379" # Port mapping to localhost
18 | logging:
19 | driver: none
20 |
21 | react-app:
22 | build:
23 | context: ./client
24 | dockerfile: Dockerfile
25 | container_name: reactjs-container
26 | ports:
27 | - "3000:3000"
28 | depends_on:
29 | - nodejs-app
30 | environment:
31 | - NODE_ENV=development
32 |
33 | nodejs-app:
34 | build:
35 | context: ./server
36 | dockerfile: Dockerfile
37 | container_name: nodejs-api-container
38 | ports:
39 | - "5000:5000"
40 | - "3002:3002"
41 | depends_on:
42 | - mongodb
43 | - redis
44 | # command: ["pm2-runtime", "start", "npm", "--", "start"]
45 | command: ["npm", "start"]
46 |
47 | volumes:
48 | mongodb-data:
49 |
--------------------------------------------------------------------------------
/getLogins.sh:
--------------------------------------------------------------------------------
1 | docker exec -it nodejs-api-container cat /usr/src/app/helpers/creds.json
2 |
--------------------------------------------------------------------------------
/install_docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Colors for user feedback
4 | GREEN="\033[0;32m"
5 | RESET="\033[0m"
6 |
7 | function installDocker() {
8 | echo -e "Installing Docker\n"
9 |
10 | sudo apt-get update
11 | sudo apt-get install apt-transport-https ca-certificates curl software-properties-common -y
12 |
13 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
14 | echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
15 |
16 | sudo apt-get update
17 | sudo apt-get install docker-ce docker-ce-cli containerd.io -y
18 |
19 | sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
20 | sudo chmod +x /usr/local/bin/docker-compose
21 |
22 | echo -e "${GREEN}Docker Installed Successfully${RESET}"
23 | }
24 |
25 | function init() {
26 | if ! command -v docker &>/dev/null; then
27 | installDocker
28 | else
29 | echo -e "${GREEN}Docker is already installed.${RESET}"
30 | fi
31 | }
32 |
33 | function main() {
34 | init
35 | }
36 |
37 | main
38 |
--------------------------------------------------------------------------------
/logos/bitfinex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/logos/bitfinex.png
--------------------------------------------------------------------------------
/logos/bitrue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/logos/bitrue.png
--------------------------------------------------------------------------------
/logos/bittrex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/logos/bittrex.png
--------------------------------------------------------------------------------
/logos/gateio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/logos/gateio.png
--------------------------------------------------------------------------------
/logos/huobi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/logos/huobi.png
--------------------------------------------------------------------------------
/logos/kucoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TradingBotX/market-making-bot/b0049041336ee148ed906142c443d7b433bd7ec8/logos/kucoin.png
--------------------------------------------------------------------------------
/server/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/server/.env.example:
--------------------------------------------------------------------------------
1 | MONGO_URL=mongodb://mongodb:27017/market-making-bot
2 |
3 | PORT=5000
4 |
5 | WS_PORT=3002
6 | WS_HEARTBEAT=6000
7 |
8 | # Redis Config
9 | REDIS_HOST=redis
10 | REDIS_PORT=6379
11 | REDIS_PREFIX=MMBot
12 |
13 | ACCESS_TOKEN_SECRET=MMBot
14 |
15 | RESET_ADMIN=false
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /logs
3 |
4 | .env
--------------------------------------------------------------------------------
/server/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Node.js runtime as the base image
2 | FROM node:16
3 |
4 | # Install PM2 globally
5 | RUN npm install pm2 -g
6 |
7 | # Set the working directory inside the container
8 | WORKDIR /usr/src/app
9 |
10 | # Copy package.json and package-lock.json to the working directory
11 | COPY package*.json ./
12 |
13 | # Install project dependencies
14 | RUN npm install
15 | RUN npm install bcrypt
16 |
17 | # Copy the rest of the application code
18 | COPY . .
19 |
20 | # Expose the port that your Node.js app will run on
21 | EXPOSE 3000
22 |
23 | # Use PM2 to start your Node.js app
24 | CMD [ "npm", "start" ]
25 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const createError = require("http-errors");
2 | const express = require("express");
3 | const path = require("path");
4 | const cors = require("cors");
5 | const cookieParser = require("cookie-parser");
6 | const morganLogger = require("morgan");
7 | const logSymbols = require("log-symbols");
8 | const mongoose = require("mongoose");
9 |
10 | require("./helpers/globals");
11 |
12 | function connectToMongoDB() {
13 | try {
14 | mongoose
15 | .connect(process.env.MONGO_URL, {
16 | useNewUrlParser: true,
17 | useUnifiedTopology: true,
18 | // useCreateIndex: true,
19 | })
20 | .then(() => {
21 | logger.info("[", logSymbols.success, "] connected to mongodb");
22 | logger.debug("emitting event in internal bus");
23 | InternalBus.emit(GlobalEvents.mongodb_connected);
24 | })
25 | .catch((e) => {
26 | console.log(e);
27 | logger.error(`[*] error while connecting to mongodb:`, e);
28 | logger.info("[*] Retrying connection to mongodb in 5 seconds...");
29 | setTimeout(connectToMongoDB, 5000);
30 | });
31 | } catch (err0) {
32 | logger.error(
33 | `[*] error while connecting to mongodb: ${JSON.stringify(err0)}`
34 | );
35 | logger.error(
36 | `[*] error while connecting to mongodb at :${process.env.MONGO_URL}`
37 | );
38 | logger.info("[*] Retrying connection to mongodb in 5 seconds...");
39 | setTimeout(connectToMongoDB, 5000);
40 | }
41 | }
42 |
43 | connectToMongoDB();
44 |
45 | const { checkSetup } = require("./helpers/initialSetup");
46 |
47 | checkSetup();
48 |
49 | require("dotenv").config();
50 | require("./services/redis");
51 | require("./helpers/logger");
52 | require("./helpers/RESPONSE");
53 | require("./helpers/MAIL");
54 | require("./helpers/socket_io");
55 | require("./crons/walletBalanceCron");
56 | require("./crons/scheduledCrons");
57 | require("./helpers/exchangeSocket/bitfinex");
58 |
59 | require("events").EventEmitter.defaultMaxListeners = 20;
60 |
61 | const indexRouter = require("./routes/index");
62 | const adminRouter = require("./routes/admin");
63 | const spreadBotRouter = require("./routes/spreadBot");
64 | const bitrue = require("./helpers/exchangeHelpers/bitrue");
65 | const bittrex = require("./helpers/exchangeHelpers/bittrex");
66 |
67 | const NetLogger = require("./helpers/networkLogger").NetLogger;
68 |
69 | const app = express();
70 |
71 | app.use(
72 | morganLogger(":method :url :status :remote-addr", {
73 | stream: NetLogger.stream,
74 | })
75 | );
76 |
77 | // view engine setup
78 | app.set("views", path.join(__dirname, "views"));
79 | app.set("view engine", "jade");
80 |
81 | app.use(morganLogger("dev"));
82 | app.use(express.json());
83 | app.use(express.urlencoded({ extended: false }));
84 | app.use(cookieParser());
85 | app.use(express.static(path.join(__dirname, "public")));
86 |
87 | app.use(cors());
88 |
89 | app.use("/", indexRouter);
90 | app.use("/api/admin", adminRouter);
91 | app.use("/api/spreadbot", spreadBotRouter);
92 |
93 | // catch 404 and forward to error handler
94 | app.use(function (req, res, next) {
95 | next(createError(404));
96 | });
97 |
98 | // error handler
99 | app.use(function (err, req, res, next) {
100 | // set locals, only providing error in development
101 | res.locals.message = err.message;
102 | res.locals.error = req.app.get("env") === "development" ? err : {};
103 |
104 | // render the error page
105 | res.status(err.status || 500);
106 | res.render("error");
107 | });
108 |
109 | logger.info("[", logSymbols.success, "] server started");
110 |
111 | async function updatePrices() {
112 | const currencies = [
113 | "XDC",
114 | "SRX",
115 | "PLI",
116 | "LBT",
117 | "USPLUS",
118 | "FXD",
119 | "PRNT",
120 | "GBEX",
121 | "XTT",
122 | "XSP",
123 | ];
124 | let i,
125 | orderBook,
126 | query = {},
127 | pair;
128 | for (i = 0; i < currencies.length; i++) {
129 | pair = `${currencies[i]}-USDT`;
130 | orderBook = await bitrue.orderBook(pair);
131 | if (orderBook.bids[0] && orderBook.asks[0])
132 | query[pair] = {
133 | bid: [parseFloat(parseFloat(orderBook.bids[0][0]).toFixed(12))],
134 | ask: [parseFloat(parseFloat(orderBook.asks[0][0]).toFixed(12))],
135 | };
136 | }
137 | InternalBus.emit(GlobalEvents.converter_price, query);
138 | }
139 |
140 | // //EUR price update
141 | // async function updateEURPrice() {
142 | // let query = {};
143 | // const EURUSDTBook = await bittrex.orderBook("USDT-EUR");
144 | // if (EURUSDTBook.bids[1] && EURUSDTBook.asks[1])
145 | // query[`EUR-USDT`] = {
146 | // bid: [parseFloat(parseFloat(1 / EURUSDTBook.asks[1].rate).toFixed(8))],
147 | // ask: [parseFloat(parseFloat(1 / EURUSDTBook.bids[1].rate).toFixed(8))],
148 | // };
149 | // InternalBus.emit(GlobalEvents.converter_price, query);
150 | // }
151 |
152 | updatePrices();
153 | // updateEURPrice();
154 |
155 | setInterval(async () => {
156 | updatePrices();
157 | }, 300000);
158 |
159 | // setInterval(async () => {
160 | // updateEURPrice();
161 | // }, 120000);
162 |
163 | module.exports = app;
164 |
--------------------------------------------------------------------------------
/server/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('server-boiler-plate:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 |
24 | /**
25 | * Listen on provided port, on all network interfaces.
26 | */
27 |
28 | server.listen(port);
29 | server.on('error', onError);
30 | server.on('listening', onListening);
31 |
32 | /**
33 | * Normalize a port into a number, string, or false.
34 | */
35 |
36 | function normalizePort(val) {
37 | var port = parseInt(val, 10);
38 |
39 | if (isNaN(port)) {
40 | // named pipe
41 | return val;
42 | }
43 |
44 | if (port >= 0) {
45 | // port number
46 | return port;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | /**
53 | * Event listener for HTTP server "error" event.
54 | */
55 |
56 | function onError(error) {
57 | if (error.syscall !== 'listen') {
58 | throw error;
59 | }
60 |
61 | var bind = typeof port === 'string'
62 | ? 'Pipe ' + port
63 | : 'Port ' + port;
64 |
65 | // handle specific listen errors with friendly messages
66 | switch (error.code) {
67 | case 'EACCES':
68 | console.error(bind + ' requires elevated privileges');
69 | process.exit(1);
70 | break;
71 | case 'EADDRINUSE':
72 | console.error(bind + ' is already in use');
73 | process.exit(1);
74 | break;
75 | default:
76 | throw error;
77 | }
78 | }
79 |
80 | /**
81 | * Event listener for HTTP server "listening" event.
82 | */
83 |
84 | function onListening() {
85 | var addr = server.address();
86 | var bind = typeof addr === 'string'
87 | ? 'pipe ' + addr
88 | : 'port ' + addr.port;
89 | debug('Listening on ' + bind);
90 | }
91 |
--------------------------------------------------------------------------------
/server/controllers/indexController.js:
--------------------------------------------------------------------------------
1 | const responseHelper = require("../helpers/RESPONSE");
2 | const { RedisClient } = require("../services/redis");
3 |
4 | module.exports = {
5 | getUSDRates: async (req, res) => {
6 | const converterPrice = JSON.parse(await RedisClient.get("converterPrice"));
7 | return responseHelper.successWithData(res, "Done", { converterPrice });
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/server/crons/scheduledCrons.js:
--------------------------------------------------------------------------------
1 | const CronJob = require("cron").CronJob;
2 | const cronController = require("../controllers/cronController");
3 | const spreadBotController = require("../controllers/spreadBotController");
4 |
5 | // new CronJob(
6 | // "56 * * * *",
7 | // async () => {
8 | // cronController.checkBalances();
9 | // },
10 | // null,
11 | // true,
12 | // "Asia/Kolkata"
13 | // );
14 |
15 | new CronJob(
16 | "14 * * * * *",
17 | async () => {
18 | await spreadBotController.autoCancelOrders();
19 | await spreadBotController.runBot();
20 | await spreadBotController.updateCancellingOrders();
21 | await spreadBotController.updateOrdersMin();
22 | await spreadBotController.placeFailedOrders();
23 | await spreadBotController.checkOrderNumbers();
24 | },
25 | null,
26 | true,
27 | "Asia/Kolkata"
28 | );
29 |
30 | new CronJob(
31 | "*/10 * * * *",
32 | async () => {
33 | cronController.updatedCompletedOrdersStatus();
34 | // spreadBotController.updateMaintainOrderStatus();
35 | await spreadBotController.updateOrders10Min();
36 | },
37 | null,
38 | true,
39 | "Asia/Kolkata"
40 | );
41 |
42 | // new CronJob(
43 | // "0 */3 * * *",
44 | // async () => {
45 | // await spreadBotController.maintainBalance();
46 | // },
47 | // null,
48 | // true,
49 | // "Asia/Kolkata"
50 | // );
51 |
52 | // new CronJob(
53 | // "16 2 * * * *",
54 | // async () => {
55 | // await spreadBotController.differenceMail();
56 | // // await spreadBotController.maintainBalance();
57 | // },
58 | // null,
59 | // true,
60 | // "Asia/Kolkata"
61 | // );
62 |
63 | new CronJob(
64 | "0 8 * * *",
65 | async () => {
66 | await cronController.updateBalance("daily");
67 | },
68 | null,
69 | true,
70 | "Asia/Kolkata"
71 | );
72 |
73 | new CronJob(
74 | "5 * * * *",
75 | async () => {
76 | await cronController.updateBalance("hourly");
77 | },
78 | null,
79 | true,
80 | "Asia/Kolkata"
81 | );
82 |
--------------------------------------------------------------------------------
/server/helpers/MAIL.js:
--------------------------------------------------------------------------------
1 | const nodemailer = require("nodemailer");
2 | require("dotenv").config();
3 |
4 | let transporter = nodemailer.createTransport({
5 | host: process.env.MAIL_HOST,
6 | port: process.env.MAIL_PORT,
7 | secure: false, // true for 465, false for other ports
8 | auth: {
9 | user: process.env.MAIL_USERNAME,
10 | pass: process.env.MAIL_PASSWORD,
11 | },
12 | });
13 | var mails = {};
14 | mails.send = async function (
15 | to,
16 | subject,
17 | html,
18 | attachments,
19 | text = "",
20 | from = "Indsoft Node Monitor Alert " + process.env.MAIL_FROM
21 | ) {
22 | var info = await transporter
23 | .sendMail({
24 | from: from, // sender address
25 | to: to, // list of receivers
26 | subject: subject, // Subject line
27 | text: text, // plain text body
28 | html: html, // html body
29 | attachments: attachments,
30 | })
31 | .catch(function (err) {
32 | console.log("sending_mail_error", to, subject, err);
33 | throw err;
34 | });
35 |
36 | console.log("sending_mail_response", to, subject, info);
37 | return info;
38 | };
39 |
40 | module.exports = mails;
41 | global.mail = mails;
42 |
--------------------------------------------------------------------------------
/server/helpers/RESPONSE.js:
--------------------------------------------------------------------------------
1 | const responseHelper = {
2 | //for all standard errors
3 | error: function (res, message, httpCode = 200) {
4 | res.status(httpCode).json({
5 | statusCode: 422,
6 | message: message,
7 | });
8 | },
9 |
10 | //for database save error
11 | databaseError: function (res, error, httpCode = 200) {
12 | console.log("DB_ERROR : ", error);
13 | if (error && error.code && error.code == 11000) {
14 | res.status(httpCode).json({
15 | statusCode: 500,
16 | message: "Fields Value should be Unique.",
17 | });
18 | } else {
19 | res.status(httpCode).json({
20 | statusCode: 500,
21 | message: "Server Error",
22 | });
23 | }
24 | },
25 |
26 | //for standard server error
27 | serverError: function (res, error, httpCode = 200) {
28 | // logger.error(`SERVER_ERROR : `, error);
29 | res.status(httpCode).json({
30 | statusCode: 500,
31 | message: "Server Error",
32 | });
33 | },
34 |
35 | // for bcrypt hash error
36 | bcryptError: function (res, error, httpCode = 200) {
37 | console.log("BCRYPT_ERROR : ", error);
38 | res.status(httpCode).json({
39 | statusCode: 500,
40 | message: "Bcrypt Error",
41 | });
42 | },
43 |
44 | //for succesful request with data
45 | successWithData: function (res, msg, data, httpCode = 200) {
46 | res.status(httpCode).json({
47 | statusCode: 200,
48 | message: msg,
49 | data: data,
50 | });
51 | },
52 |
53 | //for succesful request with data
54 | successWithPaginationData: function (
55 | res,
56 | msg,
57 | data,
58 | pagination,
59 | httpCode = 200
60 | ) {
61 | res.status(httpCode).json({
62 | statusCode: 200,
63 | message: msg,
64 | data: data,
65 | pagination,
66 | });
67 | },
68 |
69 | //for successful request with message
70 | successWithMessage: function (res, message, httpCode = 200) {
71 | res.status(httpCode).json({
72 | statusCode: 200,
73 | message: message,
74 | });
75 | },
76 |
77 | errorWithMessage: function (message, code) {
78 | return {
79 | status: code || 0,
80 | message: message || "Error occured",
81 | result: {},
82 | };
83 | },
84 |
85 | //for chart response
86 | chartResponse: function (res, data, httpCode = 200) {
87 | res.status(httpCode).json(data);
88 | },
89 | };
90 |
91 | global.responseHelper = responseHelper;
92 | module.exports = responseHelper;
93 |
--------------------------------------------------------------------------------
/server/helpers/axiosHelper.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | const axios = require("axios");
3 | const httpsProxyAgent = require("https-proxy-agent");
4 |
5 | module.exports = {
6 | makeGETRequest: async function (reqObject) {
7 | const config = {
8 | method: "get",
9 | url: reqObject.url,
10 | headers: {
11 | "Content-Type": reqObject.contentType,
12 | },
13 | json: true,
14 | };
15 | let result = await axios(config);
16 | return result;
17 | },
18 |
19 | makePOSTRequest: async function (reqObject) {
20 | const config = {
21 | method: "post",
22 | url: reqObject.url,
23 | headers: {
24 | "Content-Type": reqObject.contentType,
25 | },
26 | data: reqObject.data,
27 | };
28 | let result = await axios(config);
29 | return result;
30 | },
31 |
32 | makeDELETERequest: async function (reqObject) {
33 | const config = {
34 | method: "delete",
35 | url: reqObject.url,
36 | headers: {
37 | "Content-Type": reqObject.contentType,
38 | },
39 | data: reqObject.data,
40 | };
41 | let result = await axios(config);
42 | return result;
43 | },
44 |
45 | makeGETHeaderRequest: async function (reqObject) {
46 | const config = {
47 | method: "get",
48 | url: reqObject.url,
49 | headers: reqObject.headers,
50 | };
51 | let result = await axios(config);
52 | return result;
53 | },
54 |
55 | makePOSTHeaderRequest: async function (reqObject) {
56 | const config = {
57 | method: "post",
58 | url: reqObject.url,
59 | headers: reqObject.headers,
60 | data: reqObject.data,
61 | };
62 | let result = await axios(config);
63 | return result;
64 | },
65 |
66 | makeDELETEHeaderRequest: async function (reqObject) {
67 | const config = {
68 | method: "delete",
69 | url: reqObject.url,
70 | headers: reqObject.headers,
71 | };
72 | let result = await axios(config);
73 | return result;
74 | },
75 |
76 | makePOSTRequestWithToken: async function (reqObject) {
77 | const config = {
78 | method: "post",
79 | url: reqObject.url,
80 | headers: {
81 | "Content-Type": reqObject.contentType,
82 | Authorization: reqObject.token,
83 | },
84 | data: reqObject.data,
85 | };
86 | let result = await axios(config);
87 | return result;
88 | },
89 |
90 | makeGETHeaderRequestProxy: async function (reqObject) {
91 | const agent = new httpsProxyAgent(reqObject.proxy);
92 | const config = {
93 | method: "get",
94 | url: reqObject.url,
95 | headers: reqObject.headers,
96 | httpsAgent: agent,
97 | };
98 | let result = await axios(config);
99 | return result;
100 | },
101 |
102 | makePOSTHeaderRequestProxy: async function (reqObject) {
103 | const agent = new httpsProxyAgent(reqObject.proxy);
104 | const config = {
105 | method: "post",
106 | url: reqObject.url,
107 | headers: reqObject.headers,
108 | data: reqObject.data,
109 | httpsAgent: agent,
110 | };
111 | let result = await axios(config);
112 | return result;
113 | },
114 |
115 | makePUTHeaderRequest: async function (reqObject) {
116 | const config = {
117 | method: "put",
118 | url: reqObject.url,
119 | headers: reqObject.headers,
120 | data: reqObject.data,
121 | };
122 | let result = await axios(config);
123 | return result;
124 | },
125 | };
126 |
--------------------------------------------------------------------------------
/server/helpers/creds.json:
--------------------------------------------------------------------------------
1 | { "email": "", "password": "" }
2 |
--------------------------------------------------------------------------------
/server/helpers/crypto.js:
--------------------------------------------------------------------------------
1 | const crypto = require("crypto");
2 | const algorithm = "aes256";
3 |
4 | /**
5 | *
6 | * @param {string} text
7 | * @param {string} encryptionKey
8 | */
9 | const encrypt = function (text, encryptionKey) {
10 | try {
11 | let iv = crypto.randomBytes(16);
12 | let cipher = crypto.createCipheriv(
13 | algorithm,
14 | Buffer.from(encryptionKey),
15 | iv
16 | );
17 | let encrypted = cipher.update(text);
18 | encrypted = Buffer.concat([encrypted, cipher.final()]);
19 | return iv.toString("hex") + ":" + encrypted.toString("hex");
20 | } catch (error) {
21 | console.log("encrypt_error", error);
22 | return "error";
23 | }
24 | };
25 |
26 | /**
27 | *
28 | * @param {string} encrypted
29 | * @param {string} encryptionKey
30 | */
31 | const decrypt = function (encrypted, encryptionKey) {
32 | try {
33 | let textParts = encrypted.split(":");
34 | let iv = Buffer.from(textParts.shift(), "hex");
35 | let encryptedText = Buffer.from(textParts.join(":"), "hex");
36 | let decipher = crypto.createDecipheriv(
37 | algorithm,
38 | Buffer.from(encryptionKey),
39 | iv
40 | );
41 | let decrypted = decipher.update(encryptedText);
42 | decrypted = Buffer.concat([decrypted, decipher.final()]);
43 | return decrypted.toString();
44 | } catch (error) {
45 | console.log("decrypt_error", error);
46 | return "error";
47 | }
48 | };
49 |
50 | exports.AESEncrypt = encrypt;
51 | exports.AESDecrypt = decrypt;
52 |
--------------------------------------------------------------------------------
/server/helpers/data.json:
--------------------------------------------------------------------------------
1 | {"secret":"a9029e3bb6f23c30841c63bbc5b04f05"}
--------------------------------------------------------------------------------
/server/helpers/databaseHelpers/adminHelper.js:
--------------------------------------------------------------------------------
1 | const admin = require("../../models/admin");
2 |
3 | module.exports = {
4 | getAdminsByAlertLevel: async (level) => {
5 | try {
6 | const adminData = await admin.find({
7 | alerts: { $gte: level },
8 | });
9 | return adminData;
10 | } catch (error) {
11 | logger.error(`adminHelper_getAdminsByAlertLevel_error : `, error);
12 | return [];
13 | }
14 | },
15 |
16 | updateAlertLevel: async (email, level) => {
17 | try {
18 | await admin.updateOne(
19 | {
20 | email: email,
21 | },
22 | {
23 | $set: {
24 | alerts: level,
25 | },
26 | }
27 | );
28 | return true;
29 | } catch (error) {
30 | logger.error(`adminHelper_updateAlertLevel_error : `, error);
31 | return "error";
32 | }
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/server/helpers/decryptedEnv.js:
--------------------------------------------------------------------------------
1 | const dailyData = require("../models/dailyData");
2 | const _ = require("lodash");
3 | // const { argv } = require("yargs");
4 | // const secret = argv["secret"];
5 | // const fs = require("fs");
6 | // const path = require("path");
7 |
8 | // const data = fs.readFileSync(path.resolve(__dirname, "data.json"), "UTF-8");
9 | // const secret = JSON.parse(data).secret;
10 | // if (_.isEmpty(secret)) process.exit(9);
11 |
12 | const { AESDecrypt } = require("./crypto");
13 |
14 | /**
15 | *
16 | * @param {String} encryptedKey name of field as per .env
17 | */
18 | const GetDecryptedEnv = async (encryptedKey) => {
19 | const data = await dailyData.findOne({ id: 1 });
20 | const secret = data.data;
21 | const decoded = AESDecrypt(encryptedKey, secret);
22 | return decoded;
23 | };
24 |
25 | exports.GetDecryptedEnv = GetDecryptedEnv;
26 |
--------------------------------------------------------------------------------
/server/helpers/exchangeSocket/bitfinex.js:
--------------------------------------------------------------------------------
1 | const logSymbols = require("log-symbols");
2 |
3 | const WsWrapper = require("../socketClass/wsClass");
4 |
5 | const bitURL = `wss://api-pub.bitfinex.com/ws/2`;
6 | const Subscribed_Pairs = [
7 | "XDC-USDT",
8 | "USDC-USDT",
9 | "ETH-USDT",
10 | "XRP-USDT",
11 | "BTC-USDT",
12 | ];
13 |
14 | let validPair = "";
15 | for (let i = 0; i < Subscribed_Pairs.length; i++) {
16 | let currPair = Subscribed_Pairs[i];
17 | if (i !== Subscribed_Pairs.length - 1) {
18 | validPair += `${currPair},`;
19 | } else {
20 | validPair += `${currPair}`;
21 | }
22 | }
23 |
24 | validPair = validPair.split(",");
25 | if (validPair.length > 0) {
26 | for (let pair of validPair) {
27 | let [firstCurrency, secondCurrency] = pair
28 | .split("-")
29 | .map((e) => e.toUpperCase());
30 | if (secondCurrency === "USDT") secondCurrency = "UST";
31 | if (firstCurrency === "EURT") firstCurrency = "EUT";
32 | else if (firstCurrency === "USDC") firstCurrency = "UDC";
33 | let tempPair = "";
34 | tempPair = `t${firstCurrency}${secondCurrency}`;
35 | let sData = {
36 | pair: tempPair,
37 | orgPair: pair,
38 | };
39 | setTimeout(() => {
40 | bitfinexSocket(sData);
41 | }, 10000);
42 | }
43 | }
44 |
45 | const bitfinexSocket = (sData) => {
46 | let onopen = function (data) {
47 | logger.info("[", logSymbols.success, "] bitfinex ws connected", sData.pair);
48 | let msg = JSON.stringify({
49 | event: "subscribe",
50 | channel: "ticker",
51 | symbol: sData.pair,
52 | });
53 |
54 | setTimeout(() => {
55 | this.socket.send(msg);
56 | }, 1000);
57 | };
58 | let onclose = function (evt) {
59 | // console.log("bitfinex ws close", evt);
60 | this.socket.removeAllListeners();
61 | this.reconnect();
62 | };
63 | let onerror = function (evt) {
64 | console.log("bitfinex ws error", evt);
65 | };
66 | let onmessage = async function (evt) {
67 | let wsData = JSON.parse(evt.data);
68 |
69 | if (wsData[1] && wsData[1] != "hb" && wsData[1] != "cs") {
70 | const query = {};
71 |
72 | let originalPair = "";
73 | if (["XDC-USD"].includes(sData.orgPair)) {
74 | originalPair = sData.orgPair.replace("-USD", "-USDT");
75 | } else {
76 | originalPair = sData.orgPair;
77 | }
78 |
79 | query[originalPair] = {
80 | bid: [wsData[1][0]],
81 | ask: [wsData[1][2]],
82 | };
83 | InternalBus.emit(GlobalEvents.converter_started, originalPair);
84 | InternalBus.emit(GlobalEvents.converter_price, query);
85 | }
86 | };
87 |
88 | let wSocket = new WsWrapper(
89 | "bitfinex_converter",
90 | bitURL,
91 | {
92 | onClose: onclose,
93 | onOpen: onopen,
94 | onError: onerror,
95 | onMessage: onmessage,
96 | },
97 | { asks: [], bids: [] }
98 | );
99 | };
100 |
--------------------------------------------------------------------------------
/server/helpers/globals.js:
--------------------------------------------------------------------------------
1 | const Event = require("events");
2 | const InternalBus = new Event.EventEmitter();
3 | const requestIp = require("request-ip");
4 |
5 | const isset = async function (variable) {
6 | return typeof variable !== typeof undefined ? true : false;
7 | };
8 |
9 | global.isset = isset;
10 |
11 | const GlobalEvents = Object.freeze({
12 | mongodb_connected: 0,
13 | exchange_pair_updated: 1,
14 | exchange_orderbook_update: 2,
15 | crons_synced: 3,
16 | admin_logout: 4,
17 | socket_sync: 5,
18 | best_price: 6,
19 | monitor: 7,
20 | converter_price: 8,
21 | converter_started: 9,
22 | exchange_updated: 10,
23 | exchange_deactivated: 11,
24 | volume_bot_updated: 12,
25 | arbitrage_updated: 13,
26 | favourable_orders: 14,
27 | arbitrage_order_placed: 15,
28 | });
29 |
30 | /**
31 | * Applicaitons internal bus to be used for pushing data across files on certain events
32 | * For: database connection.
33 | *
34 | * @NOTE Theres a cap on the amount of listeners on the app ( max-listernes ); only use when no other option
35 | */
36 | global.InternalBus = InternalBus;
37 | global.GlobalEvents = GlobalEvents;
38 |
39 | global.timeouts = {};
40 | global.flags = {};
41 |
42 | /**
43 | * Global Stack Trace
44 | */
45 |
46 | Object.defineProperty(global, "__stack", {
47 | get: function () {
48 | const orig = Error.prepareStackTrace;
49 | Error.prepareStackTrace = function (_, stack) {
50 | return stack;
51 | };
52 | const err = new Error();
53 | Error.captureStackTrace(err, arguments.callee);
54 | const stack = err.stack;
55 | Error.prepareStackTrace = orig;
56 | return stack;
57 | },
58 | });
59 |
60 | Object.defineProperty(Object.prototype, "partialMatch", {
61 | value: function (fields) {
62 | for (let key of Object.keys(fields)) {
63 | if (Object.keys(this).includes(key)) {
64 | if (this[key] === fields[key]) continue;
65 | return false;
66 | } else {
67 | return false;
68 | }
69 | }
70 | return true;
71 | },
72 | });
73 |
74 | Object.defineProperty(Array.prototype, "includesPartial", {
75 | value: function (fields) {
76 | for (let i = 0; i < this.length; i++) {
77 | const obj = this[i];
78 | if (obj.partialMatch(fields)) {
79 | return i;
80 | }
81 | }
82 | return null;
83 | },
84 | });
85 |
86 | // Object.defineProperty(global, "__line", {
87 | // get: function () {
88 | // return __stack[1].getLineNumber();
89 | // },
90 | // });
91 |
92 | function getCallerIP(request) {
93 | const clientIp = requestIp.getClientIp(request);
94 | var ip =
95 | request.headers["x-forwarded-for"] ||
96 | request.connection.remoteAddress ||
97 | request.socket.remoteAddress ||
98 | request.connection.socket.remoteAddress;
99 | let ipa = ip.split(",").shift();
100 |
101 | ip = ipa.split(":").slice(-1).shift(); //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
102 | if (isCorrectIP(ip) === false) {
103 | let ipNew = ipa.split(":").shift();
104 | if (isCorrectIP(ipNew) === false) {
105 | return "Not Found";
106 | } else {
107 | return ipNew;
108 | }
109 | } else {
110 | return ip;
111 | }
112 | }
113 | global.getCallerIP = getCallerIP;
114 |
115 | async function isCorrectIP(ip) {
116 | const isIp = require("is-ip");
117 | if (isIp(ip)) {
118 | return true;
119 | } else {
120 | return false;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/server/helpers/logger.js:
--------------------------------------------------------------------------------
1 | /**
2 | * logger.js file to print logs in a more structured manner.
3 | * there are two levels of logs 'error', 'info' and 'debug'.
4 | * use info for as how you use console.log
5 | * use debug to print more info which you feel might be required to log in case of debugging
6 | *
7 | * @NOTE logger accepts only one arguement which has to a string or a non-circular json
8 | */
9 |
10 | const winston = require("winston");
11 | const path = require("path");
12 | const fs = require("fs");
13 | const _ = require("lodash");
14 | const { argv } = require("yargs");
15 | const stack = require("callsite");
16 |
17 | require("winston-daily-rotate-file");
18 |
19 | const { combine, timestamp, printf } = winston.format;
20 |
21 | const logPath = path.join(__dirname, "../logs");
22 | const appPath = path.join(logPath, "info");
23 | const debugPath = path.join(logPath, "debug");
24 | const errorPath = path.join(logPath, "error");
25 | const networkPath = path.join(logPath, "network");
26 |
27 | const defaultLogLevel = "info";
28 | const validLogLevels = ["info", "debug", "error", "silly", "orders"];
29 | let logLevel = defaultLogLevel;
30 |
31 | if (argv["log-level"]) {
32 | if (validLogLevels.includes(argv["log-level"]) === true) {
33 | console.warn(`[*] log level: ${argv["log-level"]}`);
34 | logLevel = argv["log-level"];
35 | } else {
36 | console.warn("[*] invalid log level");
37 | }
38 | }
39 |
40 | if (!fs.existsSync(logPath)) {
41 | console.log("[*] creating log folders");
42 | fs.mkdirSync(logPath);
43 | fs.mkdirSync(appPath);
44 | fs.mkdirSync(debugPath);
45 | fs.mkdirSync(errorPath);
46 | fs.mkdirSync(networkPath);
47 | } else {
48 | if (!fs.existsSync(appPath)) fs.mkdirSync(appPath);
49 | if (!fs.existsSync(debugPath)) fs.mkdirSync(debugPath);
50 | if (!fs.existsSync(errorPath)) fs.mkdirSync(errorPath);
51 | if (!fs.existsSync(networkPath)) fs.mkdirSync(networkPath);
52 | }
53 |
54 | const levels = {
55 | error: 0,
56 | info: 1,
57 | debug: 2,
58 | silly: 3,
59 | };
60 |
61 | const logger = winston.createLogger({
62 | levels,
63 | format: combine(
64 | timestamp(),
65 | printf(({ level, message, timestamp, error, ...rest }) => {
66 | if (_.isObject(message)) message = JSON.stringify(message);
67 |
68 | let allRest = "";
69 | rest = rest[Symbol.for("splat")] || [];
70 |
71 | if (rest.length > 0) {
72 | allRest = rest
73 | .map((e) => {
74 | if (_.isObject(e)) {
75 | if (e.stack) {
76 | return e.stack;
77 | }
78 | delete e.apiKey;
79 | delete e.apiSecret;
80 | delete e.token;
81 | delete e.tokenId;
82 | delete e.tokenSecret;
83 | delete e.walletAddress;
84 | delete e.privateKey;
85 | delete e.passPhrase;
86 | return JSON.stringify(e);
87 | }
88 | return e;
89 | })
90 | .join(" ");
91 | }
92 |
93 | let infoStack = "\nStackTrace::: ";
94 |
95 | stack().forEach(function (site) {
96 | infoStack += `File: ${site.getFileName()}:${site.getLineNumber()} Function: ${
97 | site.getFunctionName() || "anonymous"
98 | } \n`;
99 | });
100 |
101 | if (error) {
102 | if (error.stack)
103 | return `${timestamp} ${level}: ${message} Error:${error.stack} ${allRest}`;
104 | else {
105 | return `${timestamp} ${level}: ${infoStack}: ${message} Error: ${JSON.stringify(
106 | error
107 | )} ${allRest}`;
108 | }
109 | }
110 |
111 | if (level === "error") {
112 | return `${timestamp} ${level}: ${infoStack} ${message} ${allRest}`;
113 | }
114 |
115 | return `${timestamp} ${level}: ${message} ${allRest}`;
116 | })
117 | ),
118 | transports: [
119 | new winston.transports.DailyRotateFile({
120 | filename: `${errorPath}/error-%DATE%.log`,
121 | datePattern: "YYYY-MM-DD",
122 | level: "error",
123 | maxSize: "10m",
124 | }),
125 | new winston.transports.DailyRotateFile({
126 | filename: `${appPath}/info-%DATE%.log`,
127 | datePattern: "YYYY-MM-DD",
128 | level: "info",
129 | maxSize: "10m",
130 | }),
131 | new winston.transports.DailyRotateFile({
132 | filename: `${debugPath}/debug-%DATE%.log`,
133 | datePattern: "YYYY-MM-DD",
134 | level: "debug",
135 | maxSize: "10m",
136 | }),
137 | // new winston.transports.DailyRotateFile({
138 | // filename: `${networkPath}/network-%DATE%.log`,
139 | // datePattern: "YYYY-MM-DD",
140 | // level: "silly",
141 | // }),
142 | new winston.transports.Console({
143 | level: logLevel,
144 | }),
145 | ],
146 | });
147 |
148 | // logger.debug("in debug file only");
149 | // logger.info("in files above ( including ) info");
150 | // logger.error("in all files");
151 |
152 | // logger.stream = {
153 | // write: function (message, encoding) {
154 | // logger.silly(message);
155 | // },
156 | // };
157 |
158 | global.logger = logger;
159 |
160 | // try {
161 | // throw new Error("test error");
162 | // } catch (e) {
163 | // logger.error("this will thow error", e);
164 | // }
165 |
--------------------------------------------------------------------------------
/server/helpers/networkLogger.js:
--------------------------------------------------------------------------------
1 | const winston = require("winston");
2 | const path = require("path");
3 | const fs = require("fs");
4 | const _ = require("lodash");
5 |
6 | const { combine, timestamp, printf } = winston.format;
7 |
8 | const logPath = path.join(__dirname, "../logs");
9 | const networkPath = path.join(logPath, "network");
10 |
11 | if (!fs.existsSync(logPath)) {
12 | console.log("[*] creating log folders");
13 | fs.mkdirSync(logPath);
14 | fs.mkdirSync(networkPath);
15 | } else {
16 | if (!fs.existsSync(networkPath)) fs.mkdirSync(networkPath);
17 | }
18 |
19 | const NetLogger = winston.createLogger({
20 | levels: { req: 0 },
21 | format: combine(
22 | timestamp(),
23 | printf(({ level, message, timestamp, error, ...rest }) => {
24 | if (_.isObject(message)) message = JSON.stringify(message);
25 |
26 | let allRest = "";
27 | rest = rest[Symbol.for("splat")] || [];
28 |
29 | if (rest.length > 0) {
30 | allRest = rest
31 | .map((e) => {
32 | if (_.isObject(e)) {
33 | if (e.stack) {
34 | return e.stack;
35 | }
36 | return JSON.stringify(e);
37 | }
38 | return e;
39 | })
40 | .join(" ");
41 | }
42 |
43 | if (error) {
44 | if (error.stack)
45 | return `${timestamp} ${level}: ${message} Error:${error.stack} ${allRest}`;
46 | else {
47 | return `${timestamp} ${level}: ${message} Error:${JSON.stringify(
48 | error
49 | )} ${allRest}`;
50 | }
51 | }
52 |
53 | return `${timestamp} ${level}: ${message} ${allRest}`;
54 | })
55 | ),
56 | transports: [
57 | new winston.transports.DailyRotateFile({
58 | filename: `${networkPath}/network-%DATE%.log`,
59 | datePattern: "YYYY-MM-DD",
60 | level: "req",
61 | }),
62 | ],
63 | });
64 |
65 | require("winston-daily-rotate-file");
66 |
67 | NetLogger.stream = {
68 | write: function (message, encoding) {
69 | NetLogger.req(message);
70 | },
71 | };
72 |
73 | exports.NetLogger = NetLogger;
74 |
--------------------------------------------------------------------------------
/server/helpers/socketClass/wsClass.js:
--------------------------------------------------------------------------------
1 | const WebSocket = require("ws");
2 |
3 | const defaultListener = (d) => {
4 | console.log("d", d);
5 | };
6 |
7 | class WsWrapper {
8 | constructor(
9 | name,
10 | wss,
11 | listeners = {
12 | onClose: defaultListener,
13 | onOpen: defaultListener,
14 | onError: defaultListener,
15 | onMessage: defaultListener,
16 | },
17 | ...rest
18 | ) {
19 | this.socketName = name;
20 | this.wss = wss;
21 | this.listeners = listeners;
22 | this.vars = rest;
23 | this.connect();
24 | }
25 |
26 | connect() {
27 | this.socket = new WebSocket(this.wss);
28 | this.initiateListeners();
29 | }
30 |
31 | reconnect() {
32 | this.socket.removeAllListeners();
33 | this.socket.close();
34 | this.socket = undefined;
35 | this.connect();
36 | }
37 |
38 | initiateListeners() {
39 | this.socket.onopen = this.listeners.onOpen.bind(this);
40 | this.socket.onmessage = this.listeners.onMessage.bind(this);
41 | this.socket.onerror = this.listeners.onError.bind(this);
42 | this.socket.onclose = this.listeners.onClose.bind(this);
43 | }
44 |
45 | terminate() {
46 | this.socket.removeAllListeners();
47 | this.socket.close();
48 | }
49 | }
50 |
51 | module.exports = WsWrapper;
52 |
--------------------------------------------------------------------------------
/server/helpers/socket_io.js:
--------------------------------------------------------------------------------
1 | const app = require("express")();
2 | const server = require("http").createServer(app);
3 | const io = require("socket.io")(server);
4 | const jwt = require("jsonwebtoken");
5 |
6 | const { RedisClient } = require("../services/redis");
7 |
8 | io.listen(process.env.WS_PORT || 3002);
9 |
10 | global.socket_io = io;
11 |
12 | let SOCKET_COUNT = 0;
13 |
14 | /**
15 | *
16 | * SOCKET MIDDDLEWARE STARTS
17 | *
18 | */
19 |
20 | io.use((socket, next) => {
21 | try {
22 | if (socket.handshake.query.transfer == "test") {
23 | next();
24 | } else {
25 | if (!socket.handshake.query && !socket.handshake.query.jwt) {
26 | return socket.disconnect();
27 | }
28 |
29 | const token = socket.handshake.query.jwt;
30 |
31 | const decodedUser = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
32 |
33 | if (decodedUser.exp * 1000 < Date.now()) return socket.disconnect();
34 |
35 | logger.debug(":ws jwt ok");
36 |
37 | socket.user = decodedUser;
38 |
39 | next();
40 | }
41 | } catch (e) {
42 | logger.error("socket_connection_error", e);
43 | return socket.disconnect();
44 | }
45 | });
46 |
47 | io.use((socket, next) => {
48 | SOCKET_COUNT++;
49 | emitSocketSync();
50 | next();
51 | });
52 |
53 | /**connected to mongodb
54 | *
55 | * SOCKET MIDDDLEWARE STOPS
56 | *
57 | * @note no listerners in socket handler permitted without proper exit calls
58 | */
59 |
60 | /**
61 | *
62 | * SOCKET CONNECTION HANDLER STARTS
63 | *
64 | */
65 | io.on("connection", (socket) => {
66 | let last_ping = Date.now();
67 | let intervalRef;
68 |
69 | emitSocketSync();
70 | // logger.debug(":ws ", socket.user.email);
71 |
72 | socket.on("ping-transfer", (cb) => {
73 | last_ping = Date.now();
74 | socket.emit("pong");
75 | cb(true);
76 | });
77 |
78 | socket.on("heart-beat", (token) => {
79 | try {
80 | const currDecoded = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
81 | if (currDecoded.email !== socket.user.email) return socket.disconnect();
82 | if (currDecoded.exp * 1000 < Date.now()) return socket.disconnect();
83 | last_ping = Date.now();
84 | socket.emit("pong");
85 | } catch (e) {
86 | logger.error(e);
87 | if (socket) socket.disconnect();
88 | }
89 | });
90 |
91 | socket.once("disconnect", () => {
92 | socket = undefined;
93 | clearInterval(intervalRef);
94 | SOCKET_COUNT--;
95 | emitSocketSync();
96 | });
97 |
98 | socket.on("joinRooms", (rooms) => {
99 | rooms.forEach((room) => {
100 | console.log("joining room", room);
101 | socket.join(room);
102 | emitStarterData(room, socket);
103 | });
104 | emitSocketSync();
105 | });
106 |
107 | socket.on("leaveAll", () => {
108 | socket.leaveAll();
109 | });
110 |
111 | socket.on("get_wallet_balance", () => {
112 | emitStarterData("wallet", socket);
113 | });
114 |
115 | intervalRef = setInterval(() => {
116 | if (Date.now() - last_ping > 10000) {
117 | socket.disconnect();
118 | }
119 | }, 5000);
120 | });
121 |
122 | /**
123 | *
124 | * SOCKET CONNECTION HANDLER STOPS
125 | *
126 | */
127 |
128 | /**
129 | *
130 | * BROADCASTS STARTS
131 | *
132 | */
133 |
134 | function emitSocketSync() {
135 | io.emit("socket_count", SOCKET_COUNT);
136 | }
137 |
138 | // setInterval(() => console.log(SOCKET_COUNT), 5000);
139 |
140 | /**
141 | *
142 | * BROADCASTS STOPS
143 | *
144 | */
145 |
146 | /**
147 | *
148 | * HELPER FUNCS
149 | *
150 | */
151 |
152 | async function emitStarterData(room, socket) {
153 | try {
154 | switch (room) {
155 | case "op_connect": {
156 | return InternalBus.emit(GlobalEvents.mongodb_connected);
157 | }
158 |
159 | case "monitor": {
160 | return socket.emit("memory_usage", process.memoryUsage());
161 | }
162 |
163 | case "wallet": {
164 | socket.emit(
165 | "balances",
166 | JSON.parse(await RedisClient.get("wallet_balances"))
167 | );
168 | const wallet_balance = JSON.parse(
169 | await RedisClient.get("wallet_balances")
170 | );
171 | const exchanges = Object.keys(wallet_balance);
172 | let data = [];
173 | for (let exchange of exchanges) {
174 | data = [
175 | ...data,
176 | ...wallet_balance[exchange].data.map((e) => {
177 | return { ...e, exchange };
178 | }),
179 | ];
180 | }
181 |
182 | data = data.reduce((acc, e) => {
183 | const index = acc.includesPartial({
184 | currency: e.currency,
185 | // botName: e.botName,
186 | });
187 | if (index !== null) {
188 | acc[index].balance += e.balance;
189 | } else {
190 | acc.push({
191 | ...e,
192 | });
193 | }
194 | return acc;
195 | }, []);
196 |
197 | socket.emit("live_snapshot", data);
198 | return;
199 | }
200 |
201 | default:
202 | return;
203 | }
204 | } catch (e) {
205 | logger.error(e);
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/server/middlewares/errorHandler.js:
--------------------------------------------------------------------------------
1 | const { CustomError } = require("../helpers/errors");
2 |
3 | exports.errorHandler = (err, req, res, next) => {
4 | if (err instanceof CustomError) {
5 | logger.error(err);
6 | return res.status(err.statusCode).send({ errors: err.serializeErrors() });
7 | }
8 |
9 | logger.error("uncaught error", { error: err });
10 |
11 | res.status(500).send({
12 | errors: [{ message: "internal error" }],
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/server/middlewares/requireAdmin.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | module.exports = function (req, res, next) {
4 | const token = req.headers.authorization || req.headers.token;
5 |
6 | jwt.verify(
7 | token,
8 | process.env.ACCESS_TOKEN_SECRET,
9 | async function (err, decoded) {
10 | if (err) {
11 | // logger.error(`requireAdmin_jwt_error`, err, token);
12 | return responseHelper.error(res, "please login again.");
13 | } else {
14 | if (decoded.level !== 1 && decoded.level !== 2) {
15 | return res
16 | .status(401)
17 | .json({ errors: [{ message: "unauthorized" }] });
18 | }
19 | req.user = decoded;
20 | next();
21 | }
22 | }
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/server/middlewares/requireSuperAdmin.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | module.exports = function (req, res, next) {
4 | const token = req.headers.authorization || req.headers.token;
5 |
6 | jwt.verify(
7 | token,
8 | process.env.ACCESS_TOKEN_SECRET,
9 | async function (err, decoded) {
10 | if (err) {
11 | return responseHelper.error(res, "please login again.");
12 | } else {
13 | if (decoded.level !== 2) {
14 | return res
15 | .status(401)
16 | .json({ errors: [{ message: "unauthorized" }] });
17 | }
18 | req.user = decoded;
19 | next();
20 | }
21 | }
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/server/middlewares/validateRequest.js:
--------------------------------------------------------------------------------
1 | const { validationResult } = require("express-validator");
2 | const { RequestValidationError } = require("../helpers/errors");
3 |
4 | exports.validateRequest = (checks) => {
5 | return async function (req, res, next) {
6 | for (let check of checks) {
7 | await check.run(req);
8 | }
9 |
10 | const errors = validationResult(req);
11 | if (!errors.isEmpty()) {
12 | throw new RequestValidationError(errors.array());
13 | } else {
14 | next();
15 | }
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/server/models/admin.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const bcrypt = require("bcrypt");
3 |
4 | const userSchema = mongoose.Schema(
5 | {
6 | name: { type: String, required: true },
7 | email: { type: String, unique: true, required: true },
8 | password: { type: String, required: true },
9 | level: { type: Number, enum: [0, 1, 2], required: true, default: 0 }, // needs to be set manually or can be approved by a level 2 admin
10 | alerts: { type: Number, enum: [0, 1, 2], default: 0 }, //0 no mails, 1 critical, 2 all
11 | },
12 | {
13 | timestamps: true,
14 | }
15 | );
16 |
17 | userSchema.methods.generateHash = function (password) {
18 | return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
19 | };
20 |
21 | userSchema.methods.validPassword = function (password) {
22 | return bcrypt.compareSync(password, this.password);
23 | };
24 |
25 | module.exports = mongoose.model("Admin", userSchema);
26 |
--------------------------------------------------------------------------------
/server/models/arbitrageOperations.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const arbitrageOperationsSchema = mongoose.Schema(
4 | {
5 | minAmount: {},
6 | maxAmount: {},
7 | minPriceBy: [
8 | {
9 | type: String,
10 | enum: ["total_amount", "price_diff"],
11 | default: "total_amount",
12 | },
13 | ],
14 | minPrice: {
15 | total_amount: Number,
16 | price_diff: Number,
17 | },
18 | virtualArbitrage: { type: Boolean, default: false },
19 | exchangeConnection: {},
20 | connectionDetails: {},
21 | status: { type: Boolean, default: false },
22 | activeOrderTolerance: Number,
23 | statusMsg: String,
24 | },
25 | {
26 | timestamps: true,
27 | }
28 | );
29 |
30 | module.exports = mongoose.model(
31 | "ArbitrageOperations",
32 | arbitrageOperationsSchema
33 | );
34 |
--------------------------------------------------------------------------------
/server/models/completedOrders.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | let completedOrders = new Schema(
5 | {
6 | botType: { type: String, required: true },
7 | exchange: { type: String, required: true },
8 | pair: { type: String, required: true },
9 | type: { type: String, required: true, enum: ["buy", "sell"] },
10 | account: { type: String, required: true },
11 | exchangeId: { type: String, required: true },
12 | price: { type: Number, required: true, default: 0 },
13 | usdtPrice: { type: Number, required: true, default: 0 },
14 | XDC: { type: Number, default: 0 },
15 | USDT: { type: Number, default: 0 },
16 | USD: { type: Number, default: 0 },
17 | ETH: { type: Number, default: 0 },
18 | BTC: { type: Number, default: 0 },
19 | XRP: { type: Number, default: 0 },
20 | IDR: { type: Number, default: 0 },
21 | SGD: { type: Number, default: 0 },
22 | SRX: { type: Number, default: 0 },
23 | PLI: { type: Number, default: 0 },
24 | LBT: { type: Number, default: 0 },
25 | fees: { type: Number, default: 0 },
26 | feeCurrency: { type: String, default: "USD" },
27 | feesUSDT: { type: Number, default: 0 },
28 | status: { type: String, default: "active" },
29 | deletedAt: { type: String },
30 | },
31 | {
32 | timestamps: true,
33 | }
34 | );
35 |
36 | //export the model
37 | module.exports = mongoose.model("completedOrders", completedOrders);
38 |
--------------------------------------------------------------------------------
/server/models/dailyData.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const dailyData = new mongoose.Schema(
4 | {
5 | id: { type: Number },
6 | data: { type: String },
7 | },
8 | {
9 | timestamps: true,
10 | }
11 | );
12 |
13 | module.exports = mongoose.model("dailyData", dailyData);
14 |
--------------------------------------------------------------------------------
/server/models/dailyStats.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const dailyStats = new mongoose.Schema(
4 | {
5 | exchange: String,
6 | account: String,
7 | stats: [
8 | {
9 | currency: String,
10 | yesterdayBalance: Number,
11 | todayBalance: Number,
12 | balanceChange: Number,
13 | type: { type: String, enum: ["profit", "loss"] },
14 | diffUSDT: Number,
15 | },
16 | ],
17 | time: String,
18 | },
19 | {
20 | timestamps: true,
21 | }
22 | );
23 |
24 | module.exports = mongoose.model("dailyStats", dailyStats);
25 |
--------------------------------------------------------------------------------
/server/models/dailyWalletBalances.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const dailyWalletBalances = new mongoose.Schema(
4 | {
5 | exchange: String,
6 | account: String,
7 | currency: [
8 | {
9 | currency: String,
10 | balance: Number,
11 | inTrade: Number,
12 | total: Number,
13 | },
14 | ],
15 | time: String,
16 | },
17 | {
18 | timestamps: true,
19 | }
20 | );
21 |
22 | module.exports = mongoose.model("dailyWalletBalances", dailyWalletBalances);
23 |
--------------------------------------------------------------------------------
/server/models/exchangeCurrencies.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const exchangeCurrencies = new mongoose.Schema(
4 | {
5 | exchange: { type: String, unique: true, required: true },
6 | currency: [
7 | {
8 | symbol: String,
9 | name: String,
10 | currencyId: String,
11 | exchangeSymbol: String,
12 | minimumBalance: Number,
13 | minArbBalance: Number,
14 | },
15 | ],
16 | },
17 | {
18 | timestamps: true,
19 | }
20 | );
21 |
22 | module.exports = mongoose.model("exchangeCurrencies", exchangeCurrencies);
23 |
--------------------------------------------------------------------------------
/server/models/exchangeData.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const exchangeData = new mongoose.Schema(
4 | {
5 | uniqueId: { type: String, unique: true, required: true },
6 | exchange: { type: String, unique: true, required: true },
7 | apiKey: { type: String, default: "" },
8 | apiSecret: { type: String, default: "" },
9 | passPhrase: { type: String, default: "" },
10 | subAccUserId: { type: String, default: "" },
11 | accountId: { type: String, default: "" },
12 | },
13 | {
14 | timestamps: true,
15 | }
16 | );
17 |
18 | module.exports = mongoose.model("exchangeData", exchangeData);
19 |
--------------------------------------------------------------------------------
/server/models/exchangePair.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | let exchangePair = new Schema(
5 | {
6 | exchange: { type: String, unique: true, required: true },
7 | pair: [
8 | {
9 | name: { type: String, required: true },
10 | decimalsAmount: { type: Number },
11 | decimalsPrice: { type: Number },
12 | minAmount: { type: Number, default: 0 },
13 | maxAmount: { type: Number },
14 | },
15 | ],
16 | tradeFee: { type: Number, required: true, default: 0 },
17 | disabled: { type: Boolean, default: false },
18 | deletedAt: { type: String },
19 | },
20 | {
21 | timestamps: true,
22 | }
23 | );
24 |
25 | //export the model
26 | module.exports = mongoose.model("exchangePair", exchangePair);
27 |
--------------------------------------------------------------------------------
/server/models/exchangeWalletSnapshot.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const walletSnapShot = new mongoose.Schema(
4 | {
5 | snapId: { type: String, required: true, index: true },
6 | exchange: String,
7 | account: String,
8 | currency: [
9 | {
10 | currency: String,
11 | balance: Number,
12 | inTrade: Number,
13 | total: Number,
14 | },
15 | ],
16 | },
17 | {
18 | timestamps: true,
19 | }
20 | );
21 |
22 | module.exports = mongoose.model("walletSnapShot", walletSnapShot);
23 |
--------------------------------------------------------------------------------
/server/models/spreadBotDetails.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | let spreadBotDetails = new Schema(
5 | {
6 | uniqueId: { type: String, required: true, unique: true },
7 | exchange: { type: String, required: true },
8 | pair: { type: String, required: true },
9 | maxOrders: { type: Number, required: true, default: 0 },
10 | percentGap: { type: Number, required: true, default: 0 },
11 | price: { type: Number, required: true, default: 0 },
12 | usdtPrice: { type: Number, required: true, default: 0 },
13 | amountBuy: { type: Number, required: true, default: 0 },
14 | amountSell: { type: Number, required: true, default: 0 },
15 | placedAmountBuy: { type: Number, required: true, default: 0 },
16 | filledAmountBuy: { type: Number, required: true, default: 0 },
17 | placedTotalBuy: { type: Number, default: 0 }, //in USDT
18 | updatedTotalBuy: { type: Number, default: 0 }, //in USDT
19 | placedAmountSell: { type: Number, required: true, default: 0 },
20 | filledAmountSell: { type: Number, required: true, default: 0 },
21 | placedTotalSell: { type: Number, default: 0 }, //in USDT
22 | updatedTotalSell: { type: Number, default: 0 }, //in USDT
23 | mappedOrders: [],
24 | status: { type: String, required: true, default: "active" },
25 | started: { type: Boolean, required: true, default: false },
26 | // ordersGenerated: { type: Boolean, required: true, default: false },
27 | balanceToBeMaintanedC1: { type: Number, required: true, default: 0 },
28 | balanceToBeMaintanedC2: { type: Number, required: true, default: 0 },
29 | lastSettledAtC1: { type: Number, required: true, default: 0 },
30 | lastSettledAtC2: { type: Number, required: true, default: 0 },
31 | deletedAt: { type: String },
32 | },
33 | {
34 | timestamps: true,
35 | }
36 | );
37 |
38 | //export the model
39 | module.exports = mongoose.model("spreadBotDetails", spreadBotDetails);
40 |
--------------------------------------------------------------------------------
/server/models/spreadBotGeneratedOrders.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | let spreadBotGeneratedOrders = new Schema(
5 | {
6 | uniqueId: { type: String, unique: true, required: true },
7 | currency: { type: String, required: true },
8 | type: { type: String, required: true },
9 | usdtPrice: { type: Number, required: true, default: 0 },
10 | status: { type: String, required: true, default: "active" },
11 | revOrderId: { type: String, default: "" },
12 | oppOrderId: { type: String, default: "" },
13 | mappedOrders: [],
14 | },
15 | {
16 | timestamps: true,
17 | }
18 | );
19 |
20 | //export the model
21 | module.exports = mongoose.model(
22 | "spreadBotGeneratedOrders",
23 | spreadBotGeneratedOrders
24 | );
25 |
--------------------------------------------------------------------------------
/server/models/spreadBotMaintainOrders.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | let spreadBotMaintainOrders = new Schema(
5 | {
6 | orderId: { type: String, required: true },
7 | uniqueId: { type: String, unique: true, required: true },
8 | mappingId: { type: String, required: true },
9 | exchange: { type: String, required: true },
10 | pair: { type: String, required: true },
11 | type: { type: String, required: true },
12 | price: { type: Number, required: true, default: 0 },
13 | usdtPrice: { type: Number, required: true, default: 0 },
14 | originalQty: { type: Number, required: true, default: 0 },
15 | filledQty: { type: Number, required: true, default: 0 },
16 | total: { type: Number, required: true, default: 0 },
17 | usdtTotal: { type: Number, required: true, default: 0 },
18 | updatedTotal: { type: Number, required: true, default: 0 },
19 | updatedUsdtTotal: { type: Number, required: true, default: 0 },
20 | fees: { type: Number, default: 0 },
21 | feeCurrency: { type: String, default: "USD" },
22 | feesUSDT: { type: Number, default: 0 },
23 | status: { type: String, required: true, default: "active" },
24 | currentBalance: { type: Number, required: true, default: 0 },
25 | currency: { type: String, required: true, default: "" },
26 | },
27 | {
28 | timestamps: true,
29 | }
30 | );
31 |
32 | //export the model
33 | module.exports = mongoose.model(
34 | "spreadBotMaintainOrders",
35 | spreadBotMaintainOrders
36 | );
37 |
--------------------------------------------------------------------------------
/server/models/spreadBotOrders.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | let spreadBotOrders = new Schema(
5 | {
6 | orderId: { type: String, required: true },
7 | uniqueId: { type: String, unique: true, required: true },
8 | mappingId: { type: String, required: true },
9 | exchange: { type: String, required: true },
10 | pair: { type: String, required: true },
11 | type: { type: String, required: true },
12 | price: { type: Number, required: true, default: 0 },
13 | usdtPrice: { type: Number, required: true, default: 0 },
14 | originalQty: { type: Number, required: true, default: 0 },
15 | filledQty: { type: Number, required: true, default: 0 },
16 | total: { type: Number, required: true, default: 0 },
17 | usdtTotal: { type: Number, required: true, default: 0 },
18 | updatedTotal: { type: Number, required: true, default: 0 },
19 | updatedUsdtTotal: { type: Number, required: true, default: 0 },
20 | fees: { type: Number, default: 0 },
21 | feeCurrency: { type: String, default: "USD" },
22 | feesUSDT: { type: Number, default: 0 },
23 | status: { type: String, required: true, default: "active" },
24 | revOrderId: { type: String, default: "" },
25 | oppOrderId: { type: String, default: "" },
26 | cancelling: { type: Boolean, default: false },
27 | // refId: { type: String },
28 | },
29 | {
30 | timestamps: true,
31 | }
32 | );
33 |
34 | //export the model
35 | module.exports = mongoose.model("spreadBotOrders", spreadBotOrders);
36 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "nodemon --max-old-space-size=1024 -r dotenv/config ./bin/www --ignore ./helpers/creds.json",
7 | "start": "nodemon --max-old-space-size=1024 -r dotenv/config ./bin/www --ignore ./helpers/creds.json",
8 | "start-pm2": "pm2 start ./bin/www --name Server --node-args='--max-old-space-size=1024' --time"
9 | },
10 | "dependencies": {
11 | "axios": "^1.4.0",
12 | "bcrypt": "^5.1.0",
13 | "callsite": "^1.0.0",
14 | "cookie-parser": "~1.4.4",
15 | "cors": "^2.8.5",
16 | "cron": "^2.4.0",
17 | "crypto": "^1.0.1",
18 | "crypto-js": "^4.1.1",
19 | "debug": "^2.6.9",
20 | "dotenv": "^16.0.3",
21 | "events": "^3.3.0",
22 | "exceljs": "^4.3.0",
23 | "express": "~4.16.1",
24 | "express-async-errors": "^3.1.1",
25 | "express-validator": "^7.0.1",
26 | "fs": "0.0.1-security",
27 | "http-build-query": "^0.7.0",
28 | "http-errors": "^1.6.3",
29 | "jade": "~1.11.0",
30 | "jsonwebtoken": "^9.0.1",
31 | "lodash": "^4.17.21",
32 | "log-symbols": "^4.0.0",
33 | "mongoose": "^7.4.1",
34 | "morgan": "^1.9.1",
35 | "nodemailer": "^6.9.2",
36 | "nodemon": "^2.0.22",
37 | "nonce": "^1.0.4",
38 | "path": "^0.12.7",
39 | "pm2": "^5.3.0",
40 | "querystring": "^0.2.1",
41 | "redis": "^3.0.2",
42 | "request-ip": "^3.3.0",
43 | "socket.io": "^2.3.0",
44 | "tempfile": "^3.0.0",
45 | "uuid": "^9.0.0",
46 | "winston": "^3.8.2",
47 | "winston-daily-rotate-file": "^4.7.1",
48 | "ws": "^8.13.0",
49 | "yargs": "^17.7.2"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/server/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
--------------------------------------------------------------------------------
/server/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require("express");
2 | const indexController = require("../controllers/indexController");
3 | var router = express.Router();
4 |
5 | /* GET home page. */
6 |
7 | router.get("/getusdrates", indexController.getUSDRates);
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/server/routes/spreadBot.js:
--------------------------------------------------------------------------------
1 | var express = require("express");
2 | const spreadBotController = require("../controllers/spreadBotController");
3 | var router = express.Router();
4 | const RequireAdmin = require("../middlewares/requireAdmin");
5 |
6 | /* GET home page. */
7 | router.post("/addorder", RequireAdmin, spreadBotController.addOrder);
8 | router.post("/cancelorder", RequireAdmin, spreadBotController.cancelOrder);
9 | router.get("/getorders", RequireAdmin, spreadBotController.getOrders);
10 | router.post(
11 | "/getorderdetails",
12 | RequireAdmin,
13 | spreadBotController.getOrderDetails
14 | );
15 |
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/server/views/error.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= message
5 | h2= error.status
6 | pre #{error.stack}
7 |
--------------------------------------------------------------------------------
/server/views/index.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= title
5 | p Welcome to #{title}
6 |
--------------------------------------------------------------------------------
/server/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title= title
5 | link(rel='stylesheet', href='/stylesheets/style.css')
6 | body
7 | block content
8 |
--------------------------------------------------------------------------------