├── .circleci ├── ci_increase_chart_version.sh └── config.yml ├── .dockerignore ├── .env.template ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── .nvmrc ├── Dockerfile ├── LICENSE ├── README.md ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── ether.png ├── favicon.png ├── index.html ├── manifest.json ├── omg_logo.svg ├── robots.txt └── serve.json └── src ├── actions ├── __tests__ │ ├── createAction.test.js │ ├── networkAction.test.js │ ├── setupAction.test.js │ ├── tokenAction.test.js │ └── uiAction.test.js ├── createAction.js ├── networkAction.js ├── setupAction.js ├── tokenAction.js └── uiAction.js ├── components ├── alert │ ├── Alert.js │ └── Alert.module.scss ├── button │ ├── Button.js │ └── Button.module.scss ├── copy │ ├── Copy.js │ └── Copy.module.scss ├── gaspicker │ ├── GasPicker.js │ └── GasPicker.module.scss ├── hamburger │ ├── Hamburger.js │ └── Hamburger.module.scss ├── info │ ├── Info.js │ └── Info.module.scss ├── input │ ├── Input.js │ └── Input.module.scss ├── inputselect │ ├── InputSelect.js │ └── InputSelect.module.scss ├── mobileheader │ ├── MobileHeader.js │ └── MobileHeader.module.scss ├── mobilemenu │ ├── MobileMenu.js │ └── MobileMenu.module.scss ├── modal │ └── Modal.js ├── pager │ ├── Pager.js │ └── Pager.module.scss ├── select │ ├── Select.js │ └── Select.module.scss ├── tabs │ ├── Tabs.js │ └── Tabs.module.scss ├── tooltip │ ├── Tooltip.js │ └── Tooltip.module.scss ├── transaction │ ├── Transaction.js │ └── Transaction.module.scss └── walletpicker │ ├── WalletPicker.js │ └── WalletPicker.module.scss ├── containers ├── account │ ├── Account.js │ └── Account.module.scss ├── app │ ├── App.js │ └── App.module.scss ├── home │ ├── Home.js │ └── Home.module.scss ├── modals │ ├── deposit │ │ ├── DepositModal.js │ │ ├── DepositModal.module.scss │ │ └── steps │ │ │ ├── ApproveStep.js │ │ │ └── InputStep.js │ ├── exit │ │ ├── ExitModal.js │ │ ├── ExitModal.module.scss │ │ └── steps │ │ │ ├── AddTokenStep.js │ │ │ ├── DoExitStep.js │ │ │ └── SelectStep.js │ ├── ledger │ │ ├── LedgerConnect.js │ │ ├── LedgerConnect.module.scss │ │ ├── LedgerPrompt.js │ │ └── LedgerPrompt.module.scss │ ├── merge │ │ ├── MergeModal.js │ │ └── MergeModal.module.scss │ ├── processexit │ │ ├── ProcessExitsModal.js │ │ └── ProcessExitsModal.module.scss │ ├── transfer │ │ ├── TransferModal.js │ │ └── TransferModal.module.scss │ └── wrongnetwork │ │ ├── WrongNetworkModal.js │ │ └── WrongNetworkModal.module.scss ├── status │ ├── Status.js │ └── Status.module.scss └── transactions │ ├── Deposits.js │ ├── Exits.js │ ├── Transactions.js │ └── Transactions.module.scss ├── fonts ├── MessinaSans-Regular.otf └── MessinaSansMono-Regular.otf ├── images ├── arrow.png ├── boxarrow.svg ├── browserwallet.png ├── chevron.svg ├── close.png ├── coinbase.jpg ├── connect.svg ├── eth.svg ├── key.svg ├── ledger.png ├── ledger_connect.png ├── lock.svg ├── omg_logo.svg └── walletconnect.png ├── index.js ├── index.module.scss ├── reducers ├── __tests__ │ ├── balanceReducer.test.js │ ├── depositReducer.test.js │ ├── exitReducer.test.js │ ├── feeReducer.test.js │ ├── gasReducer.test.js │ ├── loadingReducer.test.js │ ├── queueReducer.test.js │ ├── setupReducer.test.js │ ├── statusReducer.test.js │ ├── tokenReducer.test.js │ ├── transactionReducer.test.js │ └── uiReducer.test.js ├── balanceReducer.js ├── depositReducer.js ├── exitReducer.js ├── feeReducer.js ├── gasReducer.js ├── index.js ├── loadingReducer.js ├── queueReducer.js ├── setupReducer.js ├── statusReducer.js ├── tokenReducer.js ├── transactionReducer.js └── uiReducer.js ├── selectors ├── balanceSelector.js ├── exitSelector.js ├── feeSelector.js ├── gasSelector.js ├── loadingSelector.js ├── queueSelector.js ├── setupSelector.js ├── statusSelector.js ├── transactionSelector.js └── uiSelector.js ├── services ├── __mocks__ │ └── networkService.js ├── errorService.js └── networkService.js ├── store ├── __mocks__ │ └── index.js └── index.js └── util ├── __tests__ └── amountConvert.test.js ├── amountConvert.js ├── config.js ├── networkName.js └── useInterval.js /.circleci/ci_increase_chart_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | """ 4 | This is the script that would send a dispatch event to the helm chart repo to auto increase chart version. 5 | You can set the UPDATE_DEV flag to decide whether to update to dev too. 6 | For master, we increase the chart version and update dev together. The app version should be short git sha with length 7. 7 | For release, we increase the chart version only. The app version should be semver. (eg. 1.0.3-pre.0) 8 | Required env vars: 9 | - CHART_NAME (eg. webwallet) 10 | - APP_VERSION (eg. 3d75118) 11 | - HELM_CHART_REPO (eg. helm-devlopement) 12 | - UPDATE_DEV (true/false) 13 | - GITHUB_API_TOKEN 14 | """ 15 | 16 | set -ex 17 | 18 | [ -z "$CHART_NAME" ] && echo "CHART_NAME should be set" && exit 1 19 | [ -z "$APP_VERSION" ] && echo "APP_VERSION should be set" && exit 1 20 | [ -z "$HELM_CHART_REPO" ] && echo "HELM_CHART_REPO should be set" && exit 1 21 | [ -z "$UPDATE_DEV" ] && echo "UPDATE_DEV should be set" && exit 1 22 | [ -z "$GITHUB_API_TOKEN" ] && echo "GITHUB_API_TOKEN should be set" && exit 1 23 | 24 | 25 | echo "increase chart version: chart [${CHART_NAME}], appVersion: [${APP_VERSION}], update_dev: [${UPDATE_DEV}]" 26 | 27 | curl --location --request POST "https://api.github.com/repos/omgnetwork/${HELM_CHART_REPO}/dispatches" \ 28 | --header "Accept: application/vnd.github.v3+json" \ 29 | --header "authorization: token ${GITHUB_API_TOKEN}" \ 30 | --header "Content-Type: application/json" \ 31 | --data-raw " { \ 32 | \"event_type\": \"increase-chart-version\", \ 33 | \"client_payload\": { \ 34 | \"chart_name\": \"${CHART_NAME}\", \ 35 | \"app_version\": \"${APP_VERSION}\", \ 36 | \"update_dev\": \"${UPDATE_DEV}\" \ 37 | } \ 38 | }" 39 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | increase_chart_version: 3 | docker: 4 | - image: cimg/base:2020.01 5 | environment: 6 | CHART_NAME: webwallet 7 | HELM_CHART_REPO: helm-development 8 | UPDATE_DEV: true 9 | steps: 10 | - checkout 11 | - run: APP_VERSION="${CIRCLE_TAG}" sh .circleci/ci_increase_chart_version.sh 12 | 13 | release: 14 | docker: 15 | - image: node:15.2.1 16 | steps: 17 | - checkout 18 | - run: npx -y semantic-release@17.2.3 19 | test: 20 | docker: 21 | - image: node:12.16.1-alpine3.11 22 | steps: 23 | - checkout 24 | - run: | 25 | apk update && apk upgrade 26 | apk add --no-cache git openssh make gcc g++ python 27 | - run: npm install --unsafe-perm 28 | - run: npm run audit-check 29 | - run: npm run lint 30 | - run: npm run test 31 | - run: npm run build 32 | orbs: 33 | gcp-gcr: circleci/gcp-gcr@0.8.0 34 | version: 2.1 35 | workflows: 36 | tagged: 37 | jobs: 38 | - gcp-gcr/add-image-tag: 39 | context: 40 | - production-docker-push 41 | filters: 42 | tags: 43 | only: /.*/ 44 | branches: 45 | ignore: /.*/ 46 | gcloud-service-key: PRODUCTION_DOCKER_GCLOUD_KEY 47 | image: $CIRCLE_PROJECT_REPONAME 48 | source-tag: $CIRCLE_SHA1 49 | target-tag: $CIRCLE_TAG 50 | - increase_chart_version: 51 | filters: 52 | tags: 53 | only: /.*/ 54 | branches: 55 | ignore: /.*/ 56 | requires: 57 | - gcp-gcr/add-image-tag 58 | untagged: 59 | jobs: 60 | - test: 61 | filters: 62 | tags: 63 | ignore: /.*/ 64 | - gcp-gcr/build-and-push-image: 65 | context: 66 | - production-docker-push 67 | filters: 68 | branches: 69 | only: /^master$/ 70 | tags: 71 | ignore: /.*/ 72 | gcloud-service-key: PRODUCTION_DOCKER_GCLOUD_KEY 73 | image: $CIRCLE_PROJECT_REPONAME 74 | requires: 75 | - test 76 | tag: $CIRCLE_SHA1 77 | - release: 78 | filters: 79 | branches: 80 | only: /^master$/ 81 | tags: 82 | ignore: /.*/ 83 | requires: 84 | - gcp-gcr/build-and-push-image 85 | version: 2 86 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # add git-ignore syntax here of things you don't want copied into docker image 2 | 3 | .git 4 | *Dockerfile* 5 | *docker-compose* 6 | node_modules 7 | build 8 | .circleci 9 | .nvmrc 10 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | REACT_APP_WATCHER_URL= https://watcher-info.omg.network 2 | REACT_APP_PLASMA_ADDRESS= 0xplasmaframeworkaddress 3 | REACT_APP_BLOCKEXPLORER_URL= https://blockexplorer.omg.network 4 | REACT_APP_ETHERSCAN_URL= https://ropsten.etherscan.io 5 | REACT_APP_SYNC_INTERVAL= 120 6 | REACT_APP_POLL_INTERVAL= 20 7 | REACT_APP_NETWORK= ropsten 8 | 9 | REACT_APP_ALTERNATE_WALLETS= Mainnet,https://webwallet.mainnet.omg.network|Rinkeby,https://webwallet.rinkeby.omg.network 10 | REACT_APP_SENTRY_DSN= https://sentrydsn.com 11 | REACT_APP_GTM_ID= GTM-XXXXXX 12 | REACT_APP_RPC_PROXY= https://customnode.com 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/* 2 | node_modules/ 3 | public/ 4 | .circleci 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:react/recommended" 5 | ], 6 | "plugins": [ 7 | "react" 8 | ], 9 | "env": { 10 | "browser": true, 11 | "node": true, 12 | "jest": true, 13 | "es6": true 14 | }, 15 | "rules": { 16 | "eol-last": ["error", "always"], 17 | "object-curly-spacing": ["error", "always"], 18 | "array-bracket-spacing": ["error", "always"], 19 | "space-before-function-paren": ["error", "always"], 20 | "comma-dangle": ["error", "never"], 21 | "semi": ["error", "always"], 22 | "quotes": ["error", "single"], 23 | "no-case-declarations": "off", 24 | "react/prop-types": "off", 25 | "no-unused-vars": "off", 26 | "indent": ["error", 2, { "SwitchCase": 1 }], 27 | "no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }], 28 | "no-trailing-spaces": "error" 29 | }, 30 | "parserOptions": { 31 | "ecmaFeatures": { 32 | "jsx": true 33 | }, 34 | "ecmaVersion": 11, 35 | "sourceType": "module" 36 | }, 37 | "settings": { 38 | "react": { 39 | "pragma": "React", 40 | "version": "detect" 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /.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 | .DS_Store 16 | .env 17 | .env.development 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # generated runtime envs 24 | public/env.js 25 | 26 | # enforce npm 27 | yarn.lock 28 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12.16.1 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.16.1-alpine3.11 2 | 3 | RUN apk update && apk upgrade && \ 4 | apk add --no-cache git openssh make gcc g++ python 5 | 6 | RUN addgroup -g 10000 -S omg && \ 7 | adduser -u 10000 -S omg -G omg 8 | USER omg 9 | WORKDIR /home/omg 10 | COPY --chown=omg:omg package.json . 11 | COPY --chown=omg:omg package-lock.json . 12 | 13 | RUN npm install 14 | 15 | COPY --chown=omg:omg . . 16 | RUN npm run build 17 | 18 | EXPOSE 3000 19 | CMD npm run serve 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Wallet 2 | 3 | [![CircleCI](https://circleci.com/gh/omgnetwork/web-wallet.svg?style=svg)](https://circleci.com/gh/omgnetwork/web-wallet) 4 | 5 | This is an example client side wallet built with React.js which allows you to make interactions with the OMG network from the browser. 6 | To run this application locally, make sure you have a local instance of elixir-omg running or have access to an already deployed network. 7 | 8 | - This example application is using [`omg-js`](https://github.com/omgnetwork/omg-js) 9 | - Requires Node 12.16.1 10 | 11 | ## Initial Setup 12 | 13 | 1. Install dependencies by running `npm install` from the root 14 | 15 | 2. Create a `.env` file in the root and add your configuration. See `.env.template` for an example with fake variables. 16 | 17 | ```env 18 | REACT_APP_WATCHER_URL= the watcher url 19 | REACT_APP_PLASMA_ADDRESS= the plasma framework address 20 | REACT_APP_BLOCKEXPLORER_URL= the block explorer url 21 | REACT_APP_ETHERSCAN_URL= the etherscan url (https://etherscan.io, etc.) 22 | REACT_APP_SYNC_INTERVAL= max number of blocks that watcher has to sync to the child chain before allowing further transactions 23 | REACT_APP_POLL_INTERVAL= number of seconds to poll account data 24 | REACT_APP_NETWORK= the network your environment is on (ropsten, rinkeby, private, main, etc.) 25 | REACT_APP_ALTERNATE_WALLETS= *optional* other web wallets hosted on different envs, follow this format -> name,url|name,url|name,url 26 | REACT_APP_SENTRY_DSN= *optional* sentry dsn handler 27 | REACT_APP_GTM_ID= *optional* google tag manager id (GTM-XXXXXXX) 28 | REACT_APP_RPC_PROXY= *optional, required for WalletConnect support* rpc url for connection to a remote ethereum node 29 | ``` 30 | 31 | 3. Make sure you are using the correct version of Node 32 | 33 | 4. Start the app by running `npm run start` from the root directory. 34 | 35 | ## Running the wallet locally 36 | 37 | Open up your browser and navigate to `http://localhost:3000`. 38 | 39 | From here, you can perform these actions: 40 | 41 | 1. Deposit into the OMG Network. 42 | 43 | 2. Transfer funds on the OMG Network. 44 | 45 | 3. Exit your funds back to the Rootchain. 46 | 47 | 4. Process exits to receive your funds back on the Rootchain. 48 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-wallet", 3 | "version": "1.0.0", 4 | "private": true, 5 | "engines": { 6 | "node": ">=12.16.1" 7 | }, 8 | "dependencies": { 9 | "@ledgerhq/hw-app-eth": "^5.27.2", 10 | "@ledgerhq/hw-transport-webusb": "^5.23.0", 11 | "@material-ui/core": "^4.8.3", 12 | "@material-ui/icons": "^4.5.1", 13 | "@material-ui/lab": "^4.0.0-alpha.39", 14 | "@metamask/legacy-web3": "^2.0.0", 15 | "@omisego/omg-js": "^4.1.2-1.0.4", 16 | "@sentry/react": "^5.21.4", 17 | "@walletconnect/web3-provider": "^1.3.6", 18 | "axios": "^0.21.1", 19 | "bignumber.js": "^9.0.0", 20 | "bn.js": "^5.1.1", 21 | "buffer": "^5.6.0", 22 | "elliptic": "^6.5.3", 23 | "eth-sig-util": "^2.5.3", 24 | "ethereumjs-abi": "^0.6.8", 25 | "ethereumjs-util": "^7.0.5", 26 | "human-standard-token-abi": "^2.0.0", 27 | "json5": "^2.1.2", 28 | "lodash": "^4.17.20", 29 | "moment": "^2.24.0", 30 | "node-sass": "^4.13.0", 31 | "numbro": "^2.1.2", 32 | "omg-json-bigint": "^1.0.0", 33 | "react": "^16.12.0", 34 | "react-copy-to-clipboard": "^5.0.2", 35 | "react-dom": "^16.12.0", 36 | "react-gtm-module": "^2.0.8", 37 | "react-redux": "^7.1.3", 38 | "react-scripts": "^4.0.3", 39 | "redux": "^4.0.5", 40 | "redux-devtools-extension": "^2.13.8", 41 | "redux-mock-store": "^1.5.4", 42 | "redux-thunk": "^2.3.0", 43 | "serve": "^11.3.2", 44 | "truncate-middle": "^1.0.6", 45 | "walletlink": "^2.0.2", 46 | "web3": "1.3.4" 47 | }, 48 | "scripts": { 49 | "preinstall": "npx npm-force-resolutions", 50 | "buildenv-dev": "react-env", 51 | "buildenv-prod": "NODE_ENV=production react-env --dest build", 52 | "serve": "npm run buildenv-prod && serve -s build -l 3000 -c public/serve.json", 53 | "start": "npm run buildenv-dev && react-scripts start", 54 | "build": "GENERATE_SOURCEMAP=false react-scripts build", 55 | "lint": "eslint . --ext .js,.jsx", 56 | "test": "react-scripts test --watchAll=false", 57 | "test:coverage": "npm run test --coverage", 58 | "audit-check": "audit-ci --moderate" 59 | }, 60 | "eslintConfig": { 61 | "extends": "react-app" 62 | }, 63 | "browserslist": { 64 | "production": [ 65 | ">0.2%", 66 | "not dead", 67 | "not op_mini all" 68 | ], 69 | "development": [ 70 | "last 1 chrome version", 71 | "last 1 firefox version", 72 | "last 1 safari version" 73 | ] 74 | }, 75 | "devDependencies": { 76 | "@beam-australia/react-env": "2.1.2", 77 | "audit-ci": "^3.1.1" 78 | }, 79 | "resolutions": { 80 | "http-proxy": "^1.18.1", 81 | "elliptic": "^6.5.3", 82 | "object-path": "^0.11.5", 83 | "node-forge": "^0.10.0" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /public/ether.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/public/ether.png -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/public/favicon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | OMG Network | Web Wallet 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "OMG Network | Web Wallet", 3 | "name": "OMG Network | Web Wallet", 4 | "icons": [ 5 | { 6 | "src": "favicon.png", 7 | "type": "image/png", 8 | "sizes": "236x236" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/omg_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /public/serve.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": [ 3 | { 4 | "source": "*", 5 | "headers": [ 6 | { 7 | "key": "X-Frame-Options", 8 | "value": "SAMEORIGIN" 9 | }, 10 | { 11 | "key": "Strict-Transport-Security", 12 | "value": "max-age=15552000; includeSubDomains" 13 | }, 14 | { 15 | "key": "X-Content-Type-Options", 16 | "value": "nosniff" 17 | }, 18 | { 19 | "key": "X-XSS-Protection", 20 | "value": "1; mode=block" 21 | }, 22 | { 23 | "key": "Feature-Policy", 24 | "value": "geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; vibrate 'none'; fullscreen 'self'; payment 'none';" 25 | }, 26 | { 27 | "key": "Referrer-Policy", 28 | "value": "no-referrer" 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /src/actions/__tests__/createAction.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { createAction } from 'actions/createAction'; 17 | import store from 'store'; 18 | 19 | jest.mock('store'); 20 | jest.mock('services/networkService'); 21 | 22 | function fakeAsyncRequestSuccess () { 23 | return Promise.resolve('toto-success'); 24 | } 25 | 26 | function fakeAsyncRequestFailure () { 27 | return Promise.reject(Error('toto-failed')); 28 | } 29 | 30 | describe('createAction', () => { 31 | beforeEach(() => { 32 | store.clearActions(); 33 | jest.clearAllMocks(); 34 | }); 35 | 36 | it('should return false to caller on async failure', async () => { 37 | const res = await store.dispatch( 38 | createAction('TEST/GET', () => fakeAsyncRequestFailure()) 39 | ); 40 | expect(res).toBe(false); 41 | }); 42 | 43 | it('should return true to caller on async success', async () => { 44 | const res = await store.dispatch( 45 | createAction('TEST/GET', () => fakeAsyncRequestSuccess()) 46 | ); 47 | expect(res).toBe(true); 48 | }); 49 | 50 | it('should dispatch request/success on successful async call', async () => { 51 | const expectedActions = [ 52 | { type: 'TEST/GET/REQUEST' }, 53 | { type: 'TEST/GET/SUCCESS', payload: 'toto-success' } 54 | ]; 55 | await store.dispatch( 56 | createAction('TEST/GET', () => fakeAsyncRequestSuccess()) 57 | ); 58 | expect(store.getActions()).toEqual(expectedActions); 59 | }); 60 | 61 | it('should dispatch request/error/uiError on failure of async call', async () => { 62 | const expectedActions = [ 63 | { type: 'TEST/GET/REQUEST' }, 64 | { type: 'TEST/GET/ERROR' }, 65 | { type: 'UI/ERROR/UPDATE', payload: 'Something went wrong' } 66 | ]; 67 | await store.dispatch( 68 | createAction('TEST/GET', () => fakeAsyncRequestFailure()) 69 | ); 70 | expect(store.getActions()).toEqual(expectedActions); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /src/actions/__tests__/setupAction.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import * as actions from 'actions/setupAction'; 17 | import store from 'store'; 18 | 19 | jest.mock('store'); 20 | 21 | describe('setupActions', () => { 22 | beforeEach(() => { 23 | store.clearActions(); 24 | jest.clearAllMocks(); 25 | }); 26 | 27 | it('should dispatch correct actions on setWalletMethod', async () => { 28 | const expectedActions = [ { type: 'SETUP/WALLET_METHOD/SET', payload: 'WalletLink' } ]; 29 | await store.dispatch(actions.setWalletMethod('WalletLink')); 30 | expect(store.getActions()).toEqual(expectedActions); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/actions/__tests__/tokenAction.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { getToken } from 'actions/tokenAction'; 17 | import networkService from 'services/networkService'; 18 | import store from 'store'; 19 | 20 | jest.mock('services/networkService'); 21 | jest.mock('store'); 22 | 23 | describe('tokenAction', () => { 24 | beforeEach(() => { 25 | store.clearActions(); 26 | jest.clearAllMocks(); 27 | }); 28 | 29 | it('should return token information using getToken', async () => { 30 | const tokenInfo = await getToken('0x123'); 31 | // expect(networkService.web3.eth.Contract).toHaveBeenCalled(); 32 | expect(tokenInfo).toEqual({ 33 | currency: '0x123', 34 | decimals: 18, 35 | name: 'OMG' 36 | }); 37 | }); 38 | 39 | it('should return early if token info already fetched', async () => { 40 | await getToken('0x0000000000000000000000000000000000000000'); 41 | // expect(networkService.web3.eth.Contract).not.toHaveBeenCalled(); 42 | expect(store.getActions()).toEqual([]); 43 | }); 44 | 45 | it('should dispatch token success using getToken', async () => { 46 | await getToken('0x123'); 47 | const expectedActions = [ { 48 | type: 'TOKEN/GET/SUCCESS', 49 | payload: { 50 | currency: '0x123', 51 | decimals: 18, 52 | name: 'OMG' 53 | } 54 | } ]; 55 | expect(store.getActions()).toEqual(expectedActions); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/actions/__tests__/uiAction.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import * as actions from 'actions/uiAction'; 17 | import store from 'store'; 18 | 19 | jest.mock('store'); 20 | 21 | describe('uiActions', () => { 22 | beforeEach(() => { 23 | store.clearActions(); 24 | jest.clearAllMocks(); 25 | }); 26 | 27 | it('should dispatch correct actions on openModal', async () => { 28 | const expectedActions = [ { type: 'UI/MODAL/OPEN', payload: 'toto' } ]; 29 | await store.dispatch(actions.openModal('toto')); 30 | expect(store.getActions()).toEqual(expectedActions); 31 | }); 32 | 33 | it('should dispatch correct actions on closeModal', async () => { 34 | const expectedActions = [ { type: 'UI/MODAL/CLOSE', payload: 'toto' } ]; 35 | await store.dispatch(actions.closeModal('toto')); 36 | expect(store.getActions()).toEqual(expectedActions); 37 | }); 38 | 39 | it('should dispatch correct actions on openAlert', async () => { 40 | const expectedActions = [ { type: 'UI/ALERT/UPDATE', payload: 'toto' } ]; 41 | await store.dispatch(actions.openAlert('toto')); 42 | expect(store.getActions()).toEqual(expectedActions); 43 | }); 44 | 45 | it('should dispatch correct actions on closeAlert', async () => { 46 | const expectedActions = [ { type: 'UI/ALERT/UPDATE', payload: null } ]; 47 | await store.dispatch(actions.closeAlert()); 48 | expect(store.getActions()).toEqual(expectedActions); 49 | }); 50 | 51 | it('should dispatch correct actions on openError', async () => { 52 | const expectedActions = [ { type: 'UI/ERROR/UPDATE', payload: 'toto' } ]; 53 | await store.dispatch(actions.openError('toto')); 54 | expect(store.getActions()).toEqual(expectedActions); 55 | }); 56 | 57 | it('should dispatch correct actions on closeError', async () => { 58 | const expectedActions = [ { type: 'UI/ERROR/UPDATE', payload: null } ]; 59 | await store.dispatch(actions.closeError()); 60 | expect(store.getActions()).toEqual(expectedActions); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/actions/createAction.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { WebWalletError } from 'services/errorService'; 17 | 18 | export function createAction (key, asyncAction) { 19 | return async function (dispatch) { 20 | dispatch({ type: `${key}/REQUEST` }); 21 | try { 22 | const response = await asyncAction(); 23 | dispatch({ type: `${key}/SUCCESS`, payload: response }); 24 | return true; 25 | } catch (error) { 26 | // cancel request loading state 27 | dispatch({ type: `${key}/ERROR` }); 28 | 29 | const _error = error instanceof WebWalletError 30 | ? error 31 | : new WebWalletError({ 32 | originalError: error, 33 | customErrorMessage: 'Something went wrong', 34 | reportToSentry: true, 35 | reportToUi: true 36 | }); 37 | 38 | // perform necessary reports 39 | _error.report(dispatch); 40 | return false; 41 | } 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/actions/setupAction.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function setWalletMethod (methodName) { 17 | return function (dispatch) { 18 | return dispatch({ type: 'SETUP/WALLET_METHOD/SET', payload: methodName }); 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/actions/tokenAction.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import erc20abi from 'human-standard-token-abi'; 17 | import networkService from 'services/networkService'; 18 | import truncate from 'truncate-middle'; 19 | import store from 'store'; 20 | 21 | export async function getToken (_currency) { 22 | const currency = _currency.toLowerCase(); 23 | 24 | const state = store.getState(); 25 | if (state.token[currency]) { 26 | return state.token[currency]; 27 | } 28 | 29 | const tokenContract = new networkService.web3.eth.Contract(erc20abi, currency); 30 | 31 | //this breaks web3.js 1.3.4 32 | //const callOptions = { from: currency }; 33 | //tokenContract.methods.symbol().call(callOptions) will fail 34 | 35 | const [ _name, _decimals ] = await Promise.all([ 36 | tokenContract.methods.symbol().call(), 37 | tokenContract.methods.decimals().call() 38 | ]).catch(e => [ null, null ]); 39 | 40 | const decimals = _decimals ? Number(_decimals.toString()) : 0; 41 | const name = _name || truncate(currency, 6, 4, '...'); 42 | 43 | const tokenInfo = { 44 | currency, 45 | decimals, 46 | name 47 | }; 48 | 49 | store.dispatch({ 50 | type: 'TOKEN/GET/SUCCESS', 51 | payload: tokenInfo 52 | }); 53 | return tokenInfo; 54 | } 55 | -------------------------------------------------------------------------------- /src/actions/uiAction.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function openModal (modal) { 17 | return function (dispatch) { 18 | return dispatch({ type: 'UI/MODAL/OPEN', payload: modal }); 19 | }; 20 | } 21 | 22 | export function closeModal (modal) { 23 | return function (dispatch) { 24 | return dispatch({ type: 'UI/MODAL/CLOSE', payload: modal }); 25 | }; 26 | } 27 | 28 | export function openAlert (message) { 29 | return function (dispatch) { 30 | return dispatch({ type: 'UI/ALERT/UPDATE', payload: message }); 31 | }; 32 | } 33 | 34 | export function closeAlert () { 35 | return function (dispatch) { 36 | return dispatch({ type: 'UI/ALERT/UPDATE', payload: null }); 37 | }; 38 | } 39 | 40 | export function openError (message) { 41 | return function (dispatch) { 42 | return dispatch({ type: 'UI/ERROR/UPDATE', payload: message }); 43 | }; 44 | } 45 | 46 | export function closeError () { 47 | return function (dispatch) { 48 | return dispatch({ type: 'UI/ERROR/UPDATE', payload: null }); 49 | }; 50 | } 51 | 52 | export function ledgerConnect (derivation) { 53 | return function (dispatch) { 54 | return dispatch({ type: 'UI/LEDGER/UPDATE', payload: derivation }); 55 | }; 56 | } 57 | 58 | export function setActiveHistoryTab (tab) { 59 | return function (dispatch) { 60 | return dispatch({ type: 'UI/HISTORYTAB/UPDATE', payload: tab }); 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/components/alert/Alert.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { Snackbar } from '@material-ui/core'; 18 | import MuiAlert from '@material-ui/lab/Alert'; 19 | 20 | function _Alert ({ children, open, onClose, type = 'success', duration = 3000 }) { 21 | function Alert (props) { 22 | return ; 23 | } 24 | 25 | return ( 26 | 35 | 36 | {children} 37 | 38 | 39 | ); 40 | } 41 | 42 | export default _Alert; 43 | -------------------------------------------------------------------------------- /src/components/alert/Alert.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | -------------------------------------------------------------------------------- /src/components/button/Button.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { CircularProgress } from '@material-ui/core'; 18 | 19 | import Tooltip from 'components/tooltip/Tooltip'; 20 | 21 | import * as styles from './Button.module.scss'; 22 | 23 | function Button ({ 24 | children, 25 | style, 26 | onClick, 27 | type, 28 | disabled, 29 | loading, 30 | tooltip = '', 31 | className 32 | }) { 33 | return ( 34 |
47 | {children} 48 | {loading && ( 49 | 50 |
51 | 52 |
53 |
54 | )} 55 |
56 | ); 57 | } 58 | 59 | export default React.memo(Button); 60 | -------------------------------------------------------------------------------- /src/components/button/Button.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Button { 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | color: $gray6; 8 | padding: 15px; 9 | flex: 1; 10 | cursor: pointer; 11 | transition: all 200ms ease-in-out; 12 | min-width: 150px; 13 | @include mobile { 14 | min-width: 100px; 15 | } 16 | } 17 | 18 | .primary { 19 | background-color: $blue; 20 | } 21 | 22 | .secondary { 23 | background-color: $gray4; 24 | } 25 | 26 | .outline { 27 | border: 2px solid $gray4; 28 | } 29 | 30 | .disabled { 31 | filter: brightness(50%); 32 | cursor: initial; 33 | } 34 | 35 | .loading { 36 | margin: 0 -20px 0 10px !important; 37 | } -------------------------------------------------------------------------------- /src/components/copy/Copy.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState } from 'react'; 17 | import { CopyToClipboard } from 'react-copy-to-clipboard'; 18 | import { FileCopyOutlined } from '@material-ui/icons'; 19 | 20 | import Alert from 'components/alert/Alert'; 21 | 22 | import * as styles from './Copy.module.scss'; 23 | 24 | function Copy ({ value, light }) { 25 | const [ open, setOpen ] = useState(false); 26 | 27 | return ( 28 |
29 | setOpen(true)} 32 | > 33 |
38 | 39 |
40 |
41 | setOpen(false)}> 42 | Copied to clipboard! 43 | 44 |
45 | ); 46 | } 47 | 48 | export default React.memo(Copy); 49 | -------------------------------------------------------------------------------- /src/components/copy/Copy.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Copy { 4 | .icon { 5 | cursor: pointer; 6 | background-color: $gray3; 7 | border-radius: 100%; 8 | width: 25px; 9 | height: 25px; 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | 14 | svg { 15 | width: 12px; 16 | height: 12px; 17 | } 18 | } 19 | 20 | .light { 21 | background-color: $gray3; 22 | color: $gray6; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/gaspicker/GasPicker.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useEffect } from 'react'; 17 | import { useSelector } from 'react-redux'; 18 | 19 | import { selectGas } from 'selectors/gasSelector'; 20 | 21 | import * as styles from './GasPicker.module.scss'; 22 | 23 | function GasPicker ({ selectedSpeed, setSelectedSpeed, setGasPrice }) { 24 | const gas = useSelector(selectGas); 25 | 26 | useEffect(() => { 27 | setGasPrice(gas[selectedSpeed]); 28 | }, [ selectedSpeed, gas, setGasPrice ]); 29 | 30 | return ( 31 |
32 |
33 | Gas Fee 34 |
35 | 36 |
37 |
setSelectedSpeed('slow')} 39 | className={[ 40 | styles.category, 41 | selectedSpeed === 'slow' ? styles.selected : '' 42 | ].join(' ')} 43 | > 44 |
Slow
45 |
{gas.slow / 1000000000} gwei
46 |
47 | 48 |
setSelectedSpeed('normal')} 50 | className={[ 51 | styles.category, 52 | selectedSpeed === 'normal' ? styles.selected : '' 53 | ].join(' ')} 54 | > 55 |
Normal
56 |
{gas.normal / 1000000000} gwei
57 |
58 | 59 |
setSelectedSpeed('fast')} 61 | className={[ 62 | styles.category, 63 | selectedSpeed === 'fast' ? styles.selected : '' 64 | ].join(' ')} 65 | > 66 |
Fast
67 |
{gas.fast / 1000000000} gwei
68 |
69 |
70 |
71 | ); 72 | } 73 | 74 | export default React.memo(GasPicker); 75 | -------------------------------------------------------------------------------- /src/components/gaspicker/GasPicker.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .GasPicker { 4 | display: flex; 5 | flex-direction: column; 6 | 7 | .label { 8 | margin-bottom: 10px; 9 | } 10 | 11 | .items { 12 | display: flex; 13 | flex-direction: row; 14 | justify-content: space-between; 15 | 16 | .category { 17 | display: flex; 18 | cursor: pointer; 19 | flex: 1; 20 | margin-right: 10px; 21 | flex-direction: column; 22 | justify-content: center; 23 | transition: all 100ms ease-in-out; 24 | padding: 10px; 25 | color: $gray5; 26 | border: 2px solid $gray4; 27 | .title { 28 | font-weight: bold; 29 | color: $gray6; 30 | padding-bottom: 5px; 31 | } 32 | &:last-child { 33 | margin-right: 0px; 34 | } 35 | } 36 | 37 | .selected { 38 | background-color: $gray3; 39 | border: 2px solid $blue; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/hamburger/Hamburger.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import * as styles from './Hamburger.module.scss'; 4 | 5 | function Hamburger ({ hamburgerClick, isOpen, className }) { 6 | return ( 7 |
hamburgerClick()} className={className}> 8 |
15 |
22 |
29 |
30 | ); 31 | } 32 | 33 | export default Hamburger; 34 | -------------------------------------------------------------------------------- /src/components/hamburger/Hamburger.module.scss: -------------------------------------------------------------------------------- 1 | .xline { 2 | height: 2px; 3 | width: 20px; 4 | background-color: white; 5 | margin: 5px 0; 6 | transition: all 250ms ease-in-out; 7 | } 8 | 9 | .xline1 { 10 | transform-origin: top left; 11 | &.open { 12 | transform: rotate(45deg) translateY(0px); 13 | } 14 | &.closed { 15 | transform: initial; 16 | } 17 | } 18 | 19 | .xline2 { 20 | &.open { 21 | opacity: 0; 22 | } 23 | &.closed { 24 | opacity: 1; 25 | } 26 | } 27 | 28 | .xline3 { 29 | transform-origin: bottom left; 30 | &.open { 31 | transform: rotate(-45deg) translateY(0px); 32 | } 33 | &.closed { 34 | transform: initial; 35 | } 36 | } -------------------------------------------------------------------------------- /src/components/info/Info.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | 18 | import * as styles from './Info.module.scss'; 19 | 20 | function Info ({ data }) { 21 | return ( 22 |
23 | {data.map((i, index) => ( 24 |
25 | {i.header && ( 26 |
{i.header}
27 | )} 28 |
29 | 30 | {i.title} 31 | 32 | {i.value} 33 |
34 |
35 | ))} 36 |
37 | ); 38 | } 39 | 40 | export default Info; 41 | -------------------------------------------------------------------------------- /src/components/info/Info.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Info { 4 | display: flex; 5 | flex-direction: column; 6 | 7 | .header { 8 | padding-bottom: 10px; 9 | font-family: 'Messina'; 10 | } 11 | 12 | .item { 13 | display: flex; 14 | flex-direction: row; 15 | align-items: center; 16 | word-break: break-word; 17 | justify-content: space-between; 18 | padding-bottom: 15px; 19 | margin-bottom: 15px; 20 | border-bottom: 1px solid $gray3; 21 | span:last-child { 22 | margin-left: 10px; 23 | } 24 | .headerFont { 25 | font-family: 'Messina'; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/components/input/Input.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { Search } from '@material-ui/icons'; 18 | import BN from 'bignumber.js'; 19 | 20 | import * as styles from './Input.module.scss'; 21 | 22 | function Input ({ 23 | placeholder, 24 | label, 25 | type = 'text', 26 | icon, 27 | unit, 28 | value, 29 | onChange, 30 | paste, 31 | className, 32 | maxValue 33 | }) { 34 | async function handlePaste () { 35 | try { 36 | const text = await navigator.clipboard.readText(); 37 | if (text) { 38 | onChange({ target: { value: text } }); 39 | } 40 | } catch (err) { 41 | // navigator clipboard api not supported in client browser 42 | } 43 | } 44 | 45 | function handleMaxClick () { 46 | onChange({ target: { value: maxValue } }); 47 | } 48 | 49 | const overMax = new BN(value).gt(new BN(maxValue)); 50 | 51 | return ( 52 |
53 | {label &&
{label}
} 54 |
60 | {icon && } 61 | 68 | {unit && ( 69 |
70 | {maxValue && (value !== maxValue) && ( 71 |
75 | MAX 76 |
77 | )} 78 | {unit} 79 |
80 | )} 81 | {paste && ( 82 |
83 | Paste 84 |
85 | )} 86 |
87 |
88 | ); 89 | } 90 | 91 | export default React.memo(Input); 92 | -------------------------------------------------------------------------------- /src/components/input/Input.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Input { 4 | display: flex; 5 | flex-direction: column; 6 | margin-bottom: 10px; 7 | 8 | .label { 9 | font-size: 1em; 10 | margin-bottom: 10px; 11 | } 12 | 13 | .field { 14 | position: relative; 15 | padding: 10px; 16 | border: 2px solid $gray4; 17 | transition: all 200ms ease-in-out; 18 | display: flex; 19 | flex-direction: row; 20 | align-items: center; 21 | &:focus-within { 22 | border: 2px solid $blue; 23 | } 24 | .icon { 25 | margin-right: 10px; 26 | } 27 | .input { 28 | flex: 1; 29 | background-color: $gray3; 30 | color: $gray6; 31 | } 32 | .unit { 33 | margin: 0 10px; 34 | position: absolute; 35 | right: 0; 36 | background-color: $gray3; 37 | display: flex; 38 | flex-direction: row; 39 | align-items: center; 40 | } 41 | .paste { 42 | color: $blue; 43 | margin-left: 10px; 44 | cursor: pointer; 45 | } 46 | &.error { 47 | border: 2px solid $red; 48 | color: $red; 49 | .input { 50 | color: $red; 51 | } 52 | } 53 | } 54 | } 55 | 56 | .maxValue { 57 | background-color: $blue; 58 | opacity: 0.8; 59 | color: white; 60 | padding: 3px 7px; 61 | font-size: 12px; 62 | border-radius: 4px; 63 | margin-right: 10px; 64 | z-index: 1; 65 | cursor: pointer; 66 | transition: all 150ms ease-in-out; 67 | &:active { 68 | opacity: 0.5; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/components/inputselect/InputSelect.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { KeyboardArrowDown } from '@material-ui/icons'; 18 | import Input from 'components/input/Input'; 19 | 20 | import * as styles from './InputSelect.module.scss'; 21 | 22 | function InputSelect ({ 23 | placeholder, 24 | label, 25 | value, 26 | onChange, 27 | selectOptions, 28 | onSelect, 29 | selectValue, 30 | maxValue 31 | }) { 32 | const selected = selectOptions.find(i => i.value === selectValue); 33 | 34 | const renderUnit = ( 35 |
36 | 50 |
51 |
52 |
{selected ? selected.title : ''}
53 |
{selected ? selected.subTitle : ''}
54 |
55 | 56 |
57 |
58 | ); 59 | 60 | return ( 61 | 70 | ); 71 | } 72 | 73 | export default React.memo(InputSelect); 74 | -------------------------------------------------------------------------------- /src/components/inputselect/InputSelect.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .selectContainer { 4 | height: 46px; 5 | margin: -10px -10px -10px 0; 6 | position: relative; 7 | 8 | .select { 9 | border: none; 10 | outline: none; 11 | border-radius: 0; 12 | padding-right: 10px; 13 | -webkit-appearance: none; 14 | -webkit-border-radius: 0px; 15 | background-color: $gray3; 16 | color: $gray3; 17 | position: absolute; 18 | right: 0; 19 | top: 0; 20 | bottom: 0; 21 | opacity: 0; 22 | } 23 | 24 | .selected { 25 | flex: 1; 26 | display: flex; 27 | flex-direction: row; 28 | justify-content: flex-end; 29 | align-items: center; 30 | height: 46px; 31 | margin-right: 10px; 32 | 33 | .details { 34 | text-align: right; 35 | margin-right: 10px; 36 | font-size: 0.9em; 37 | .subTitle { 38 | font-size: 0.7em; 39 | white-space: nowrap; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/components/mobileheader/MobileHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import logo from 'images/omg_logo.svg'; 4 | 5 | import Hamburger from 'components/hamburger/Hamburger'; 6 | import * as styles from './MobileHeader.module.scss'; 7 | 8 | function MobileHeader ({ mobileMenuOpen, onHamburgerClick }) { 9 | return ( 10 |
11 | omg-network 12 | 16 |
17 | ); 18 | } 19 | 20 | export default MobileHeader; 21 | -------------------------------------------------------------------------------- /src/components/mobileheader/MobileHeader.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .MobileHeader { 4 | display: none; 5 | flex-direction: row; 6 | justify-content: space-between; 7 | background-color: $gray1; 8 | align-items: center; 9 | margin-bottom: 15px; 10 | 11 | @include mobile { 12 | display: flex; 13 | } 14 | .logo { 15 | height: 30px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/mobilemenu/MobileMenu.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Status from 'containers/status/Status'; 4 | 5 | import * as styles from './MobileMenu.module.scss'; 6 | 7 | function MobileMenu ({ mobileMenuOpen }) { 8 | return ( 9 | 15 | ); 16 | } 17 | 18 | export default MobileMenu; 19 | -------------------------------------------------------------------------------- /src/components/mobilemenu/MobileMenu.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .menu { 4 | background-color: $gray1; 5 | padding: 15px; 6 | position: fixed; 7 | top: 60px; 8 | bottom: 0; 9 | left: 0; 10 | right: 0; 11 | display: none; 12 | max-width: initial; 13 | z-index: 2; 14 | &.open { 15 | display: flex; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/modal/Modal.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { makeStyles } from '@material-ui/core/styles'; 18 | import { 19 | Modal, 20 | Backdrop, 21 | Fade 22 | } from '@material-ui/core'; 23 | 24 | // Renamed due to https://github.com/facebook/create-react-app/issues/10047 25 | import { gray6, gray3, gray1 } from 'index.module.scss'; 26 | 27 | const useStyles = makeStyles({ 28 | modal: { 29 | display: 'flex', 30 | alignItems: 'center', 31 | justifyContent: 'center', 32 | outline: 'none' 33 | }, 34 | paper: { 35 | backgroundColor: gray3, 36 | padding: '20px', 37 | border: 'none', 38 | outline: 'none', 39 | width: '500px', 40 | boxSizing: 'border-box', 41 | maxWidth: '100%' 42 | }, 43 | light: { 44 | backgroundColor: gray6, 45 | color: gray1, 46 | borderRadius: '4px' 47 | } 48 | }); 49 | 50 | function _Modal ({ 51 | children, 52 | open, 53 | onClose, 54 | light 55 | }) { 56 | const classes = useStyles(); 57 | 58 | return ( 59 | 71 | 72 |
78 | {children} 79 |
80 |
81 |
82 | ); 83 | } 84 | 85 | export default _Modal; 86 | -------------------------------------------------------------------------------- /src/components/pager/Pager.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { NavigateNext, NavigateBefore } from '@material-ui/icons'; 18 | 19 | import * as styles from './Pager.module.scss'; 20 | 21 | function Pager ({ currentPage, isLastPage, onClickNext, onClickBack }) { 22 | return ( 23 |
24 | {`Page ${currentPage}`} 25 |
32 | 33 |
34 |
41 | 42 |
43 |
44 | ); 45 | } 46 | 47 | export default Pager; 48 | -------------------------------------------------------------------------------- /src/components/pager/Pager.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Pager { 4 | display: flex; 5 | flex-direction: row; 6 | justify-content: flex-end; 7 | align-items: center; 8 | margin-bottom: 20px; 9 | 10 | .number { 11 | font-size: 0.8em; 12 | margin-right: 10px; 13 | } 14 | 15 | .box { 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | height: 20px; 20 | margin-left: 3px; 21 | transition: all 200ms ease-in-out; 22 | cursor: pointer; 23 | } 24 | 25 | .disabled { 26 | pointer-events: none; 27 | cursor: initial; 28 | opacity: 0.5; 29 | } 30 | } -------------------------------------------------------------------------------- /src/components/select/Select.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import * as styles from './Select.module.scss'; 18 | 19 | function Select ({ 20 | label, 21 | value, 22 | options, 23 | onSelect, 24 | loading, 25 | error = '', 26 | className 27 | }) { 28 | const selected = options.find(i => i.value === value); 29 | 30 | function renderOption (i) { 31 | if (i.title && i.subTitle) { 32 | return `${i.title} - ${i.subTitle}`; 33 | } 34 | if (i.title && !i.subTitle) { 35 | return i.title; 36 | } 37 | if (i.subTitle && !i.title) { 38 | return i.subTitle; 39 | } 40 | } 41 | 42 | const renderLoading = ( 43 |
44 | Loading... 45 |
46 | ); 47 | 48 | const renderSelect = ( 49 | <> 50 | 64 |
65 |
66 |
{selected ? selected.title : error}
67 |
{selected ? selected.subTitle : ''}
68 |
69 |
70 | 71 | ); 72 | 73 | return ( 74 |
80 | {label &&
{label}
} 81 |
82 | {loading ? renderLoading : renderSelect} 83 |
84 |
85 | ); 86 | } 87 | 88 | export default React.memo(Select); 89 | -------------------------------------------------------------------------------- /src/components/select/Select.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Select { 4 | display: flex; 5 | flex-direction: column; 6 | margin-bottom: 10px; 7 | 8 | .label { 9 | margin-bottom: 10px; 10 | } 11 | 12 | .field { 13 | position: relative; 14 | border: 2px solid $gray4; 15 | transition: all 200ms ease-in-out; 16 | display: flex; 17 | flex-direction: row; 18 | align-items: center; 19 | } 20 | 21 | .select { 22 | border: none; 23 | outline: none; 24 | border-radius: 0; 25 | padding-right: 10px; 26 | -webkit-appearance: none; 27 | -webkit-border-radius: 0px; 28 | background-color: $gray3; 29 | color: $gray3; 30 | position: absolute; 31 | left: 0; 32 | top: 0; 33 | bottom: 0; 34 | opacity: 0; 35 | } 36 | 37 | .selected { 38 | flex: 1; 39 | display: flex; 40 | flex-direction: row; 41 | align-items: center; 42 | height: 50px; 43 | margin-left: 10px; 44 | 45 | .details { 46 | text-align: left; 47 | margin-right: 10px; 48 | font-size: 0.9em; 49 | .subTitle { 50 | font-size: 0.7em; 51 | white-space: nowrap; 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/components/tabs/Tabs.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | 18 | import * as styles from './Tabs.module.scss'; 19 | 20 | function Tabs ({ tabs, activeTab, onClick, className }) { 21 | return ( 22 |
23 | {tabs.map((i, index) => { 24 | return ( 25 |
onClick(i)} 28 | className={[ 29 | styles.tab, 30 | activeTab === i ? styles.active : '' 31 | ].join(' ')} 32 | > 33 | {i} 34 |
35 | ); 36 | })} 37 |
38 | ); 39 | } 40 | 41 | export default React.memo(Tabs); 42 | -------------------------------------------------------------------------------- /src/components/tabs/Tabs.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Tabs { 4 | display: flex; 5 | flex-direction: row; 6 | justify-content: flex-start; 7 | border-bottom: 2px solid $gray4; 8 | flex: 1; 9 | margin-bottom: 20px; 10 | 11 | .tab { 12 | color: $gray5; 13 | transition: color 200ms ease-in-out; 14 | cursor: pointer; 15 | margin-right: 20px; 16 | padding-bottom: 10px; 17 | } 18 | 19 | .active { 20 | color: $gray6; 21 | border-bottom: 2px solid $gray6; 22 | margin-bottom: -2px; 23 | z-index: 1; 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/components/tooltip/Tooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tooltip as MuiTooltip } from '@material-ui/core'; 3 | 4 | import * as styles from './Tooltip.module.scss'; 5 | 6 | function Tooltip ({ 7 | title, 8 | arrow = true, 9 | children 10 | }) { 11 | return ( 12 | 15 | {title} 16 |
17 | } 18 | arrow={arrow} 19 | > 20 | {children} 21 | 22 | ); 23 | } 24 | 25 | export default React.memo(Tooltip); 26 | -------------------------------------------------------------------------------- /src/components/tooltip/Tooltip.module.scss: -------------------------------------------------------------------------------- 1 | .title { 2 | font-size: 14px; 3 | padding: 10px; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/transaction/Transaction.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | 18 | import Tooltip from 'components/tooltip/Tooltip'; 19 | 20 | import * as styles from './Transaction.module.scss'; 21 | 22 | function Transaction ({ 23 | link, 24 | status, 25 | statusPercentage, 26 | subStatus, 27 | button, 28 | title, 29 | midTitle, 30 | subTitle, 31 | tooltip = '' 32 | }) { 33 | function renderValue () { 34 | if (button) { 35 | return ( 36 |
37 |
41 | {button.text} 42 |
43 |
{subStatus}
44 |
45 | ); 46 | } 47 | return ( 48 |
49 |
50 |
58 | {status} 59 | {status === 'Pending' && !!statusPercentage && ( 60 | 61 | 62 | {`(${Math.max(statusPercentage, 0)}%)`} 63 | 64 | 65 | )} 66 |
67 |
{subStatus}
68 |
69 | ); 70 | } 71 | 72 | const Resolved = link ? 'a' : 'div'; 73 | return ( 74 |
75 | 81 |
{title}
82 | {midTitle && ( 83 |
{midTitle}
84 | )} 85 |
{subTitle}
86 |
87 |
88 | {renderValue()} 89 |
90 |
91 | ); 92 | } 93 | 94 | export default React.memo(Transaction); 95 | -------------------------------------------------------------------------------- /src/components/transaction/Transaction.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Transaction { 4 | display: flex; 5 | flex-direction: row; 6 | padding: 20px; 7 | background-color: $gray3; 8 | margin-bottom: 5px; 9 | min-height: 101px; 10 | box-sizing: border-box; 11 | transition: all 200ms ease-in-out; 12 | &:hover { 13 | background-color: $gray2; 14 | } 15 | @include mobile { 16 | flex-direction: column; 17 | padding: 15px 10px; 18 | } 19 | } 20 | 21 | .left { 22 | display: flex; 23 | flex-direction: column; 24 | flex: 1; 25 | div:last-child { 26 | margin-top: 10px; 27 | font-size: 0.7em; 28 | } 29 | @include mobile { 30 | margin-bottom: 10px; 31 | } 32 | } 33 | 34 | .midTitle { 35 | margin-top: 10px; 36 | color: $gray6; 37 | font-size: 0.8em; 38 | } 39 | 40 | .statusContainer { 41 | display: flex; 42 | flex-direction: column; 43 | text-align: right; 44 | align-items: flex-end; 45 | font-size: 0.9em; 46 | @include mobile { 47 | text-align: left; 48 | align-items: flex-start; 49 | } 50 | div:last-child { 51 | margin-top: 10px; 52 | font-size: 0.8em; 53 | } 54 | } 55 | 56 | .status { 57 | display: flex; 58 | flex-direction: row; 59 | align-items: center; 60 | justify-content: flex-end; 61 | div:last-child { 62 | font-size: 0.8em; 63 | } 64 | @include mobile { 65 | flex-direction: row-reverse; 66 | justify-content: flex-end; 67 | } 68 | .indicator { 69 | margin: 0 10px 0 0; 70 | width: 8px; 71 | height: 8px; 72 | border-radius: 100%; 73 | @include mobile { 74 | margin-left: 10px; 75 | } 76 | } 77 | .pending { 78 | background-color: $yellow; 79 | } 80 | .exited { 81 | background-color: $green; 82 | } 83 | .failed { 84 | background-color: $red; 85 | } 86 | } 87 | 88 | .percentage { 89 | margin-left: 10px; 90 | @include mobile { 91 | margin-left: 0; 92 | margin-right: 10px; 93 | } 94 | } 95 | 96 | .button { 97 | color: $gray1; 98 | background-color: $blue; 99 | border-radius: 20px; 100 | padding: 5px 10px; 101 | cursor: pointer; 102 | } 103 | -------------------------------------------------------------------------------- /src/components/walletpicker/WalletPicker.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .WalletPicker { 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: flex-start; 8 | margin-left: auto; 9 | margin-right: auto; 10 | flex: 1; 11 | padding: 20px; 12 | font-family: 'Messina'; 13 | @include mobile { 14 | font-size: 0.9em; 15 | } 16 | 17 | .title { 18 | display: flex; 19 | flex-direction: row; 20 | justify-content: space-between; 21 | align-items: flex-start; 22 | width: 100%; 23 | @include mobile { 24 | flex-direction: column; 25 | } 26 | img { 27 | margin-bottom: 20px; 28 | height: 60px; 29 | @include mobile { 30 | height: 50px; 31 | } 32 | } 33 | .menu { 34 | display: flex; 35 | flex-direction: row; 36 | align-items: center; 37 | z-index: 1; 38 | position: relative; 39 | @include mobile { 40 | width: 100%; 41 | justify-content: space-between; 42 | } 43 | a { 44 | cursor: pointer; 45 | } 46 | .chevron { 47 | transform: rotate(90deg); 48 | transition: all 200ms ease-in-out; 49 | height: 20px; 50 | margin-bottom: 0; 51 | &.open { 52 | transform: rotate(-90deg); 53 | } 54 | } 55 | .dropdown { 56 | display: flex; 57 | flex-direction: column; 58 | position: absolute; 59 | right: 0; 60 | top: 27px; 61 | a { 62 | background-color: $gray3; 63 | transition: all 200ms ease-in-out; 64 | padding: 10px 15px; 65 | cursor: pointer; 66 | &:hover { 67 | background-color: $gray2; 68 | } 69 | } 70 | } 71 | .network { 72 | margin-left: 20px; 73 | display: flex; 74 | flex-direction: row; 75 | align-items: center; 76 | cursor: pointer; 77 | .indicator { 78 | margin-right: 5px; 79 | width: 5px; 80 | height: 13px; 81 | background-color: $green; 82 | border-radius: 4px; 83 | } 84 | } 85 | } 86 | } 87 | 88 | .directive { 89 | margin: 20px 0; 90 | font-size: 1.2em; 91 | } 92 | 93 | .loader { 94 | display: flex; 95 | flex-direction: column; 96 | .button { 97 | margin-top: 20px; 98 | align-self: center; 99 | } 100 | } 101 | 102 | .wallets { 103 | display: flex; 104 | flex-direction: row; 105 | width: 800px; 106 | justify-content: space-around; 107 | margin-top: 20px; 108 | @include mobile { 109 | flex-direction: column; 110 | width: 100%; 111 | } 112 | .wallet { 113 | width: calc(25% - 10px); 114 | border: 2px solid transparent; 115 | border-radius: 4px; 116 | transition: all 200ms ease-in-out; 117 | display: flex; 118 | flex-direction: column; 119 | color: $gray1; 120 | background-color: $gray6; 121 | align-items: center; 122 | box-sizing: border-box; 123 | padding: 20px; 124 | text-align: center; 125 | &.disabled { 126 | pointer-events: none; 127 | opacity: 0.4; 128 | } 129 | @include mobile { 130 | width: 100%; 131 | margin-bottom: 10px; 132 | } 133 | h3 { 134 | font-size: 1em; 135 | margin-top: 10px; 136 | } 137 | img { 138 | height: 50px; 139 | width: 50px; 140 | border-radius: 8px; 141 | } 142 | .walletconnect { 143 | border: 1px solid #389BFC; 144 | border-radius: 8px; 145 | display: flex; 146 | justify-content: center; 147 | align-items: center; 148 | width: 50px; 149 | height: 50px; 150 | img { 151 | height: 23px; 152 | width: auto; 153 | margin-left: 2px; 154 | } 155 | } 156 | & > div { 157 | font-size: 0.8em; 158 | @include mobile { 159 | font-size: 1em; 160 | } 161 | } 162 | &:hover { 163 | cursor: pointer; 164 | border: 2px solid $blue; 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/containers/account/Account.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useMemo, useCallback } from 'react'; 17 | import { useDispatch, useSelector } from 'react-redux'; 18 | import { isEqual } from 'lodash'; 19 | import truncate from 'truncate-middle'; 20 | import { Send, MergeType } from '@material-ui/icons'; 21 | 22 | import { selectLoading } from 'selectors/loadingSelector'; 23 | import { selectIsSynced } from 'selectors/statusSelector'; 24 | import { selectChildchainBalance, selectRootchainBalance } from 'selectors/balanceSelector'; 25 | import { selectPendingExits } from 'selectors/exitSelector'; 26 | import { selectChildchainTransactions } from 'selectors/transactionSelector'; 27 | 28 | import { openModal } from 'actions/uiAction'; 29 | 30 | import Copy from 'components/copy/Copy'; 31 | import Button from 'components/button/Button'; 32 | import { logAmount } from 'util/amountConvert'; 33 | 34 | import networkService from 'services/networkService'; 35 | 36 | import * as styles from './Account.module.scss'; 37 | 38 | function Account () { 39 | const dispatch = useDispatch(); 40 | const isSynced = useSelector(selectIsSynced); 41 | const childBalance = useSelector(selectChildchainBalance, isEqual); 42 | const rootBalance = useSelector(selectRootchainBalance, isEqual); 43 | const pendingExits = useSelector(selectPendingExits, isEqual); 44 | const transactions = useSelector(selectChildchainTransactions, isEqual); 45 | const criticalTransactionLoading = useSelector(selectLoading([ 'EXIT/CREATE' ])); 46 | 47 | const exitPending = useMemo(() => pendingExits.some(i => i.status === 'Pending'), [ pendingExits ]); 48 | const transferPending = useMemo(() => transactions.some(i => i.status === 'Pending'), [ transactions ]); 49 | const disabled = !childBalance.length || !isSynced || exitPending || transferPending; 50 | 51 | const handleModalClick = useCallback( 52 | (name) => dispatch(openModal(name)), 53 | [ dispatch ] 54 | ); 55 | 56 | return ( 57 |
58 |

Account

59 |
60 | {`Wallet Address : ${networkService.account ? truncate(networkService.account, 6, 4, '...') : ''}`} 61 | 62 |
63 | 64 |
65 |
66 |
67 |
68 | Balance on Childchain 69 | OMG Network 70 |
71 |
72 |
handleModalClick('mergeModal')} 74 | className={[ 75 | styles.transfer, 76 | (disabled || criticalTransactionLoading) ? styles.disabled : '' 77 | ].join(' ')} 78 | > 79 | 80 | Merge 81 |
82 |
handleModalClick('transferModal')} 84 | className={[ 85 | styles.transfer, 86 | (disabled || criticalTransactionLoading) ? styles.disabled : '' 87 | ].join(' ')} 88 | > 89 | 90 | Transfer 91 |
92 |
93 |
94 | {childBalance.map((i, index) => { 95 | return ( 96 |
97 |
98 | {i.name} 99 |
100 | {logAmount(i.amount, i.decimals)} 101 |
102 | ); 103 | })} 104 |
105 | 112 | 119 |
120 |
121 | 122 |
123 |
124 |
125 | Balance on Rootchain 126 | Ethereum Network 127 |
128 |
129 | 130 | {rootBalance.map((i, index) => { 131 | return ( 132 |
133 |
134 | {i.name} 135 |
136 | {logAmount(i.amount, i.decimals)} 137 |
138 | ); 139 | })} 140 |
141 |
142 |
143 | ); 144 | } 145 | 146 | export default React.memo(Account); 147 | -------------------------------------------------------------------------------- /src/containers/account/Account.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Account { 4 | margin-bottom: 20px; 5 | } 6 | 7 | .wallet { 8 | display: flex; 9 | flex-direction: row; 10 | align-items: center; 11 | margin-bottom: 20px; 12 | @include mobile { 13 | justify-content: space-between; 14 | } 15 | .address { 16 | margin-right: 20px; 17 | @include mobile { 18 | font-size: 0.8em; 19 | } 20 | } 21 | } 22 | 23 | .balances { 24 | display: flex; 25 | flex-direction: row; 26 | @include mobile { 27 | flex-direction: column; 28 | } 29 | 30 | .box { 31 | background-color: $gray3; 32 | padding: 20px; 33 | display: flex; 34 | flex-direction: column; 35 | flex: 1; 36 | @include mobile { 37 | font-size: 0.8rem; 38 | padding: 15px; 39 | } 40 | 41 | &:first-child { 42 | margin-right: 20px; 43 | @include mobile { 44 | margin-right: 0; 45 | margin-bottom: 20px; 46 | } 47 | } 48 | 49 | .buttons { 50 | margin: 20px -20px -20px -20px; 51 | @include mobile { 52 | margin: 15px -15px -15px -15px; 53 | } 54 | display: flex; 55 | flex-direction: row; 56 | button { 57 | flex: 1; 58 | } 59 | } 60 | 61 | .header { 62 | display: flex; 63 | flex-direction: row; 64 | justify-content: space-between; 65 | align-items: center; 66 | margin-bottom: 20px; 67 | .actions { 68 | display: flex; 69 | flex-direction: row; 70 | align-items: center; 71 | @include mobile { 72 | flex-direction: column; 73 | align-items: flex-end; 74 | } 75 | } 76 | .title { 77 | display: flex; 78 | flex-direction: column; 79 | font-family: 'Messina'; 80 | span:first-child { 81 | font-size: 0.8em; 82 | } 83 | } 84 | .transfer { 85 | font-family: 'Messina'; 86 | cursor: pointer; 87 | border-radius: 20px; 88 | padding: 5px 10px; 89 | border: 2px solid $gray6; 90 | filter: brightness(100%); 91 | display: flex; 92 | flex-direction: row; 93 | align-items: center; 94 | color: $gray6; 95 | svg { 96 | margin-right: 10px; 97 | width: 15px; 98 | height: 15px; 99 | } 100 | &:first-child { 101 | margin-right: 10px; 102 | @include mobile { 103 | margin-right: 0px; 104 | margin-bottom: 5px; 105 | } 106 | } 107 | } 108 | .disabled { 109 | pointer-events: none; 110 | border: 2px solid $gray3; 111 | color: $gray3; 112 | filter: brightness(75%); 113 | } 114 | } 115 | 116 | .row { 117 | display: flex; 118 | flex-direction: row; 119 | align-items: center; 120 | justify-content: space-between; 121 | color: $gray6; 122 | margin-bottom: 5px; 123 | 124 | .token { 125 | display: flex; 126 | flex-direction: row; 127 | align-items: center; 128 | .symbol { 129 | margin-right: 10px; 130 | } 131 | } 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /src/containers/app/App.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState } from 'react'; 17 | import { useDispatch, useSelector } from 'react-redux'; 18 | 19 | import { closeAlert, closeError } from 'actions/uiAction'; 20 | import { selectAlert, selectError } from 'selectors/uiSelector'; 21 | 22 | import Home from 'containers/home/Home'; 23 | import WalletPicker from 'components/walletpicker/WalletPicker'; 24 | import Alert from 'components/alert/Alert'; 25 | 26 | import * as styles from './App.module.scss'; 27 | 28 | function App () { 29 | const dispatch = useDispatch(); 30 | 31 | const errorMessage = useSelector(selectError); 32 | const alertMessage = useSelector(selectAlert); 33 | const [ enabled, setEnabled ] = useState(false); 34 | 35 | const handleErrorClose = () => dispatch(closeError()); 36 | const handleAlertClose = () => dispatch(closeAlert()); 37 | 38 | return ( 39 |
40 | 46 | {errorMessage} 47 | 48 | 49 | 55 | {alertMessage} 56 | 57 | 58 | {!enabled && } 59 | {enabled && } 60 |
61 | ); 62 | } 63 | 64 | export default App; 65 | -------------------------------------------------------------------------------- /src/containers/app/App.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .App { 4 | display: flex; 5 | flex-direction: column; 6 | min-height: 100vh; 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/home/Home.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Home { 4 | display: flex; 5 | flex-direction: row; 6 | flex: 1; 7 | max-height: 100vh; 8 | 9 | @include mobile { 10 | flex-direction: column; 11 | max-height: initial; 12 | } 13 | 14 | .sidebar { 15 | display: flex; 16 | flex-direction: column; 17 | background-color: $gray2; 18 | align-items: flex-start; 19 | 20 | .logo { 21 | width: 130px; 22 | padding: 50px 0px 10px 40px; 23 | } 24 | 25 | @include mobile { 26 | display: none; 27 | } 28 | } 29 | 30 | .main { 31 | padding: 40px; 32 | background-color: $gray1; 33 | flex: 1; 34 | overflow: auto; 35 | position: relative; 36 | @include mobile { 37 | padding: 15px; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/containers/modals/deposit/DepositModal.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState, useCallback, useEffect } from 'react'; 17 | import { useDispatch } from 'react-redux'; 18 | 19 | import { closeModal } from 'actions/uiAction'; 20 | import { getToken } from 'actions/tokenAction'; 21 | import networkService from 'services/networkService'; 22 | 23 | import Modal from 'components/modal/Modal'; 24 | 25 | import InputStep from './steps/InputStep'; 26 | import ApproveStep from './steps/ApproveStep'; 27 | 28 | const ETH = networkService.OmgUtil.transaction.ETH_CURRENCY; 29 | 30 | function DepositModal ({ open }) { 31 | const dispatch = useDispatch(); 32 | 33 | const [ step, setStep ] = useState('INPUT_STEP'); 34 | const [ currency, setCurrency ] = useState(ETH); 35 | const [ tokenInfo, setTokenInfo ] = useState({}); 36 | const [ value, setValue ] = useState(''); 37 | 38 | useEffect(() => { 39 | async function getTokenInfo () { 40 | if (currency && networkService.web3.utils.isAddress(currency)) { 41 | const tokenInfo = await getToken(currency); 42 | setTokenInfo(tokenInfo); 43 | } else { 44 | setTokenInfo({}); 45 | } 46 | } 47 | getTokenInfo(); 48 | }, [ currency ]); 49 | 50 | const handleClose = useCallback(() => { 51 | setCurrency(ETH); 52 | setValue(''); 53 | setStep('INPUT_STEP'); 54 | dispatch(closeModal('depositModal')); 55 | }, [ dispatch ]); 56 | 57 | return ( 58 | 59 | {step === 'INPUT_STEP' && ( 60 | setStep('APPROVE_STEP')} 63 | currency={currency} 64 | tokenInfo={tokenInfo} 65 | value={value} 66 | setCurrency={setCurrency} 67 | setTokenInfo={setTokenInfo} 68 | setValue={setValue} 69 | /> 70 | )} 71 | {step === 'APPROVE_STEP' && ( 72 | 78 | )} 79 | 80 | ); 81 | } 82 | 83 | export default React.memo(DepositModal); 84 | -------------------------------------------------------------------------------- /src/containers/modals/deposit/DepositModal.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .buttons { 4 | display: flex; 5 | flex-direction: row; 6 | margin-top: 30px; 7 | justify-content: flex-end; 8 | 9 | div:first-child { 10 | margin-right: 10px; 11 | } 12 | } 13 | 14 | .disclaimer { 15 | font-size: 0.8em; 16 | margin-top: 10px; 17 | } 18 | 19 | .tabs { 20 | margin-top: 20px; 21 | } 22 | 23 | .loader { 24 | height: 250px; 25 | display: flex; 26 | justify-items: center; 27 | align-items: center; 28 | } -------------------------------------------------------------------------------- /src/containers/modals/deposit/steps/InputStep.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { useDispatch, useSelector } from 'react-redux'; 3 | 4 | import GasPicker from 'components/gaspicker/GasPicker'; 5 | import Button from 'components/button/Button'; 6 | import Input from 'components/input/Input'; 7 | import Tabs from 'components/tabs/Tabs'; 8 | 9 | import { depositEth } from 'actions/networkAction'; 10 | import { openAlert, setActiveHistoryTab } from 'actions/uiAction'; 11 | import { powAmount } from 'util/amountConvert'; 12 | import networkService from 'services/networkService'; 13 | import { selectLoading } from 'selectors/loadingSelector'; 14 | 15 | import * as styles from '../DepositModal.module.scss'; 16 | 17 | const ETH = networkService.OmgUtil.transaction.ETH_CURRENCY; 18 | 19 | function InputStep ({ 20 | onClose, 21 | onNext, 22 | currency, 23 | tokenInfo, 24 | value, 25 | setCurrency, 26 | setTokenInfo, 27 | setValue 28 | }) { 29 | const dispatch = useDispatch(); 30 | const [ activeTab, setActiveTab ] = useState('ETH'); 31 | const depositLoading = useSelector(selectLoading([ 'DEPOSIT/CREATE' ])); 32 | const [ selectedSpeed, setSelectedSpeed ] = useState('normal'); 33 | const [ gasPrice, setGasPrice ] = useState(); 34 | 35 | function handleClose () { 36 | setActiveTab('ETH'); 37 | onClose(); 38 | } 39 | 40 | async function depositETH () { 41 | if (value > 0 && tokenInfo) { 42 | const amount = powAmount(value, tokenInfo.decimals); 43 | const res = await dispatch(depositEth(amount, gasPrice)); 44 | if (res) { 45 | dispatch(setActiveHistoryTab('Deposits')); 46 | dispatch(openAlert('ETH deposit submitted.')); 47 | handleClose(); 48 | } 49 | } 50 | } 51 | 52 | const disabledSubmit = value <= 0 || !currency || !networkService.web3.utils.isAddress(currency); 53 | 54 | return ( 55 | <> 56 |

Deposit

57 | 58 | { 61 | i === 'ETH' ? setCurrency(ETH) : setCurrency(''); 62 | setActiveTab(i); 63 | }} 64 | activeTab={activeTab} 65 | tabs={[ 'ETH', 'ERC20' ]} 66 | /> 67 | 68 | {activeTab === 'ERC20' && ( 69 | setCurrency(i.target.value)} 75 | /> 76 | )} 77 | 78 | setValue(i.target.value)} 85 | /> 86 | 87 | {activeTab === 'ETH' && ( 88 | 93 | )} 94 | 95 |
96 | 103 | {activeTab === 'ETH' && ( 104 | 114 | )} 115 | {activeTab === 'ERC20' && ( 116 | 124 | )} 125 |
126 | 127 | ); 128 | } 129 | 130 | export default React.memo(InputStep); 131 | -------------------------------------------------------------------------------- /src/containers/modals/exit/ExitModal.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState } from 'react'; 17 | import { useDispatch } from 'react-redux'; 18 | 19 | import { closeModal } from 'actions/uiAction'; 20 | 21 | import Modal from 'components/modal/Modal'; 22 | 23 | import SelectStep from './steps/SelectStep'; 24 | import AddTokenStep from './steps/AddTokenStep'; 25 | import DoExitStep from './steps/DoExitStep'; 26 | 27 | function ExitModal ({ open }) { 28 | const dispatch = useDispatch(); 29 | 30 | const [ gasPrice, setGasPrice ] = useState(); 31 | const [ selectedSpeed, setSelectedSpeed ] = useState('normal'); 32 | const [ selectedUTXO, setSelectedUTXO ] = useState(); 33 | const [ step, setStep ] = useState(1); 34 | 35 | function handleClose () { 36 | setSelectedUTXO(); 37 | setStep(1); 38 | dispatch(closeModal('exitModal')); 39 | } 40 | 41 | return ( 42 | 43 | {step === 1 && ( 44 | 54 | )} 55 | {step === 2 && ( 56 | 62 | )} 63 | {step === 3 && ( 64 | 69 | )} 70 | 71 | ); 72 | } 73 | 74 | export default React.memo(ExitModal); 75 | -------------------------------------------------------------------------------- /src/containers/modals/exit/ExitModal.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .buttons { 4 | display: flex; 5 | flex-direction: row; 6 | margin-top: 30px; 7 | justify-content: flex-end; 8 | 9 | div:first-child { 10 | margin-right: 10px; 11 | } 12 | } 13 | 14 | .disclaimer { 15 | margin-top: 20px; 16 | } 17 | 18 | .list { 19 | height: 160px; 20 | overflow-y: auto; 21 | margin-bottom: 10px; 22 | .utxo { 23 | font-size: 0.8em; 24 | display: flex; 25 | flex-direction: row; 26 | align-items: center; 27 | justify-content: space-between; 28 | padding: 10px; 29 | height: 25px; 30 | background-color: $gray3; 31 | border-bottom: 2px solid $gray4; 32 | transition: all 200ms ease-in-out; 33 | cursor: pointer; 34 | .title { 35 | flex: 1 36 | } 37 | .value { 38 | flex: 1; 39 | display: flex; 40 | flex-direction: row; 41 | align-items: center; 42 | justify-content: flex-end; 43 | text-align: right; 44 | .check { 45 | display: flex; 46 | justify-content: center; 47 | align-items: center; 48 | width: 50px; 49 | svg { 50 | width: 15px; 51 | height: 15px; 52 | } 53 | } 54 | } 55 | } 56 | .selected { 57 | background-color: $gray2; 58 | color: $gray6; 59 | } 60 | } -------------------------------------------------------------------------------- /src/containers/modals/exit/steps/AddTokenStep.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { useDispatch, useSelector } from 'react-redux'; 18 | 19 | import { selectLoading } from 'selectors/loadingSelector'; 20 | import { addExitQueue } from 'actions/networkAction'; 21 | 22 | import Button from 'components/button/Button'; 23 | 24 | import * as styles from '../ExitModal.module.scss'; 25 | 26 | function AddTokenStep ({ 27 | selectedUTXO, 28 | setSelectedUTXO, 29 | setStep, 30 | gasPrice 31 | }) { 32 | const dispatch = useDispatch(); 33 | 34 | const addExitQueueLoading = useSelector(selectLoading([ 'QUEUE/CREATE' ])); 35 | 36 | async function doAddExitQueue () { 37 | const res = await dispatch(addExitQueue(selectedUTXO.currency, gasPrice)); 38 | if (res) { 39 | return setStep(3); 40 | } 41 | } 42 | 43 | function handleBackClick () { 44 | setSelectedUTXO(); 45 | setStep(1); 46 | } 47 | 48 | return ( 49 | <> 50 |

Add Exit Queue

51 | 52 |
{`The exit queue for ${selectedUTXO.tokenInfo.name} does not exist yet. Adding the exit queue is required before being able to start your exit.`}
53 | 54 |
55 | 62 | 71 |
72 | 73 | ); 74 | } 75 | 76 | export default React.memo(AddTokenStep); 77 | -------------------------------------------------------------------------------- /src/containers/modals/exit/steps/DoExitStep.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { useDispatch, useSelector } from 'react-redux'; 18 | 19 | import { exitUtxo } from 'actions/networkAction'; 20 | import { openAlert } from 'actions/uiAction'; 21 | import { selectLoading } from 'selectors/loadingSelector'; 22 | 23 | import Button from 'components/button/Button'; 24 | 25 | import * as styles from '../ExitModal.module.scss'; 26 | 27 | function DoExitStep ({ 28 | selectedUTXO, 29 | handleClose, 30 | gasPrice 31 | }) { 32 | const dispatch = useDispatch(); 33 | 34 | const submitLoading = useSelector(selectLoading([ 'EXIT/CREATE' ])); 35 | 36 | async function doExit () { 37 | const res = await dispatch(exitUtxo(selectedUTXO, gasPrice)); 38 | if (res) { 39 | dispatch(openAlert('Exit submitted. You will be blocked from making further transactions until the exit is confirmed.')); 40 | handleClose(); 41 | } 42 | } 43 | 44 | return ( 45 | <> 46 |

Start Standard Exit

47 | 48 |
{'The exit queue has been added. You can now start your exit.'}
49 | 50 |
51 | 58 | 68 |
69 | 70 | ); 71 | } 72 | 73 | export default React.memo(DoExitStep); 74 | -------------------------------------------------------------------------------- /src/containers/modals/exit/steps/SelectStep.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState, useMemo, useEffect } from 'react'; 17 | import { orderBy } from 'lodash'; 18 | import { useDispatch, useSelector } from 'react-redux'; 19 | import { Check } from '@material-ui/icons'; 20 | 21 | import networkService from 'services/networkService'; 22 | import { openAlert } from 'actions/uiAction'; 23 | import { checkForExitQueue, exitUtxo } from 'actions/networkAction'; 24 | import { selectLoading } from 'selectors/loadingSelector'; 25 | 26 | import GasPicker from 'components/gaspicker/GasPicker'; 27 | import Input from 'components/input/Input'; 28 | import Button from 'components/button/Button'; 29 | 30 | import { logAmount } from 'util/amountConvert'; 31 | 32 | import * as styles from '../ExitModal.module.scss'; 33 | 34 | function SelectStep ({ 35 | setSelectedUTXO, 36 | selectedUTXO, 37 | handleClose, 38 | setStep, 39 | gasPrice, 40 | setGasPrice, 41 | selectedSpeed, 42 | setSelectedSpeed 43 | }) { 44 | const dispatch = useDispatch(); 45 | 46 | const [ utxos, setUtxos ] = useState([]); 47 | const [ searchUTXO, setSearchUTXO ] = useState(''); 48 | 49 | const submitLoading = useSelector(selectLoading([ 50 | `QUEUE/GET_${selectedUTXO ? selectedUTXO.currency : ''}`, 51 | 'EXIT/CREATE' 52 | ])); 53 | 54 | useEffect(() => { 55 | async function fetchUTXOS () { 56 | const _utxos = await networkService.getUtxos(); 57 | const utxos = orderBy(_utxos, i => i.currency, 'desc'); 58 | setUtxos(utxos); 59 | } 60 | fetchUTXOS(); 61 | }, []); 62 | 63 | async function doCheckExitQueue () { 64 | const res = await dispatch(checkForExitQueue(selectedUTXO.currency)); 65 | if (!res) { 66 | return setStep(2); 67 | } 68 | return doExit(); 69 | } 70 | 71 | async function doExit () { 72 | const res = await dispatch(exitUtxo(selectedUTXO, gasPrice)); 73 | if (res) { 74 | dispatch(openAlert('Exit submitted. You will be blocked from making further transactions until the exit is confirmed.')); 75 | handleClose(); 76 | } 77 | } 78 | 79 | const _utxos = useMemo(() => { 80 | return utxos.filter(i => { 81 | return i.currency.toLowerCase().includes(searchUTXO.toLowerCase()) || 82 | i.tokenInfo.name.toLowerCase().includes(searchUTXO.toLowerCase()); 83 | }).filter(i => !!i); 84 | }, [ utxos, searchUTXO ]); 85 | 86 | function closeModal () { 87 | setSearchUTXO(''); 88 | setSelectedSpeed('normal'); 89 | handleClose(); 90 | } 91 | 92 | return ( 93 | <> 94 |

Start Standard Exit

95 | 96 | setSearchUTXO(i.target.value)} 102 | /> 103 | 104 |
105 | {!utxos.length && ( 106 |
You do not have any UTXOs on the OMG Network.
107 | )} 108 | {_utxos.map((i, index) => { 109 | return ( 110 |
setSelectedUTXO(i)} 113 | className={[ 114 | styles.utxo, 115 | selectedUTXO === i ? styles.selected : '' 116 | ].join(' ')} 117 | > 118 |
119 | {i.tokenInfo.name} 120 |
121 | 122 |
123 |
124 | {logAmount(i.amount.toString(), i.tokenInfo.decimals)} 125 |
126 | 127 |
128 | {selectedUTXO === i && } 129 |
130 |
131 |
132 | ); 133 | })} 134 |
135 | 136 | 141 | 142 |
143 | 150 | 160 |
161 | 162 | ); 163 | } 164 | 165 | export default React.memo(SelectStep); 166 | -------------------------------------------------------------------------------- /src/containers/modals/ledger/LedgerConnect.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .buttons { 4 | display: flex; 5 | flex-direction: row; 6 | margin-top: 30px; 7 | justify-content: flex-end; 8 | 9 | div:first-child { 10 | margin-right: 10px; 11 | } 12 | } 13 | 14 | .header { 15 | display: flex; 16 | flex-direction: column; 17 | align-items: center; 18 | margin-top: 20px; 19 | } 20 | 21 | .logo { 22 | padding: 7px; 23 | height: 60px; 24 | border-radius: 20px; 25 | background-color: white; 26 | } 27 | 28 | .logoContainer { 29 | display: flex; 30 | margin-top: 30px; 31 | align-items: center; 32 | justify-content: center; 33 | position: relative; 34 | @include mobile { 35 | display: none; 36 | } 37 | .spinner { 38 | position: absolute; 39 | bottom: -10px; 40 | right: -10px; 41 | background-color: $blue; 42 | border-radius: 100%; 43 | width: 30px; 44 | height: 30px; 45 | display: flex; 46 | justify-content: center; 47 | align-items: center; 48 | } 49 | } 50 | 51 | .title { 52 | margin-top: 30px; 53 | font-size: 1.5em; 54 | font-family: 'Messina'; 55 | font-weight: 400; 56 | color: white; 57 | text-align: center; 58 | } 59 | 60 | .description { 61 | font-family: 'Messina'; 62 | margin-top: 20px; 63 | color: white; 64 | font-size: 1em; 65 | } 66 | 67 | .steps { 68 | margin: 20px 0; 69 | .step { 70 | min-height: 40px; 71 | margin-bottom: 10px; 72 | border-radius: 4px; 73 | background-color: $gray2; 74 | display: flex; 75 | flex-direction: row; 76 | font-family: 'Messina'; 77 | @include mobile { 78 | font-size: 0.8em; 79 | } 80 | .text { 81 | padding: 10px 15px; 82 | display: flex; 83 | align-items: center; 84 | } 85 | .iconWrapper { 86 | border-radius: 4px 0px 0px 4px; 87 | min-width: 40px; 88 | background-color: white; 89 | display: flex; 90 | justify-content: center; 91 | align-items: center; 92 | img { 93 | height: 15px; 94 | } 95 | } 96 | } 97 | } 98 | 99 | .tabs { 100 | margin-top: 20px; 101 | } 102 | 103 | .selectAddressContainer { 104 | text-align: center; 105 | } 106 | -------------------------------------------------------------------------------- /src/containers/modals/ledger/LedgerPrompt.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { CircularProgress } from '@material-ui/core'; 18 | 19 | import { hashTypedDataMessage, hashTypedDataDomain } from '@omisego/omg-js-util'; 20 | 21 | import Button from 'components/button/Button'; 22 | 23 | import ledger from 'images/ledger_connect.png'; 24 | import eth from 'images/eth.svg'; 25 | import connect from 'images/connect.svg'; 26 | import lock from 'images/lock.svg'; 27 | 28 | import * as styles from './LedgerPrompt.module.scss'; 29 | 30 | function LedgerPrompt ({ 31 | loading, 32 | submit, 33 | handleClose, 34 | typedData 35 | }) { 36 | return ( 37 | <> 38 | {!loading && ( 39 | <> 40 |
41 |
42 | ledger_logo 43 |
44 |
Ledger Sign
45 |
46 |
Please make sure your Ledger meets the following conditions:
47 |
48 |
49 |
50 | connect 51 |
52 |
Connected
53 |
54 |
55 |
56 | lock 57 |
58 |
Unlocked
59 |
60 |
61 |
62 | eth 63 |
64 |
The Ethereum application is open and running a version greater than 1.4.0
65 |
66 |
67 |
68 | 75 | 83 |
84 | 85 | )} 86 | 87 | {loading && ( 88 | <> 89 |
90 |
91 | ledger_logo 92 |
93 | 94 |
95 |
96 |
Processing...
97 |
98 |
99 | Please continue signing the transaction on your Ledger device.
100 | Check that the domain and message hash displayed on the device match the following: 101 |
102 | {typedData && ( 103 |
104 |
105 | Domain Hash: {hashTypedDataDomain(typedData).toUpperCase()} 106 |
107 |
108 | Message Hash: {hashTypedDataMessage(typedData).toUpperCase()} 109 |
110 |
111 | )} 112 | 113 | )} 114 | 115 | ); 116 | } 117 | 118 | export default React.memo(LedgerPrompt); 119 | -------------------------------------------------------------------------------- /src/containers/modals/ledger/LedgerPrompt.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .buttons { 4 | display: flex; 5 | flex-direction: row; 6 | margin-top: 30px; 7 | justify-content: flex-end; 8 | 9 | .button { 10 | margin-right: 10px; 11 | min-width: 0; 12 | &:last-child { 13 | margin-right: 0px; 14 | } 15 | } 16 | } 17 | 18 | .header { 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | margin-top: 20px; 23 | } 24 | 25 | .logo { 26 | padding: 7px; 27 | height: 60px; 28 | border-radius: 20px; 29 | background-color: white; 30 | } 31 | 32 | .logoContainer { 33 | position: relative; 34 | display: flex; 35 | align-items: center; 36 | justify-content: center; 37 | @include mobile { 38 | display: none; 39 | } 40 | .spinner { 41 | position: absolute; 42 | bottom: -10px; 43 | right: -10px; 44 | background-color: $blue; 45 | border-radius: 100%; 46 | width: 30px; 47 | height: 30px; 48 | display: flex; 49 | justify-content: center; 50 | align-items: center; 51 | } 52 | } 53 | 54 | .title { 55 | margin-top: 20px; 56 | font-size: 1.5em; 57 | font-family: 'Messina'; 58 | font-weight: 400; 59 | color: white; 60 | text-align: center; 61 | } 62 | 63 | .description { 64 | font-family: 'Messina'; 65 | margin-top: 20px; 66 | color: white; 67 | font-size: 1em; 68 | } 69 | 70 | .steps { 71 | margin: 20px 0; 72 | .step { 73 | min-height: 50px; 74 | margin-bottom: 10px; 75 | border-radius: 4px; 76 | background-color: $gray2; 77 | display: flex; 78 | flex-direction: row; 79 | align-items: center; 80 | font-family: 'Messina'; 81 | @include mobile { 82 | font-size: 0.8em; 83 | } 84 | .text { 85 | padding: 10px 15px; 86 | display: flex; 87 | align-items: center; 88 | } 89 | .iconWrapper { 90 | border-radius: 4px 0px 0px 4px; 91 | min-width: 40px; 92 | min-height: 50px; 93 | background-color: white; 94 | display: flex; 95 | justify-content: center; 96 | align-items: center; 97 | img { 98 | height: 15px; 99 | max-width: 15px; 100 | } 101 | } 102 | } 103 | .code { 104 | word-break: break-all; 105 | font-family: 'MessinaMono'; 106 | padding: 10px 15px; 107 | } 108 | } -------------------------------------------------------------------------------- /src/containers/modals/merge/MergeModal.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .buttons { 4 | display: flex; 5 | flex-direction: row; 6 | margin-top: 30px; 7 | justify-content: flex-end; 8 | 9 | .button { 10 | margin-right: 10px; 11 | min-width: 0; 12 | &:last-child { 13 | margin-right: 0px; 14 | } 15 | } 16 | } 17 | 18 | .disclaimer { 19 | font-family: 'Messina'; 20 | margin: 20px 0; 21 | } 22 | 23 | .list { 24 | height: 250px; 25 | overflow-y: auto; 26 | .utxo { 27 | font-size: 0.9em; 28 | display: flex; 29 | flex-direction: row; 30 | align-items: center; 31 | justify-content: space-between; 32 | background-color: $gray3; 33 | border-bottom: 2px solid $gray4; 34 | padding: 10px; 35 | height: 25px; 36 | transition: all 200ms ease-in-out; 37 | cursor: pointer; 38 | .title { 39 | flex: 1 40 | } 41 | .value { 42 | flex: 1; 43 | display: flex; 44 | flex-direction: row; 45 | align-items: center; 46 | justify-content: flex-end; 47 | text-align: right; 48 | .check { 49 | display: flex; 50 | justify-content: center; 51 | align-items: center; 52 | width: 50px; 53 | svg { 54 | width: 15px; 55 | height: 15px; 56 | } 57 | } 58 | } 59 | } 60 | .selected { 61 | background-color: $gray2; 62 | color: $gray6; 63 | } 64 | } -------------------------------------------------------------------------------- /src/containers/modals/processexit/ProcessExitsModal.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState } from 'react'; 17 | import { useDispatch, useSelector } from 'react-redux'; 18 | import numbro from 'numbro'; 19 | 20 | import { selectByzantine } from 'selectors/statusSelector'; 21 | import { processExits, fetchExits } from 'actions/networkAction'; 22 | 23 | import GasPicker from 'components/gaspicker/GasPicker'; 24 | import Button from 'components/button/Button'; 25 | import Modal from 'components/modal/Modal'; 26 | 27 | import * as styles from './ProcessExitsModal.module.scss'; 28 | 29 | function ProcessExitsModal ({ exitData, open, toggle }) { 30 | const dispatch = useDispatch(); 31 | 32 | const byzantineChain = useSelector(selectByzantine); 33 | const [ loading, setLoading ] = useState(false); 34 | const [ gasPrice, setGasPrice ] = useState(); 35 | const [ selectedSpeed, setSelectedSpeed ] = useState('normal'); 36 | 37 | async function submit () { 38 | setLoading(true); 39 | const res = await dispatch(processExits(exitData.queuePosition, exitData.currency, gasPrice)); 40 | if (res) { 41 | await dispatch(fetchExits()); 42 | setLoading(false); 43 | return handleClose(); 44 | } 45 | return setLoading(false); 46 | } 47 | 48 | function handleClose () { 49 | setSelectedSpeed('normal'); 50 | toggle(); 51 | } 52 | 53 | return ( 54 | 55 |

Process Exit

56 | 57 |
58 | This exit is currently 59 | {exitData ? numbro(exitData.queuePosition).format({ output: 'ordinal' }) : ''} 60 | {`in the queue for this token. You will need to process ${exitData.queuePosition} ${exitData.queuePosition === 1 ? 'exit' : 'exits'} to release your funds.`} 61 |
62 | 63 | 68 | 69 |
70 | 77 | 90 |
91 |
92 | ); 93 | } 94 | 95 | export default ProcessExitsModal; 96 | -------------------------------------------------------------------------------- /src/containers/modals/processexit/ProcessExitsModal.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .buttons { 4 | display: flex; 5 | flex-direction: row; 6 | margin-top: 30px; 7 | justify-content: flex-end; 8 | 9 | div:first-child { 10 | margin-right: 10px; 11 | } 12 | } 13 | 14 | .disclaimer { 15 | padding: 10px; 16 | background-color: $blue; 17 | color: $gray6; 18 | margin-top: -12px; 19 | font-size: 0.9em; 20 | margin-bottom: 10px; 21 | } 22 | 23 | .note { 24 | margin: 10px 0; 25 | } 26 | 27 | .position { 28 | color: $gray6; 29 | font-weight: bold; 30 | margin: 0 7px; 31 | } 32 | -------------------------------------------------------------------------------- /src/containers/modals/transfer/TransferModal.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .disclaimer { 4 | font-family: 'Messina'; 5 | margin-top: 20px; 6 | } 7 | 8 | .buttons { 9 | display: flex; 10 | flex-direction: row; 11 | margin-top: 30px; 12 | justify-content: flex-end; 13 | 14 | .button { 15 | margin-right: 10px; 16 | min-width: 0; 17 | &:last-child { 18 | margin-right: 0px; 19 | } 20 | } 21 | } 22 | 23 | .address { 24 | font-size: 0.9em; 25 | margin-bottom: 20px; 26 | margin-top: 20px; 27 | word-break: break-all; 28 | } 29 | 30 | .utxoPickLink { 31 | cursor: pointer; 32 | color: $blue; 33 | font-size: 12px; 34 | text-align: right; 35 | } 36 | 37 | .description { 38 | font-family: 'Messina'; 39 | margin-bottom: 20px; 40 | } 41 | 42 | .list { 43 | height: 250px; 44 | overflow-y: auto; 45 | .utxo { 46 | font-size: 0.9em; 47 | display: flex; 48 | flex-direction: row; 49 | align-items: center; 50 | justify-content: space-between; 51 | background-color: $gray3; 52 | border-bottom: 2px solid $gray4; 53 | padding: 10px; 54 | height: 25px; 55 | transition: all 200ms ease-in-out; 56 | cursor: pointer; 57 | .title { 58 | flex: 1 59 | } 60 | .value { 61 | flex: 1; 62 | display: flex; 63 | flex-direction: row; 64 | align-items: center; 65 | justify-content: flex-end; 66 | text-align: right; 67 | .check { 68 | display: flex; 69 | justify-content: center; 70 | align-items: center; 71 | width: 50px; 72 | svg { 73 | width: 15px; 74 | height: 15px; 75 | } 76 | } 77 | } 78 | } 79 | .selected { 80 | background-color: $gray2; 81 | color: $gray6; 82 | } 83 | } 84 | 85 | .doubleList { 86 | height: 150px; 87 | } 88 | -------------------------------------------------------------------------------- /src/containers/modals/wrongnetwork/WrongNetworkModal.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import { useDispatch } from 'react-redux'; 18 | 19 | import Modal from 'components/modal/Modal'; 20 | import { closeModal } from 'actions/uiAction'; 21 | import { getNetworkName, getOtherNetworks } from 'util/networkName'; 22 | import close from 'images/close.png'; 23 | import arrow from 'images/arrow.png'; 24 | 25 | import * as styles from './WrongNetworkModal.module.scss'; 26 | 27 | function WrongNetworkModal ({ open, onClose }) { 28 | const dispatch = useDispatch(); 29 | 30 | function handleClose () { 31 | onClose(); 32 | dispatch(closeModal('wrongNetworkModal')); 33 | } 34 | 35 | return ( 36 | 41 |
42 | close 48 |

Wrong Network

49 | 50 |
51 |
52 | Please switch your wallet to the {getNetworkName()} in order to continue. 53 |
54 | 55 |
56 |
62 | {getNetworkName()} 63 |
64 | 65 | arrow 70 | 71 |
72 | {getOtherNetworks().map((network, index) => { 73 | return ( 74 |
75 |
76 | {network} 77 |
78 | ); 79 | })} 80 |
81 |
82 |
83 | 84 | ); 85 | } 86 | 87 | export default React.memo(WrongNetworkModal); 88 | -------------------------------------------------------------------------------- /src/containers/modals/wrongnetwork/WrongNetworkModal.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .WrongNetworkModal { 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: 'Messina'; 9 | text-align: center; 10 | position: relative; 11 | padding: 40px; 12 | @include mobile { 13 | padding: 20px; 14 | } 15 | .close { 16 | position: absolute; 17 | right: 0; 18 | top: 0; 19 | height: 15px; 20 | cursor: pointer; 21 | } 22 | h2 { 23 | color: $gray1; 24 | } 25 | 26 | .content { 27 | max-width: 220px; 28 | .description { 29 | margin: 20px 0; 30 | font-size: 0.9em; 31 | } 32 | .currentNetwork { 33 | background-color: $gray4; 34 | color: $gray6; 35 | border-radius: 6px; 36 | padding: 15px 20px; 37 | display: flex; 38 | flex-direction: row; 39 | align-items: center; 40 | margin-bottom: 10px; 41 | } 42 | .network { 43 | background-color: $gray6; 44 | padding: 10px; 45 | display: flex; 46 | flex-direction: row; 47 | align-items: center; 48 | color: $gray4; 49 | margin-bottom: 1px; 50 | &:first-child { 51 | border-top-left-radius: 6px; 52 | border-top-right-radius: 6px; 53 | } 54 | &:last-child { 55 | border-bottom-left-radius: 6px; 56 | border-bottom-right-radius: 6px; 57 | } 58 | } 59 | .indicator { 60 | background-color: $gray5; 61 | width: 7px; 62 | height: 7px; 63 | border-radius: 100%; 64 | margin-right: 10px; 65 | &.active { 66 | background-color: $green; 67 | } 68 | } 69 | .otherNetworks { 70 | background-color: $gray7; 71 | border-radius: 6px; 72 | padding: 10px; 73 | } 74 | .arrow { 75 | width: 20px; 76 | opacity: 0.2; 77 | transform: rotate((-90deg)); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/containers/status/Status.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .Status { 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: space-between; 7 | padding: 40px; 8 | max-width: 300px; 9 | flex: 1; 10 | 11 | h1 { 12 | margin-bottom: 40px; 13 | } 14 | 15 | .statusCircle { 16 | border-radius: 100%; 17 | width: 8px; 18 | height: 8px; 19 | margin-left: 10px; 20 | } 21 | .healthy { 22 | background-color: $green; 23 | } 24 | .unhealthy { 25 | background-color: $red; 26 | } 27 | .healthyText { 28 | color: $green; 29 | } 30 | .unhealthyText { 31 | color: $red; 32 | } 33 | 34 | .indicator { 35 | display: flex; 36 | flex-direction: row; 37 | align-items: center; 38 | } 39 | 40 | .icon { 41 | cursor: pointer; 42 | background-color: $gray3; 43 | border-radius: 100%; 44 | width: 25px; 45 | height: 25px; 46 | display: flex; 47 | justify-content: center; 48 | align-items: center; 49 | 50 | svg { 51 | width: 12px; 52 | height: 12px; 53 | } 54 | } 55 | 56 | .github { 57 | cursor: pointer; 58 | color: $gray3; 59 | svg { 60 | width: 40px; 61 | height: 40px; 62 | } 63 | } 64 | } 65 | 66 | .logo { 67 | margin-bottom: 40px; 68 | height: 50px; 69 | } 70 | -------------------------------------------------------------------------------- /src/containers/transactions/Deposits.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState, useEffect } from 'react'; 17 | import { orderBy, isEqual } from 'lodash'; 18 | import { useSelector } from 'react-redux'; 19 | import truncate from 'truncate-middle'; 20 | 21 | import { selectEthDeposits, selectErc20Deposits } from 'selectors/transactionSelector'; 22 | import { selectLoading } from 'selectors/loadingSelector'; 23 | 24 | import Transaction from 'components/transaction/Transaction'; 25 | import Pager from 'components/pager/Pager'; 26 | 27 | import config from 'util/config'; 28 | import { logAmount } from 'util/amountConvert'; 29 | 30 | import * as styles from './Transactions.module.scss'; 31 | 32 | const PER_PAGE = 10; 33 | 34 | function Deposits ({ searchHistory }) { 35 | const [ page, setPage ] = useState(1); 36 | 37 | const ethDeposits = useSelector(selectEthDeposits, isEqual); 38 | const erc20Deposits = useSelector(selectErc20Deposits, isEqual); 39 | const loading = useSelector(selectLoading([ 'DEPOSIT/GETALL' ])); 40 | 41 | useEffect(() => { 42 | setPage(1); 43 | }, [ searchHistory ]); 44 | 45 | const deposits = orderBy( 46 | [ ...ethDeposits, ...erc20Deposits ], 47 | i => i.blockNumber, 'desc' 48 | ); 49 | const _deposits = deposits.filter(i => { 50 | return i.transactionHash.includes(searchHistory) || i.returnValues.token.includes(searchHistory); 51 | }); 52 | 53 | const startingIndex = page === 1 ? 0 : ((page - 1) * PER_PAGE); 54 | const endingIndex = page * PER_PAGE; 55 | const paginatedDeposits = _deposits.slice(startingIndex, endingIndex); 56 | 57 | return ( 58 |
59 |
60 | setPage(page + 1)} 64 | onClickBack={() => setPage(page - 1)} 65 | /> 66 | {!paginatedDeposits.length && !loading && ( 67 |
No deposit history.
68 | )} 69 | {!paginatedDeposits.length && loading && ( 70 |
Loading...
71 | )} 72 | {paginatedDeposits.map((i, index) => { 73 | return ( 74 | 85 | ); 86 | })} 87 |
88 |
89 | ); 90 | } 91 | 92 | export default React.memo(Deposits); 93 | -------------------------------------------------------------------------------- /src/containers/transactions/Exits.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState } from 'react'; 17 | import { orderBy, isEqual } from 'lodash'; 18 | import moment from 'moment'; 19 | import { useSelector } from 'react-redux'; 20 | import truncate from 'truncate-middle'; 21 | 22 | import config from 'util/config'; 23 | import { selectPendingExits, selectExitedExits } from 'selectors/exitSelector'; 24 | import { selectLoading } from 'selectors/loadingSelector'; 25 | 26 | import ProcessExitsModal from 'containers/modals/processexit/ProcessExitsModal'; 27 | import Transaction from 'components/transaction/Transaction'; 28 | import Pager from 'components/pager/Pager'; 29 | 30 | import * as styles from './Transactions.module.scss'; 31 | 32 | const PER_PAGE = 10; 33 | 34 | function Exits ({ searchHistory }) { 35 | const [ page, setPage ] = useState(1); 36 | const [ processExitModal, setProcessExitModal ] = useState(false); 37 | 38 | const pendingExits = orderBy(useSelector(selectPendingExits, isEqual), i => i.blockNumber, 'desc'); 39 | const exitedExits = orderBy(useSelector(selectExitedExits, isEqual), i => i.blockNumber, 'desc'); 40 | const loading = useSelector(selectLoading([ 'EXIT/GETALL' ])); 41 | 42 | const _pendingExits = pendingExits.filter(i => { 43 | return i.transactionHash.includes(searchHistory); 44 | }); 45 | 46 | const _exitedExits = exitedExits.filter(i => { 47 | return i.transactionHash.includes(searchHistory); 48 | }); 49 | 50 | const renderPending = _pendingExits.map((i, index) => { 51 | const exitableMoment = moment.unix(i.exitableAt); 52 | const isExitable = moment().isAfter(exitableMoment); 53 | 54 | function getStatus () { 55 | if (i.status === 'Confirmed' && i.pendingPercentage >= 100) { 56 | return 'In Challenge Period'; 57 | } 58 | return i.status; 59 | } 60 | 61 | return ( 62 | setProcessExitModal(i), 68 | text: 'Process Exit' 69 | } 70 | : undefined 71 | } 72 | link={`${config.etherscanUrl}/tx/${i.transactionHash}`} 73 | status={getStatus()} 74 | subStatus={`Block ${i.blockNumber}`} 75 | statusPercentage={i.pendingPercentage <= 100 ? i.pendingPercentage : ''} 76 | title={truncate(i.transactionHash, 6, 4, '...')} 77 | midTitle={i.exitableAt ? `Exitable ${exitableMoment.format('lll')}` : ''} 78 | subTitle={i.currency ? truncate(i.currency, 6, 4, '...'): ''} 79 | /> 80 | ); 81 | }); 82 | 83 | const renderExited = _exitedExits.map((i, index) => { 84 | return ( 85 | 92 | ); 93 | }); 94 | 95 | const allExits = [ ...renderPending, ...renderExited ]; 96 | 97 | const startingIndex = page === 1 ? 0 : ((page - 1) * PER_PAGE); 98 | const endingIndex = page * PER_PAGE; 99 | const paginatedExits = allExits.slice(startingIndex, endingIndex); 100 | 101 | return ( 102 | <> 103 | setProcessExitModal(false)} 107 | /> 108 |
109 |
Exits
110 |
111 |
112 | setPage(page + 1)} 116 | onClickBack={() => setPage(page - 1)} 117 | /> 118 | {!allExits.length && !loading && ( 119 |
No exit history.
120 | )} 121 | {!allExits.length && loading && ( 122 |
Loading...
123 | )} 124 | {React.Children.toArray(paginatedExits)} 125 |
126 |
127 |
128 | 129 | ); 130 | } 131 | 132 | export default React.memo(Exits); 133 | -------------------------------------------------------------------------------- /src/containers/transactions/Transactions.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React, { useState } from 'react'; 17 | import { useDispatch } from 'react-redux'; 18 | import { orderBy, isEqual } from 'lodash'; 19 | import { useSelector } from 'react-redux'; 20 | import BN from 'bn.js'; 21 | import moment from 'moment'; 22 | import truncate from 'truncate-middle'; 23 | 24 | import { setActiveHistoryTab } from 'actions/uiAction'; 25 | 26 | import { selectActiveHistoryTab } from 'selectors/uiSelector'; 27 | import { selectChildchainTransactions } from 'selectors/transactionSelector'; 28 | import { selectLoading } from 'selectors/loadingSelector'; 29 | import networkService from 'services/networkService'; 30 | import config from 'util/config'; 31 | 32 | import Tabs from 'components/tabs/Tabs'; 33 | import Input from 'components/input/Input'; 34 | import Transaction from 'components/transaction/Transaction'; 35 | import Pager from 'components/pager/Pager'; 36 | 37 | import Exits from './Exits'; 38 | import Deposits from './Deposits'; 39 | 40 | import * as styles from './Transactions.module.scss'; 41 | 42 | const PER_PAGE = 10; 43 | 44 | function Transactions () { 45 | const dispatch = useDispatch(); 46 | const [ page, setPage ] = useState(1); 47 | const [ searchHistory, setSearchHistory ] = useState(''); 48 | 49 | const loading = useSelector(selectLoading([ 'TRANSACTION/GETALL' ])); 50 | const activeTab = useSelector(selectActiveHistoryTab, isEqual); 51 | const unorderedTransactions = useSelector(selectChildchainTransactions, isEqual); 52 | const transactions = orderBy(unorderedTransactions, i => i.block.timestamp, 'desc'); 53 | 54 | function renderStatus (utxo) { 55 | if (utxo.status === 'Pending') { 56 | return 'Pending'; 57 | } 58 | const total = utxo.outputs.reduce((prev, curr) => { 59 | if (curr.owner !== networkService.account) { 60 | return prev.add(new BN(curr.amount)); 61 | } 62 | return prev; 63 | }, new BN(0)); 64 | return `${total.toString()}`; 65 | } 66 | 67 | const _transactions = transactions.filter(i => { 68 | return i.txhash.includes(searchHistory) || i.metadata.toLowerCase().includes(searchHistory); 69 | }); 70 | 71 | const startingIndex = page === 1 ? 0 : ((page - 1) * PER_PAGE); 72 | const endingIndex = page * PER_PAGE; 73 | const paginatedTransactions = _transactions.slice(startingIndex, endingIndex); 74 | 75 | return ( 76 |
77 |
78 |

History

79 | { 84 | setPage(1); 85 | setSearchHistory(i.target.value.toLowerCase()); 86 | }} 87 | className={styles.searchBar} 88 | /> 89 |
90 | 91 |
92 |
93 | { 95 | setPage(1); 96 | dispatch(setActiveHistoryTab(tab)); 97 | }} 98 | activeTab={activeTab} 99 | tabs={[ 'Transactions', 'Deposits' ]} 100 | /> 101 | 102 | {activeTab === 'Transactions' && ( 103 |
104 | setPage(page + 1)} 108 | onClickBack={() => setPage(page - 1)} 109 | /> 110 | {!paginatedTransactions.length && !loading && ( 111 |
No transaction history.
112 | )} 113 | {!paginatedTransactions.length && loading && ( 114 |
Loading...
115 | )} 116 | {paginatedTransactions.map((i, index) => { 117 | return ( 118 | 131 | ); 132 | })} 133 |
134 | )} 135 | 136 | {activeTab === 'Deposits' && } 137 |
138 | 139 | 140 |
141 |
142 | ); 143 | } 144 | 145 | export default React.memo(Transactions); 146 | -------------------------------------------------------------------------------- /src/containers/transactions/Transactions.module.scss: -------------------------------------------------------------------------------- 1 | @import 'index.module.scss'; 2 | 3 | .container { 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | .header { 9 | h2 { 10 | flex: 1; 11 | margin-bottom: 0; 12 | } 13 | display: flex; 14 | flex-direction: row; 15 | justify-content: space-between; 16 | align-items: center; 17 | margin-bottom: 20px; 18 | @include mobile { 19 | flex-direction: column; 20 | align-items: flex-start; 21 | } 22 | } 23 | 24 | .data { 25 | display: flex; 26 | flex-direction: row; 27 | @include mobile { 28 | flex-direction: column; 29 | } 30 | } 31 | 32 | .section { 33 | flex: 1; 34 | &:first-child { 35 | margin-right: 20px; 36 | @include mobile { 37 | margin-right: 0; 38 | margin-bottom: 20px; 39 | } 40 | } 41 | } 42 | 43 | .transactionSection { 44 | margin-bottom: 20px; 45 | } 46 | 47 | .disclaimer { 48 | color: $gray3; 49 | margin-bottom: 20px; 50 | } 51 | 52 | .searchBar { 53 | flex: 1; 54 | margin-bottom: 0; 55 | & > div { 56 | border: none !important; 57 | border-bottom: 2px solid $gray3 !important; 58 | } 59 | input { 60 | background-color: $gray1 !important; 61 | } 62 | } 63 | 64 | .transactions { 65 | height: 100%; 66 | overflow: auto; 67 | 68 | .transaction { 69 | border-bottom: 1px dashed $gray3; 70 | padding: 20px 0; 71 | &:last-child { 72 | border-bottom: none; 73 | } 74 | } 75 | } 76 | 77 | .subTitle { 78 | display: flex; 79 | flex-direction: row; 80 | align-items: center; 81 | justify-content: space-between; 82 | 83 | margin-bottom: 32px; 84 | span { 85 | margin-right: 20px; 86 | } 87 | } 88 | 89 | .processExitButton { 90 | color: $blue; 91 | cursor: pointer; 92 | } -------------------------------------------------------------------------------- /src/fonts/MessinaSans-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/fonts/MessinaSans-Regular.otf -------------------------------------------------------------------------------- /src/fonts/MessinaSansMono-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/fonts/MessinaSansMono-Regular.otf -------------------------------------------------------------------------------- /src/images/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/arrow.png -------------------------------------------------------------------------------- /src/images/boxarrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/browserwallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/browserwallet.png -------------------------------------------------------------------------------- /src/images/chevron.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/close.png -------------------------------------------------------------------------------- /src/images/coinbase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/coinbase.jpg -------------------------------------------------------------------------------- /src/images/connect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/eth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/key.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/ledger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/ledger.png -------------------------------------------------------------------------------- /src/images/ledger_connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/ledger_connect.png -------------------------------------------------------------------------------- /src/images/lock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/omg_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/walletconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omgnetwork/web-wallet/4a8386f7d1174cdacaf8f092c0f8e3c3ed4ae28d/src/images/walletconnect.png -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import React from 'react'; 17 | import ReactDOM from 'react-dom'; 18 | import { Provider } from 'react-redux'; 19 | import TagManager from 'react-gtm-module'; 20 | 21 | import config from 'util/config'; 22 | import store from 'store'; 23 | 24 | import App from 'containers/app/App'; 25 | 26 | // Renamed due to https://github.com/facebook/create-react-app/issues/10047 27 | import './index.module.scss'; 28 | 29 | if (config.gtmId) { 30 | TagManager.initialize({ gtmId: config.gtmId }); 31 | } 32 | 33 | // https://docs.metamask.io/guide/ethereum-provider.html#ethereum-autorefreshonnetworkchange 34 | if (window.ethereum) { 35 | window.ethereum.autoRefreshOnNetworkChange = false; 36 | } 37 | 38 | ReactDOM.render( 39 | 40 | 41 | , 42 | document.getElementById('root') 43 | ); 44 | -------------------------------------------------------------------------------- /src/index.module.scss: -------------------------------------------------------------------------------- 1 | $red: #ff6868; 2 | $yellow: #f0ba31; 3 | $green: #0ebf9a; 4 | $blue: #4967ff; 5 | 6 | $gray1: #101010; 7 | $gray2: #29292e; 8 | $gray3: #35353f; 9 | $gray4: #585868; 10 | $gray5: #b3b3bf; 11 | $gray6: #ffffff; 12 | $gray7: #F2F3F5; 13 | 14 | :export { 15 | red: $red; 16 | yellow: $yellow; 17 | green: $green; 18 | blue: $blue; 19 | gray1: $gray1; 20 | gray2: $gray2; 21 | gray3: $gray3; 22 | gray4: $gray4; 23 | gray5: $gray5; 24 | gray6: $gray6; 25 | } 26 | 27 | @mixin mobile { 28 | @media screen and (max-width: 1000px) { 29 | @content 30 | } 31 | } 32 | 33 | @mixin tablet { 34 | @media screen and (max-width: 1000px) { 35 | @content 36 | } 37 | } 38 | 39 | @font-face { 40 | font-family: 'Messina'; 41 | src: url(./fonts/MessinaSans-Regular.otf) format('opentype'); 42 | } 43 | 44 | @font-face { 45 | font-family: 'MessinaMono'; 46 | src: url(./fonts/MessinaSansMono-Regular.otf) format('opentype'); 47 | } 48 | 49 | a { 50 | color: inherit; 51 | text-decoration: none; 52 | } 53 | 54 | body { 55 | margin: 0; 56 | padding: 0; 57 | color: $gray5; 58 | background-color: $gray1; 59 | font-family: 'MessinaMono', monospace; 60 | font-size: 14px; 61 | } 62 | 63 | input { 64 | font-family: 'MessinaMono', monospace; 65 | font-size: 1em; 66 | border: none; 67 | outline: none; 68 | } 69 | 70 | input::-webkit-outer-spin-button, 71 | input::-webkit-inner-spin-button { 72 | -webkit-appearance: none; 73 | margin: 0; 74 | } 75 | 76 | h1 { 77 | margin: 0; 78 | white-space: pre; 79 | font-family: 'Messina'; 80 | font-weight: 400; 81 | font-size: 2em; 82 | color: $blue; 83 | } 84 | 85 | h2 { 86 | color: $gray6; 87 | font-family: 'Messina'; 88 | font-weight: 100; 89 | margin: 0 0 10px 0; 90 | font-size: 1.5em; 91 | @include mobile { 92 | font-size: 1.2em; 93 | } 94 | } 95 | 96 | // override globals and third party libs 97 | .walletconnect-modal__base { 98 | max-width: 225px !important; 99 | } 100 | -------------------------------------------------------------------------------- /src/reducers/__tests__/balanceReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import balanceReducer from '../balanceReducer'; 17 | 18 | describe('balanceReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = balanceReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({ rootchain: [], childchain: [] }); 22 | }); 23 | 24 | it('should handle balance success', () => { 25 | const action = { 26 | type: 'BALANCE/GET/SUCCESS', 27 | payload: { rootchain: [ 'toto' ], childchain: [ 'toto' ] } 28 | }; 29 | const newState = balanceReducer(undefined, action); 30 | expect(newState).toEqual(action.payload); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/reducers/__tests__/depositReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import depositReducer from '../depositReducer'; 17 | 18 | describe('depositReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = depositReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({ eth: {}, erc20: {} }); 22 | }); 23 | 24 | it('should handle deposit fetch success', () => { 25 | const action = { 26 | type: 'DEPOSIT/GETALL/SUCCESS', 27 | payload: { 28 | eth: [ { 29 | transactionHash: 'toto' 30 | } ], 31 | erc20: [ { 32 | transactionHash: 'toto' 33 | } ] 34 | } 35 | }; 36 | 37 | const expected = { 38 | eth: { 'toto': { transactionHash: 'toto' } }, 39 | erc20: { 'toto': { transactionHash: 'toto' } } 40 | }; 41 | 42 | const newState = depositReducer(undefined, action); 43 | expect(newState).toEqual(expected); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/reducers/__tests__/exitReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import exitReducer from '../exitReducer'; 17 | 18 | describe('exitReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = exitReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({ pending: {}, exited: {} }); 22 | }); 23 | 24 | it('should handle exit fetch success', () => { 25 | const action = { 26 | type: 'EXIT/GETALL/SUCCESS', 27 | payload: { pending: [ 'toto' ], exited: [ 'toto' ] } 28 | }; 29 | const newState = exitReducer(undefined, action); 30 | expect(newState).toEqual(action.payload); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/reducers/__tests__/feeReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import feeReducer from '../feeReducer'; 17 | 18 | describe('feeReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = feeReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({}); 22 | }); 23 | 24 | it('should handle fee fetch success', () => { 25 | const action = { 26 | type: 'FEE/GET/SUCCESS', 27 | payload: [ 28 | { currency: 'ETH', amount: 1 }, 29 | { currency: 'OMG', amount: 10 } 30 | ] 31 | }; 32 | const newState = feeReducer(undefined, action); 33 | expect(newState).toEqual({ 34 | ETH: { currency: 'ETH', amount: 1 }, 35 | OMG: { currency: 'OMG', amount: 10 } 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/reducers/__tests__/gasReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import gasReducer from '../gasReducer'; 17 | 18 | describe('gasReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = gasReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({ slow: 0, normal: 0, fast: 0 }); 22 | }); 23 | 24 | it('should handle gas fetch success', () => { 25 | const action = { 26 | type: 'GAS/GET/SUCCESS', 27 | payload: { slow: 1, normal: 10, fast: 100 } 28 | }; 29 | const newState = gasReducer(undefined, action); 30 | expect(newState).toEqual(action.payload); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/reducers/__tests__/loadingReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import loadingReducer from '../loadingReducer'; 17 | 18 | describe('loadingReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = loadingReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({}); 22 | }); 23 | 24 | it('should handle request correctly', () => { 25 | const action = { type: 'TEST/GET/REQUEST' }; 26 | const newState = loadingReducer(undefined, action); 27 | expect(newState).toEqual({ 'TEST/GET': true }); 28 | }); 29 | 30 | it('should cancel loading state on non request correctly', () => { 31 | const action = { type: 'TEST/GET/SUCCESS' }; 32 | const newState = loadingReducer(undefined, action); 33 | expect(newState).toEqual({ 'TEST/GET': false }); 34 | 35 | const action2 = { type: 'TEST/GET/ERROR' }; 36 | const newState2 = loadingReducer(undefined, action2); 37 | expect(newState2).toEqual({ 'TEST/GET': false }); 38 | }); 39 | 40 | it('should pass through other action types', () => { 41 | const action = { type: 'TEST/MODAL/OPEN' }; 42 | const newState = loadingReducer(undefined, action); 43 | expect(newState).toEqual({}); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/reducers/__tests__/queueReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import queueReducer from '../queueReducer'; 17 | 18 | describe('queueReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = queueReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({}); 22 | }); 23 | 24 | it('should handle queue fetch success', () => { 25 | const action = { 26 | type: 'QUEUE/GET/SUCCESS', 27 | payload: { currency: 'ETH', queue: [ 1,2,3 ] } 28 | }; 29 | const newState = queueReducer(undefined, action); 30 | expect(newState).toEqual({ ETH: [ 1,2,3 ] }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/reducers/__tests__/setupReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import setupReducer from '../setupReducer'; 17 | 18 | describe('setupReducer', () => { 19 | it('should return the initial state', () => { 20 | const initialState = { walletMethod: 'WalletConnect' }; 21 | const newState = setupReducer(initialState, { type: 'ACTION/NOT/EXIST' }); 22 | expect(newState).toEqual(initialState); 23 | }); 24 | 25 | it('should handle setting the wallet method', () => { 26 | const initialState = { walletMethod: null }; 27 | const action = { 28 | type: 'SETUP/WALLET_METHOD/SET', 29 | payload: 'WalletConnect' 30 | }; 31 | const newState = setupReducer(initialState, action); 32 | expect(newState).toEqual({ ...initialState, walletMethod: 'WalletConnect' }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/reducers/__tests__/statusReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import statusReducer from '../statusReducer'; 17 | 18 | describe('statusReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = statusReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({ connection: false, byzantine: false }); 22 | }); 23 | 24 | it('should handle status fetch success', () => { 25 | const action = { 26 | type: 'STATUS/GET/SUCCESS', 27 | payload: { connection: true, byzantine: false } 28 | }; 29 | const newState = statusReducer(undefined, action); 30 | expect(newState).toEqual(action.payload); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/reducers/__tests__/tokenReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import tokenReducer from '../tokenReducer'; 17 | 18 | describe('tokenReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = tokenReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({ 22 | '0x0000000000000000000000000000000000000000': { 23 | currency: '0x0000000000000000000000000000000000000000', 24 | decimals: 18, 25 | name: 'ETH' 26 | } 27 | }); 28 | }); 29 | 30 | it('should handle token fetch success', () => { 31 | const action = { 32 | type: 'TOKEN/GET/SUCCESS', 33 | payload: { currency: '0xomg', decimals: 18, name: 'OMG' } 34 | }; 35 | const newState = tokenReducer(undefined, action); 36 | expect(newState).toEqual({ 37 | '0x0000000000000000000000000000000000000000': { currency: '0x0000000000000000000000000000000000000000', decimals: 18, name: 'ETH' }, 38 | '0xomg': { currency: '0xomg', decimals: 18, name: 'OMG' } 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/reducers/__tests__/transactionReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import transactionReducer from '../transactionReducer'; 17 | 18 | describe('transactionReducer', () => { 19 | it('should return the initial state', () => { 20 | const newState = transactionReducer(undefined, { type: '@@INIT' }); 21 | expect(newState).toEqual({}); 22 | }); 23 | 24 | it('should handle transaction fetch success', () => { 25 | const action = { 26 | type: 'TRANSACTION/GETALL/SUCCESS', 27 | payload: [ { txhash: '0x1', metadata: 'toto' } ] 28 | }; 29 | const newState = transactionReducer(undefined, action); 30 | expect(newState).toEqual({ 31 | '0x1': { txhash: '0x1', metadata: 'toto' } 32 | }); 33 | }); 34 | 35 | it('should handle transfer create success', () => { 36 | const action = { 37 | type: 'TRANSFER/CREATE/SUCCESS', 38 | payload: { txhash: '0x1', metadata: 'toto' } 39 | }; 40 | const newState = transactionReducer(undefined, action); 41 | expect(newState).toEqual({ 42 | '0x1': { txhash: '0x1', metadata: 'toto' } 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/reducers/__tests__/uiReducer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import uiReducer from '../uiReducer'; 17 | 18 | const initialState = { 19 | depositModal: false, 20 | transferModal: false, 21 | exitModal: false, 22 | mergeModal: false, 23 | wrongNetworkModal: false, 24 | ledger: false, 25 | ledgerConnectModal: true, 26 | activeHistoryTab: 'Transactions', 27 | alert: null, 28 | error: null 29 | }; 30 | 31 | describe('uiReducer', () => { 32 | it('should return the initial state', () => { 33 | const newState = uiReducer(undefined, { type: '@@INIT' }); 34 | expect(newState).toEqual(initialState); 35 | }); 36 | 37 | it('should handle modal open', () => { 38 | const action = { 39 | type: 'UI/MODAL/OPEN', 40 | payload: 'depositModal' 41 | }; 42 | const newState = uiReducer(undefined, action); 43 | expect(newState).toEqual({ ...initialState, depositModal: true }); 44 | }); 45 | 46 | it('should handle modal close', () => { 47 | const action = { 48 | type: 'UI/MODAL/CLOSE', 49 | payload: 'depositModal' 50 | }; 51 | const newState = uiReducer(undefined, action); 52 | expect(newState).toEqual(initialState); 53 | }); 54 | 55 | it('should handle new alert', () => { 56 | const action = { 57 | type: 'UI/ALERT/UPDATE', 58 | payload: 'oops' 59 | }; 60 | const newState = uiReducer(undefined, action); 61 | expect(newState).toEqual({ ...initialState, alert: 'oops' }); 62 | }); 63 | 64 | it('should handle new error', () => { 65 | const action = { 66 | type: 'UI/ERROR/UPDATE', 67 | payload: 'oops' 68 | }; 69 | const newState = uiReducer(undefined, action); 70 | expect(newState).toEqual({ ...initialState, error: 'oops' }); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /src/reducers/balanceReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialState = { 17 | rootchain: [], 18 | childchain: [] 19 | }; 20 | 21 | function balanceReducer (state = initialState, action) { 22 | switch (action.type) { 23 | case 'BALANCE/GET/SUCCESS': 24 | const { rootchain, childchain } = action.payload; 25 | return { ...state, rootchain, childchain }; 26 | default: 27 | return state; 28 | } 29 | } 30 | 31 | export default balanceReducer; 32 | -------------------------------------------------------------------------------- /src/reducers/depositReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { keyBy } from 'lodash'; 17 | 18 | const initialState = { 19 | eth: {}, 20 | erc20: {} 21 | }; 22 | 23 | function depositReducer (state = initialState, action) { 24 | switch (action.type) { 25 | case 'DEPOSIT/CREATE/SUCCESS': 26 | const isEth = action.payload.isEth; 27 | if (isEth) { 28 | return { 29 | ...state, 30 | eth: { 31 | ...state.eth, 32 | [action.payload.transactionHash]: action.payload 33 | } 34 | }; 35 | } 36 | return { 37 | ...state, 38 | erc20: { 39 | ...state.erc20, 40 | [action.payload.transactionHash]: action.payload 41 | } 42 | }; 43 | case 'DEPOSIT/CHECKALL/SUCCESS': 44 | case 'DEPOSIT/GETALL/SUCCESS': 45 | const { eth, erc20 } = action.payload; 46 | return { 47 | ...state, 48 | eth: { 49 | ...state.eth, 50 | ...keyBy(eth, 'transactionHash') 51 | }, 52 | erc20: { 53 | ...state.erc20, 54 | ...keyBy(erc20, 'transactionHash') 55 | } 56 | }; 57 | default: 58 | return state; 59 | } 60 | } 61 | 62 | export default depositReducer; 63 | -------------------------------------------------------------------------------- /src/reducers/exitReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { keyBy } from 'lodash'; 17 | 18 | const initialState = { 19 | pending: {}, 20 | exited: {} 21 | }; 22 | 23 | function exitReducer (state = initialState, action) { 24 | switch (action.type) { 25 | case 'EXIT/GETALL/SUCCESS': 26 | // action.payload will be null on an event timeout, so return old state 27 | if (!action.payload) { 28 | return state; 29 | } 30 | return { ...state, ...action.payload }; 31 | case 'EXIT/CREATE/SUCCESS': 32 | return { 33 | ...state, 34 | pending: { 35 | ...state.pending, 36 | [action.payload.transactionHash]: action.payload 37 | } 38 | }; 39 | case 'EXIT/CHECKALL/SUCCESS': 40 | return { 41 | ...state, 42 | pending: { 43 | ...state.pending, 44 | ...keyBy(action.payload, 'transactionHash') 45 | } 46 | }; 47 | default: 48 | return state; 49 | } 50 | } 51 | 52 | export default exitReducer; 53 | -------------------------------------------------------------------------------- /src/reducers/feeReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { keyBy } from 'lodash'; 17 | const initialState = {}; 18 | 19 | function feeReducer (state = initialState, action) { 20 | switch (action.type) { 21 | case 'FEE/GET/SUCCESS': 22 | return { ...state, ...keyBy(action.payload, 'currency') }; 23 | default: 24 | return state; 25 | } 26 | } 27 | 28 | export default feeReducer; 29 | -------------------------------------------------------------------------------- /src/reducers/gasReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialState = { 17 | slow: 0, 18 | normal: 0, 19 | fast: 0 20 | }; 21 | 22 | function gasReducer (state = initialState, action) { 23 | switch (action.type) { 24 | case 'GAS/GET/SUCCESS': 25 | return { ...state, ...action.payload }; 26 | default: 27 | return state; 28 | } 29 | } 30 | 31 | export default gasReducer; 32 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { combineReducers } from 'redux'; 17 | 18 | import loadingReducer from './loadingReducer'; 19 | import depositReducer from './depositReducer'; 20 | import transactionReducer from './transactionReducer'; 21 | import statusReducer from './statusReducer'; 22 | import balanceReducer from './balanceReducer'; 23 | import exitReducer from './exitReducer'; 24 | import queueReducer from './queueReducer'; 25 | import tokenReducer from './tokenReducer'; 26 | import feeReducer from './feeReducer'; 27 | import gasReducer from './gasReducer'; 28 | import uiReducer from './uiReducer'; 29 | import setupReducer from './setupReducer'; 30 | 31 | const rootReducer = combineReducers({ 32 | loading: loadingReducer, 33 | deposit: depositReducer, 34 | transaction: transactionReducer, 35 | status: statusReducer, 36 | balance: balanceReducer, 37 | exit: exitReducer, 38 | queue: queueReducer, 39 | token: tokenReducer, 40 | fees: feeReducer, 41 | gas: gasReducer, 42 | ui: uiReducer, 43 | setup: setupReducer 44 | }); 45 | 46 | export default rootReducer; 47 | -------------------------------------------------------------------------------- /src/reducers/loadingReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialLoadingState = {}; 17 | 18 | function loadingReducer (state = initialLoadingState, action) { 19 | const segments = action.type.split('/'); 20 | const requestName = `${segments[0]}/${segments[1]}`; 21 | const requestState = segments[2]; 22 | 23 | if ( 24 | requestState !== 'REQUEST' && 25 | requestState !== 'SUCCESS' && 26 | requestState !== 'ERROR' 27 | ) { 28 | return state; 29 | } 30 | 31 | return { 32 | ...state, 33 | [requestName]: requestState === 'REQUEST' 34 | }; 35 | } 36 | 37 | export default loadingReducer; 38 | -------------------------------------------------------------------------------- /src/reducers/queueReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialState = {}; 17 | 18 | function queueReducer (state = initialState, action) { 19 | switch (action.type) { 20 | case 'QUEUE/GET/SUCCESS': 21 | if (action.payload) { 22 | const { currency, queue } = action.payload; 23 | return { ...state, [currency]: queue }; 24 | } 25 | return state; 26 | default: 27 | return state; 28 | } 29 | } 30 | 31 | export default queueReducer; 32 | -------------------------------------------------------------------------------- /src/reducers/setupReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialState = { 17 | walletMethod: null 18 | }; 19 | 20 | function setupReducer (state = initialState, action) { 21 | switch (action.type) { 22 | case 'SETUP/WALLET_METHOD/SET': 23 | return { ...state, walletMethod: action.payload }; 24 | default: 25 | return state; 26 | } 27 | } 28 | 29 | export default setupReducer; 30 | -------------------------------------------------------------------------------- /src/reducers/statusReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialState = { 17 | connection: false, 18 | byzantine: false 19 | }; 20 | 21 | function statusReducer (state = initialState, action) { 22 | switch (action.type) { 23 | case 'STATUS/GET/SUCCESS': 24 | return { ...state, ...action.payload }; 25 | case 'ETHSTATS/GET/SUCCESS': 26 | if (action.payload) { 27 | return { ...state, ...action.payload }; 28 | } 29 | return state; 30 | default: 31 | return state; 32 | } 33 | } 34 | 35 | export default statusReducer; 36 | -------------------------------------------------------------------------------- /src/reducers/tokenReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const eth = '0x0000000000000000000000000000000000000000'; 17 | const initialState = { 18 | [eth]: { 19 | currency: eth, 20 | decimals: 18, 21 | name: 'ETH' 22 | } 23 | }; 24 | 25 | function tokenReducer (state = initialState, action) { 26 | switch (action.type) { 27 | case 'TOKEN/GET/SUCCESS': 28 | return { ...state, [action.payload.currency]: action.payload }; 29 | default: 30 | return state; 31 | } 32 | } 33 | 34 | export default tokenReducer; 35 | -------------------------------------------------------------------------------- /src/reducers/transactionReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { keyBy } from 'lodash'; 17 | const initialState = {}; 18 | 19 | function transactionReducer (state = initialState, action) { 20 | switch (action.type) { 21 | case 'TRANSACTION/GETALL/SUCCESS': 22 | return { ...state, ...keyBy(action.payload, 'txhash') }; 23 | case 'TRANSFER/CREATE/SUCCESS': 24 | return { ...state, [action.payload.txhash]: action.payload }; 25 | default: 26 | return state; 27 | } 28 | } 29 | 30 | export default transactionReducer; 31 | -------------------------------------------------------------------------------- /src/reducers/uiReducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | const initialState = { 17 | depositModal: false, 18 | transferModal: false, 19 | exitModal: false, 20 | mergeModal: false, 21 | wrongNetworkModal: false, 22 | ledgerConnectModal: true, 23 | ledger: false, 24 | alert: null, 25 | error: null, 26 | activeHistoryTab: 'Transactions' 27 | }; 28 | 29 | function uiReducer (state = initialState, action) { 30 | switch (action.type) { 31 | case 'UI/MODAL/OPEN': 32 | return { ...state, [action.payload]: true }; 33 | case 'UI/MODAL/CLOSE': 34 | return { ...state, [action.payload]: false }; 35 | case 'UI/ALERT/UPDATE': 36 | return { ...state, alert: action.payload }; 37 | case 'UI/ERROR/UPDATE': 38 | return { ...state, error: action.payload }; 39 | case 'UI/LEDGER/UPDATE': 40 | return { ...state, ledger: action.payload }; 41 | case 'UI/HISTORYTAB/UPDATE': 42 | return { ...state, activeHistoryTab: action.payload }; 43 | default: 44 | return state; 45 | } 46 | } 47 | 48 | export default uiReducer; 49 | -------------------------------------------------------------------------------- /src/selectors/balanceSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectRootchainBalance (state) { 17 | return state.balance.rootchain; 18 | } 19 | 20 | export function selectChildchainBalance (state) { 21 | return state.balance.childchain; 22 | } 23 | -------------------------------------------------------------------------------- /src/selectors/exitSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectPendingExits (state) { 17 | return Object.values(state.exit.pending); 18 | } 19 | 20 | export function selectExitedExits (state) { 21 | return Object.values(state.exit.exited); 22 | } 23 | -------------------------------------------------------------------------------- /src/selectors/feeSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectFees (state) { 17 | return state.fees; 18 | } 19 | -------------------------------------------------------------------------------- /src/selectors/gasSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectGas (state) { 17 | return state.gas; 18 | } 19 | -------------------------------------------------------------------------------- /src/selectors/loadingSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectLoading (requestNames) { 17 | return function (state) { 18 | return requestNames.some(name => state.loading[name]); 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/selectors/queueSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { flatten } from 'lodash'; 17 | 18 | export function selectQueue (currency) { 19 | return function (state) { 20 | return state.queue[currency]; 21 | }; 22 | } 23 | 24 | export function selectQueues (state) { 25 | return state.queue; 26 | } 27 | 28 | export function selectAllQueues (state) { 29 | const queues = Object.values(state.queue); 30 | return flatten(queues); 31 | } 32 | 33 | export function selectQueuedTokens (state) { 34 | return Object.keys(state.queue); 35 | } 36 | -------------------------------------------------------------------------------- /src/selectors/setupSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectWalletMethod () { 17 | return function (state) { 18 | return state.setup['walletMethod']; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/selectors/statusSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectConnection (state) { 17 | return state.status.connection; 18 | } 19 | 20 | export function selectByzantine (state) { 21 | return state.status.byzantine; 22 | } 23 | 24 | export function selectIsSynced (state) { 25 | return state.status.watcherSynced; 26 | } 27 | 28 | export function selectLastSeenBlock (state) { 29 | return state.status.lastSeenBlock; 30 | } 31 | -------------------------------------------------------------------------------- /src/selectors/transactionSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectChildchainTransactions (state) { 17 | return Object.values(state.transaction); 18 | } 19 | 20 | export function selectErc20Deposits (state) { 21 | return Object.values(state.deposit.erc20); 22 | } 23 | 24 | export function selectEthDeposits (state) { 25 | return Object.values(state.deposit.eth); 26 | } 27 | -------------------------------------------------------------------------------- /src/selectors/uiSelector.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | export function selectModalState (modal) { 17 | return function (state) { 18 | return state.ui[modal]; 19 | }; 20 | } 21 | 22 | export function selectAlert (state) { 23 | return state.ui.alert; 24 | } 25 | 26 | export function selectError (state) { 27 | return state.ui.error; 28 | } 29 | 30 | export function selectLedger (state) { 31 | return state.ui.ledger; 32 | } 33 | 34 | export function selectActiveHistoryTab (state) { 35 | return state.ui.activeHistoryTab; 36 | } 37 | -------------------------------------------------------------------------------- /src/services/__mocks__/networkService.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. */ 12 | 13 | const networkService = { 14 | OmgUtil: { 15 | ethErrorReason: jest.fn().mockImplementationOnce(() => Promise.resolve('toto')) 16 | }, 17 | web3: { 18 | eth: { 19 | Contract: function () { 20 | return { 21 | methods: { 22 | symbol: () => ({ 23 | call: jest.fn(() => Promise.resolve('OMG')) 24 | }), 25 | decimals: () => ({ 26 | call: jest.fn(() => Promise.resolve(18)) 27 | }) 28 | } 29 | }; 30 | } 31 | } 32 | }, 33 | checkStatus: () => Promise.resolve('toto'), 34 | getBalances: () => Promise.resolve('toto'), 35 | getAllTransactions: () => Promise.resolve('toto'), 36 | getDeposits: () => Promise.resolve('toto'), 37 | getExits: () => Promise.resolve('toto'), 38 | checkForExitQueue: () => Promise.resolve(true), 39 | getExitQueue: () => Promise.resolve('toto'), 40 | addExitQueue: () => Promise.resolve('toto'), 41 | exitUtxo: () => Promise.resolve('toto'), 42 | depositEth: () => Promise.resolve('toto'), 43 | processExits: () => Promise.resolve('toto'), 44 | transfer: () => Promise.resolve('toto'), 45 | mergeUtxos: () => Promise.resolve('toto'), 46 | getGasPrice: () => Promise.resolve('toto'), 47 | fetchFees: () => Promise.resolve([ 1, 2, 3 ]) 48 | }; 49 | 50 | export default networkService; 51 | -------------------------------------------------------------------------------- /src/services/errorService.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import * as Sentry from '@sentry/react'; 17 | import config from 'util/config'; 18 | 19 | import { openError } from 'actions/uiAction'; 20 | 21 | if (config.sentry) { 22 | Sentry.init({ dsn: config.sentry }); 23 | } 24 | 25 | const errorCache = []; 26 | const noLogErrors = [ 27 | 'user denied', 28 | 'user rejected', 29 | 'user canceled', 30 | 'user cancelled' 31 | ]; 32 | 33 | export class WebWalletError extends Error { 34 | constructor ({ 35 | originalError, 36 | customErrorMessage, 37 | reportToSentry, 38 | reportToUi 39 | }) { 40 | super(originalError.message); 41 | this._originalError = originalError; 42 | this._customErrorMessage = customErrorMessage; 43 | this._reportToSentry = reportToSentry; 44 | this._reportToUi = reportToUi; 45 | } 46 | 47 | report (dispatchMethod) { 48 | const metamaskHeaderNotFoundCode = -3200; 49 | if ( 50 | noLogErrors.find(i => this._originalError.message && this._originalError.message.toLowerCase().includes(i)) || 51 | this._originalError.code === metamaskHeaderNotFoundCode 52 | ) { 53 | return; 54 | } 55 | 56 | if (this._reportToSentry && config.sentry) { 57 | if (!errorCache.includes(this._originalError.message)) { 58 | errorCache.push(this._originalError.message); 59 | try { 60 | Sentry.captureException(this._originalError); 61 | } catch (error) { 62 | // 63 | } 64 | } 65 | } 66 | 67 | if (this._reportToUi) { 68 | dispatchMethod( 69 | openError(this._customErrorMessage || this._originalError.message || 'Something went wrong.') 70 | ); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/store/__mocks__/index.js: -------------------------------------------------------------------------------- 1 | import configureMockStore from 'redux-mock-store'; 2 | import thunk from 'redux-thunk'; 3 | 4 | const middlewares = [ thunk ]; 5 | const mockStore = configureMockStore(middlewares); 6 | 7 | const store = mockStore({ 8 | fees: {}, 9 | token: { 10 | '0x0000000000000000000000000000000000000000': { 11 | currency: '0x0000000000000000000000000000000000000000', 12 | decimals: 18, 13 | name: 'ETH' 14 | } 15 | } 16 | }); 17 | 18 | export default store; 19 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import reduxThunk from 'redux-thunk'; 17 | import * as Sentry from '@sentry/react'; 18 | import { composeWithDevTools } from 'redux-devtools-extension'; 19 | import { createStore, applyMiddleware } from 'redux'; 20 | import reducers from 'reducers'; 21 | 22 | const initialState = {}; 23 | 24 | const sentryReduxEnhancer = Sentry.createReduxEnhancer({ 25 | configureScopeWithState: (scope, state) => { 26 | scope.setTag('wallet-method', state.setup.walletMethod); 27 | }, 28 | stateTransformer: state => { 29 | return { 30 | status: state.status, 31 | ui: state.ui, 32 | setup: state.setup 33 | }; 34 | } 35 | }); 36 | 37 | const store = createStore( 38 | reducers, 39 | initialState, 40 | composeWithDevTools ( 41 | applyMiddleware(reduxThunk), 42 | sentryReduxEnhancer 43 | ) 44 | ); 45 | 46 | export default store; 47 | -------------------------------------------------------------------------------- /src/util/__tests__/amountConvert.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { logAmount, powAmount } from 'util/amountConvert'; 17 | 18 | describe('logAmount', () => { 19 | it('renders the highest denomination as a string', () => { 20 | const res = logAmount('1', 18); 21 | expect(res).toBe('0.000000000000000001'); 22 | expect(typeof res).toBe('string'); 23 | }); 24 | 25 | it('can safely accept any amount or power type', () => { 26 | const res = logAmount(1, 18); 27 | expect(res).toBe('0.000000000000000001'); 28 | 29 | const res2 = logAmount('1.0', '18'); 30 | expect(res2).toBe('0.000000000000000001'); 31 | }); 32 | 33 | it('can handle unsafe numbers', () => { 34 | const res = logAmount('999999999999999999999999999999999', 18); 35 | expect(res).toBe('999999999999999.999999999999999999'); 36 | }); 37 | }); 38 | 39 | describe('powAmount', () => { 40 | it('renders the lowest denomination as a string', () => { 41 | const res = powAmount('1', 18); 42 | expect(res).toBe('1000000000000000000'); 43 | expect(typeof res).toBe('string'); 44 | }); 45 | 46 | it('can safely accept any amount or power type', () => { 47 | const res = powAmount(1, 18); 48 | expect(res).toBe('1000000000000000000'); 49 | 50 | const res2 = powAmount('1.0', '18'); 51 | expect(res2).toBe('1000000000000000000'); 52 | }); 53 | 54 | it('can handle unsafe numbers', () => { 55 | const res = powAmount('999999999999999999999999999999999', 18); 56 | expect(res).toBe('999999999999999999999999999999999000000000000000000'); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/util/amountConvert.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | // we use BigNumber here for decimal support 17 | import BigNumber from 'bignumber.js'; 18 | 19 | export function logAmount (amount, power) { 20 | const x = new BigNumber(amount); 21 | const exp = new BigNumber(10).pow(power); 22 | 23 | const calculated = x.div(exp); 24 | return calculated.toFixed(); 25 | } 26 | 27 | export function powAmount (amount, power) { 28 | const x = new BigNumber(amount); 29 | const exp = new BigNumber(10).pow(power); 30 | 31 | const calculated = x.multipliedBy(exp); 32 | return calculated.toFixed(0); 33 | } 34 | -------------------------------------------------------------------------------- /src/util/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import env from '@beam-australia/react-env'; 17 | 18 | export default { 19 | watcherUrl: env('WATCHER_URL'), 20 | plasmaAddress: env('PLASMA_ADDRESS'), 21 | blockExplorerUrl: env('BLOCKEXPLORER_URL'), 22 | etherscanUrl: env('ETHERSCAN_URL'), 23 | checkSyncInterval: env('SYNC_INTERVAL'), 24 | pollInterval: env('POLL_INTERVAL'), 25 | network: env('NETWORK'), 26 | alternateWallets: env('ALTERNATE_WALLETS'), 27 | sentry: env('SENTRY_DSN'), 28 | gtmId: env('GTM_ID'), 29 | rpcProxy: env('RPC_PROXY') 30 | }; 31 | -------------------------------------------------------------------------------- /src/util/networkName.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { omit } from 'lodash'; 17 | import config from 'util/config'; 18 | 19 | const networkMap = { 20 | 'ropsten': 'Ropsten Test Network', 21 | 'main': 'Main Ethereum Network', 22 | 'rinkeby': 'Rinkeby Test Network', 23 | 'kovan': 'Kovan Test Network', 24 | 'private': 'Private Network' 25 | }; 26 | 27 | const shortNetworkMap = { 28 | 'ropsten': 'Ropsten', 29 | 'main': 'Mainnet', 30 | 'rinkeby': 'Rinkeby', 31 | 'kovan': 'Kovan', 32 | 'private': 'Private' 33 | }; 34 | 35 | export function getNetworkName () { 36 | return networkMap[config.network]; 37 | } 38 | 39 | export function getShortNetworkName () { 40 | return shortNetworkMap[config.network]; 41 | } 42 | 43 | export function getOtherNetworks () { 44 | const otherNetworks = omit(networkMap, [ 'private', config.network ]); 45 | return Object.values(otherNetworks); 46 | } 47 | 48 | export function getAlternateNetworks () { 49 | const rawAlternates = config.alternateWallets; 50 | if (!rawAlternates) { 51 | return []; 52 | } 53 | const options = rawAlternates.split('|'); 54 | 55 | const networks = []; 56 | options.forEach(option => { 57 | const [ networkName, networkUrl ] = option.split(','); 58 | networks.push({ 59 | name: networkName.trim(), 60 | url: networkUrl.trim() 61 | }); 62 | }); 63 | 64 | return networks; 65 | } 66 | -------------------------------------------------------------------------------- /src/util/useInterval.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019-present OmiseGO Pte Ltd 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. */ 15 | 16 | import { useEffect, useRef } from 'react'; 17 | 18 | export default function useInterval (callback, delay) { 19 | const savedCallback = useRef(); 20 | 21 | useEffect(() => { 22 | savedCallback.current = callback; 23 | }, [ callback ]); 24 | 25 | useEffect(() => { 26 | function tick () { 27 | savedCallback.current(); 28 | } 29 | if (delay !== null) { 30 | tick(); 31 | let id = setInterval(tick, delay); 32 | return () => clearInterval(id); 33 | } 34 | }, [ delay ]); 35 | } 36 | --------------------------------------------------------------------------------