From 036f81209a87946cc3269186e2e76e9320c7d2e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Volek?= Date: Mon, 30 Jul 2018 12:23:30 +0200 Subject: [PATCH 01/10] Added eslint --- .eslintrc | 55 +++++ package.json | 11 +- yarn.lock | 633 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 685 insertions(+), 14 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..4e1391be --- /dev/null +++ b/.eslintrc @@ -0,0 +1,55 @@ +{ + "extends": [ + "eslint-config-airbnb", + "plugin:flowtype/recommended", + "plugin:jest/recommended" + + ], + "env": { + "browser": true, + "jest": true + }, + "rules": { + "react/jsx-one-expression-per-line": 0, + "react/jsx-indent": [2, 4], + "react/jsx-indent-props": [2, 4], + "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"]}], + "indent": [2, 4, { "SwitchCase": 1 }], + "no-confusing-arrow": [2,{ "allowParens": true }], + "no-console": 0, + "no-alert": 0, + "no-prototype-builtins": 0, + "new-cap": 0, + "max-len": 0, + "eol-last": 0, + "spaced-comment": 0 + }, + "plugins": [ + "react", + "import", + "jest", + "flowtype" + ], + "settings": { + "import/parser": "babel-eslint", + "import/resolver": { + "node": { + "moduleDirectory": [ + "src", + "node_modules" + ] + } + }, + "import/ignore": [ + "\\.(scss|less|css)$" + ] + }, + "parserOptions": { + "ecmaVersion": 7, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "experimentalObjectRestSpread": true + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 0fee8e93..e9656541 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "dev": "webpack-dev-server --config ./webpack/config.dev.babel.js --mode development", "build": "rm -rf build && webpack --config ./webpack/config.prod.babel.js --progress", "flow": "flow check src/js", - "test": "" + "test": "", + "lint": "npx eslint ./" }, "dependencies": { "color-hash": "^1.0.3", @@ -49,6 +50,7 @@ }, "devDependencies": { "babel-cli": "^6.24.1", + "babel-eslint": "^8.2.6", "babel-loader": "7.1.4", "babel-plugin-root-import": "^5.1.0", "babel-plugin-transform-class-properties": "^6.24.1", @@ -59,6 +61,13 @@ "babel-preset-react": "^6.24.1", "copy-webpack-plugin": "4.5.1", "css-loader": "0.28.11", + "eslint": "^4", + "eslint-config-airbnb": "^17.0.0", + "eslint-plugin-flowtype": "^2.50.0", + "eslint-plugin-import": "^2.13.0", + "eslint-plugin-jest": "^21.18.0", + "eslint-plugin-jsx-a11y": "^6.1.1", + "eslint-plugin-react": "^7.10.0", "file-loader": "1.1.11", "flow-bin": "0.72.0", "html-webpack-plugin": "^3.2.0", diff --git a/yarn.lock b/yarn.lock index f9cdf0cd..c94b6d3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,82 @@ # yarn lockfile v1 +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -157,16 +233,34 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + acorn@^5.0.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" +acorn@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + add-dom-event-listener@1.x: version "1.0.2" resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.0.2.tgz#8faed2c41008721cf111da1d30d995b85be42bed" dependencies: object-assign "4.x" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + ajv-keywords@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" @@ -178,6 +272,15 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + ajv@^6.1.0: version "6.1.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e" @@ -265,6 +368,13 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" @@ -362,6 +472,10 @@ assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + ast-types@0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" @@ -411,6 +525,12 @@ aws4@^1.2.1: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" +axobject-query@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.1.tgz#05dfa705ada8ad9db993fa6896f22d395b0b0a07" + dependencies: + ast-types-flow "0.0.7" + babel-cli@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" @@ -432,7 +552,7 @@ babel-cli@^6.24.1: optionalDependencies: chokidar "^1.6.1" -babel-code-frame@^6.26.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -464,6 +584,17 @@ babel-core@^6.0.14, babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.6" +babel-eslint@^8.2.6: + version "8.2.6" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + eslint-scope "3.7.1" + eslint-visitor-keys "^1.0.0" + babel-generator@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" @@ -1139,6 +1270,10 @@ babelify@^7.3.0: babel-core "^6.0.14" object-assign "^4.0.0" +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + babylon@^6.17.3, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1376,6 +1511,10 @@ bs58@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d" +buffer-from@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" @@ -1452,6 +1591,16 @@ call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + camel-case@3.0.x: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -1593,6 +1742,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + clap@^1.0.9: version "1.2.3" resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" @@ -1839,6 +1992,15 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" +concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + connect-history-api-fallback@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" @@ -1857,6 +2019,10 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -1959,7 +2125,7 @@ create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -2118,6 +2284,10 @@ d@1: dependencies: es5-ext "^0.10.9" +damerau-levenshtein@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" + dargs@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-5.1.0.tgz#ec7ea50c78564cd36c9d5ec18f66329fade27829" @@ -2140,7 +2310,7 @@ dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" -debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2182,6 +2352,10 @@ deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -2212,6 +2386,18 @@ defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + del@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" @@ -2304,6 +2490,19 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + dom-align@1.x: version "1.6.7" resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.6.7.tgz#6858138efb6b77405ce99146d0be5e4f7282813f" @@ -2419,6 +2618,10 @@ elliptic@^6.0.0, elliptic@^6.2.3: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +emoji-regex@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -2490,6 +2693,16 @@ es-abstract@^1.5.1, es-abstract@^1.7.0: is-callable "^1.1.3" is-regex "^1.0.4" +es-abstract@^1.6.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" @@ -2529,28 +2742,173 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-scope@^3.7.1: +eslint-config-airbnb-base@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.0.0.tgz#2ee6279c4891128e49d6445b24aa13c2d1a21450" + dependencies: + eslint-restricted-globals "^0.1.1" + object.assign "^4.1.0" + object.entries "^1.0.4" + +eslint-config-airbnb@^17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.0.0.tgz#1bb8c4255483320bb68c3b614f71ae6058b0b2db" + dependencies: + eslint-config-airbnb-base "^13.0.0" + object.assign "^4.1.0" + object.entries "^1.0.4" + +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-module-utils@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-flowtype@^2.50.0: + version "2.50.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.0.tgz#953e262fa9b5d0fa76e178604892cf60dfb916da" + dependencies: + lodash "^4.17.10" + +eslint-plugin-import@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz#df24f241175e312d91662dc91ca84064caec14ed" + dependencies: + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.2.0" + has "^1.0.1" + lodash "^4.17.4" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + resolve "^1.6.0" + +eslint-plugin-jest@^21.18.0: + version "21.18.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.18.0.tgz#d7305969a9c1902f895468791d968fcf08b5c0b7" + +eslint-plugin-jsx-a11y@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz#7bf56dbe7d47d811d14dbb3ddff644aa656ce8e1" + dependencies: + aria-query "^3.0.0" + array-includes "^3.0.3" + ast-types-flow "^0.0.7" + axobject-query "^2.0.1" + damerau-levenshtein "^1.0.4" + emoji-regex "^6.5.1" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + +eslint-plugin-react@^7.10.0: + version "7.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.10.0.tgz#af5c1fef31c4704db02098f9be18202993828b50" + dependencies: + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.2" + +eslint-restricted-globals@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" + +eslint-scope@3.7.1, eslint-scope@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +espree@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + dependencies: + acorn "^5.5.0" + acorn-jsx "^3.0.0" + esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + esprima@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" +esquery@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + dependencies: + estraverse "^4.0.0" + esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -2730,7 +3088,7 @@ extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^2.1.0: +external-editor@^2.0.4, external-editor@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: @@ -2780,7 +3138,7 @@ fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" -fast-levenshtein@^2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -2825,6 +3183,13 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + file-loader@1.1.11: version "1.1.11" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.11.tgz#6fe886449b0f2a936e43cabaac0cdbfb369506f8" @@ -2894,6 +3259,15 @@ first-chunk-stream@^2.0.0: dependencies: readable-stream "^2.0.2" +flat-cache@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" @@ -3020,10 +3394,14 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2, function-bind@^1.1.1: +function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -3139,10 +3517,25 @@ global@^4.3.0: min-document "^2.19.0" process "~0.5.1" +globals@^11.0.1, globals@^11.1.0: + version "11.7.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -3315,6 +3708,12 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + hash-base@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" @@ -3537,6 +3936,10 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" +ignore@^3.3.3: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + ignore@^3.3.5: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" @@ -3593,6 +3996,25 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + inquirer@^5.1.0, inquirer@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" @@ -3634,6 +4056,12 @@ invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2: dependencies: loose-envify "^1.0.0" +invariant@^2.2.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -3860,6 +4288,10 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" @@ -3960,6 +4392,13 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +js-yaml@^3.9.1: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@~3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" @@ -4015,6 +4454,10 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -4035,6 +4478,10 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" @@ -4066,6 +4513,12 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" + keccak@^1.0.2: version "1.4.0" resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" @@ -4136,6 +4589,13 @@ less@^3.0.1: request "2.81.0" source-map "^0.5.3" +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + listr-silent-renderer@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" @@ -4194,6 +4654,15 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -4267,7 +4736,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0: +lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -4554,7 +5023,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -4677,6 +5146,10 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + needle@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" @@ -4906,6 +5379,15 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.entries@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -4962,6 +5444,17 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + ora@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" @@ -5162,7 +5655,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -5192,6 +5685,12 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -5234,12 +5733,22 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" dependencies: find-up "^2.1.0" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" @@ -5498,6 +6007,10 @@ postcss@^6.0.1: source-map "^0.6.1" supports-color "^4.4.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + prepend-http@^1.0.0, prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -5545,6 +6058,10 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -5571,6 +6088,13 @@ prop-types@^15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" +prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + proxy-addr@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" @@ -5911,6 +6435,13 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" @@ -5926,6 +6457,14 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -6096,6 +6635,10 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + regexpu-core@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" @@ -6197,6 +6740,13 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -6214,6 +6764,10 @@ resolve-dir@^1.0.0: expand-tilde "^2.0.0" global-modules "^1.0.0" +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -6232,6 +6786,12 @@ resolve@^1.1.6: dependencies: path-parse "^1.0.5" +resolve@^1.5.0, resolve@^1.6.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + dependencies: + path-parse "^1.0.5" + responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -6296,6 +6856,16 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + rxjs@^5.4.2, rxjs@^5.5.2: version "5.5.10" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.10.tgz#fde02d7a614f6c8683d0d1957827f492e09db045" @@ -6498,6 +7068,12 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -6589,7 +7165,7 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" -source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6: +source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -6857,6 +7433,17 @@ symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" @@ -6901,7 +7488,7 @@ temp@^0.8.1: os-tmpdir "^1.0.0" rimraf "~2.2.6" -text-table@^0.2.0: +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6948,6 +7535,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -7006,6 +7597,12 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" @@ -7490,6 +8087,10 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2" +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + worker-farm@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" @@ -7515,6 +8116,12 @@ write-file-atomic@^1.2.0: imurmurhash "^0.1.4" slide "^1.1.5" +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + xhr2@*: version "0.1.4" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" From e2c014f59598bf3bdfcedec0c3a59220f8dd433d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Volek?= Date: Mon, 30 Jul 2018 12:47:37 +0200 Subject: [PATCH 02/10] Fixed deps --- package.json | 10 +- webpack/config.dev.babel.js | 24 +-- webpack/config.prod.babel.js | 40 ++-- webpack/constants.js | 3 +- yarn.lock | 397 ++++++++++++++++++++--------------- 5 files changed, 271 insertions(+), 203 deletions(-) diff --git a/package.json b/package.json index e9656541..205ff8b6 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,13 @@ }, "dependencies": { "color-hash": "^1.0.3", + "copy-webpack-plugin": "^4.5.2", "ethereumjs-tx": "^1.3.3", "ethereumjs-units": "^0.2.0", "ethereumjs-util": "^5.1.4", "hdkey": "^0.8.0", + "html-webpack-plugin": "^3.2.0", + "mini-css-extract-plugin": "^0.4.1", "raf": "^3.4.0", "raven-js": "^3.22.3", "rc-tooltip": "^3.7.0", @@ -46,7 +49,8 @@ "redux-raven-middleware": "^1.2.0", "redux-thunk": "^2.2.0", "trezor-connect": "5.0.13", - "web3": "^0.19.0" + "web3": "^0.19.0", + "webpack": "^4.16.3" }, "devDependencies": { "babel-cli": "^6.24.1", @@ -59,7 +63,6 @@ "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.6.0", "babel-preset-react": "^6.24.1", - "copy-webpack-plugin": "4.5.1", "css-loader": "0.28.11", "eslint": "^4", "eslint-config-airbnb": "^17.0.0", @@ -70,11 +73,8 @@ "eslint-plugin-react": "^7.10.0", "file-loader": "1.1.11", "flow-bin": "0.72.0", - "html-webpack-plugin": "^3.2.0", "less": "^3.0.1", "less-loader": "4.1.0", - "mini-css-extract-plugin": "^0.4.0", - "webpack": "^4.8.3", "webpack-cli": "^2.1.3", "webpack-dev-server": "^3.1.4", "whatwg-fetch": "^2.0.3", diff --git a/webpack/config.dev.babel.js b/webpack/config.dev.babel.js index eb0fc488..6a79af31 100644 --- a/webpack/config.dev.babel.js +++ b/webpack/config.dev.babel.js @@ -1,15 +1,15 @@ -import { SRC, BUILD, PORT } from './constants'; import webpack from 'webpack'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import { SRC, BUILD, PORT } from './constants'; module.exports = { watch: true, mode: 'development', devtool: 'inline-source-map', entry: { - 'index': [ 'react-hot-loader/patch', `${SRC}js/index.js` ] + index: ['react-hot-loader/patch', `${SRC}js/index.js`], }, output: { filename: '[name].[hash].js', @@ -28,18 +28,18 @@ module.exports = { { test: /\.jsx?$/, exclude: /node_modules/, - use: ['babel-loader'] + use: ['babel-loader'], }, { test: /\.less$/, use: [ { loader: MiniCssExtractPlugin.loader, - options: { publicPath: '../' } + options: { publicPath: '../' }, }, 'css-loader', 'less-loader', - ] + ], }, { test: /\.(png|gif|jpg)$/, @@ -47,7 +47,7 @@ module.exports = { query: { outputPath: './images', name: '[name].[ext]', - } + }, }, { test: /\.(ttf|eot|svg|woff|woff2)$/, @@ -67,30 +67,30 @@ module.exports = { name: '[name].[ext]', }, }, - ] + ], }, resolve: { modules: [SRC, 'node_modules'], }, performance: { - hints: false + hints: false, }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', chunkFilename: '[id].css', }), - + new HtmlWebpackPlugin({ chunks: ['index'], template: `${SRC}index.html`, filename: 'index.html', - inject: true + inject: true, }), new webpack.optimize.OccurrenceOrderPlugin(), new webpack.NoEmitOnErrorsPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), - ] -} + ], +}; diff --git a/webpack/config.prod.babel.js b/webpack/config.prod.babel.js index 1cec8f5b..acac03dc 100644 --- a/webpack/config.prod.babel.js +++ b/webpack/config.prod.babel.js @@ -1,14 +1,14 @@ -import { SRC, BUILD, PORT } from './constants'; import webpack from 'webpack'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import { SRC, BUILD } from './constants'; module.exports = { mode: 'production', entry: { - 'index': [ `${SRC}js/index.js` ] + index: [`${SRC}js/index.js`], }, output: { filename: 'js/[name].[hash].js', @@ -20,28 +20,28 @@ module.exports = { { test: /\.jsx?$/, exclude: /node_modules/, - use: ['babel-loader'] + use: ['babel-loader'], }, { test: /\.less$/, use: [ { loader: MiniCssExtractPlugin.loader, - options: { publicPath: '../' } + options: { publicPath: '../' }, }, - { + { loader: 'css-loader', - options: { + options: { minimize: false, - } + }, }, - { + { loader: 'less-loader', - options: { + options: { minimize: false, - } - } - ] + }, + }, + ], }, { test: /\.(png|gif|jpg)$/, @@ -49,8 +49,8 @@ module.exports = { loader: 'file-loader', query: { outputPath: './images', - name: '[name].[hash].[ext]' - } + name: '[name].[hash].[ext]', + }, }, { test: /\.(ttf|eot|svg|woff|woff2)$/, @@ -70,24 +70,24 @@ module.exports = { name: '[name].[hash].[ext]', }, }, - ] + ], }, resolve: { modules: [SRC, 'node_modules'], }, performance: { - hints: false + hints: false, }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name].[hash].css', }), - + new HtmlWebpackPlugin({ chunks: ['index'], template: `${SRC}index.html`, filename: 'index.html', - inject: true + inject: true, }), new CopyWebpackPlugin([ @@ -101,5 +101,5 @@ module.exports = { new webpack.optimize.OccurrenceOrderPlugin(), new webpack.NoEmitOnErrorsPlugin(), new webpack.NamedModulesPlugin(), - ] -} + ], +}; diff --git a/webpack/constants.js b/webpack/constants.js index 1d2526ec..8717349e 100644 --- a/webpack/constants.js +++ b/webpack/constants.js @@ -1,5 +1,4 @@ /* @flow */ -'use strict'; import path from 'path'; @@ -10,7 +9,7 @@ const constants: Object = Object.freeze({ SRC: path.join(ABSOLUTE_BASE, 'src/'), PORT: 8081, INDEX: path.join(ABSOLUTE_BASE, 'src/index.html'), - TREZOR_CONNECT_ROOT: path.join(ABSOLUTE_BASE, '../trezor.js2/') + TREZOR_CONNECT_ROOT: path.join(ABSOLUTE_BASE, '../trezor.js2/'), }); export const BUILD: string = constants.BUILD; diff --git a/yarn.lock b/yarn.lock index c94b6d3b..6b8a24b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,121 +93,152 @@ version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" -"@webassemblyjs/ast@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.4.3.tgz#3b3f6fced944d8660273347533e6d4d315b5934a" +"@webassemblyjs/ast@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25" dependencies: - "@webassemblyjs/helper-wasm-bytecode" "1.4.3" - "@webassemblyjs/wast-parser" "1.4.3" + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" debug "^3.1.0" - webassemblyjs "1.4.3" + mamacro "^0.0.3" -"@webassemblyjs/floating-point-hex-parser@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.4.3.tgz#f5aee4c376a717c74264d7bacada981e7e44faad" +"@webassemblyjs/floating-point-hex-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz#29ce0baa97411f70e8cce68ce9c0f9d819a4e298" -"@webassemblyjs/helper-buffer@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.4.3.tgz#0434b55958519bf503697d3824857b1dea80b729" +"@webassemblyjs/helper-api-error@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz#e49b051d67ee19a56e29b9aa8bd949b5b4442a59" + +"@webassemblyjs/helper-buffer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz#873bb0a1b46449231137c1262ddfd05695195a1e" dependencies: debug "^3.1.0" -"@webassemblyjs/helper-code-frame@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.4.3.tgz#f1349ca3e01a8e29ee2098c770773ef97af43641" +"@webassemblyjs/helper-code-frame@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz#1bd2181b6a0be14e004f0fe9f5a660d265362b58" dependencies: - "@webassemblyjs/wast-printer" "1.4.3" + "@webassemblyjs/wast-printer" "1.5.13" + +"@webassemblyjs/helper-fsm@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz#cdf3d9d33005d543a5c5e5adaabf679ffa8db924" -"@webassemblyjs/helper-fsm@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.4.3.tgz#65a921db48fb43e868f17b27497870bdcae22b79" +"@webassemblyjs/helper-module-context@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz#dc29ddfb51ed657655286f94a5d72d8a489147c5" + dependencies: + debug "^3.1.0" + mamacro "^0.0.3" -"@webassemblyjs/helper-wasm-bytecode@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.4.3.tgz#0e5b4b5418e33f8a26e940b7809862828c3721a5" +"@webassemblyjs/helper-wasm-bytecode@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz#03245817f0a762382e61733146f5773def15a747" -"@webassemblyjs/helper-wasm-section@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.4.3.tgz#9ceedd53a3f152c3412e072887ade668d0b1acbf" +"@webassemblyjs/helper-wasm-section@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz#efc76f44a10d3073b584b43c38a179df173d5c7d" dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/helper-buffer" "1.4.3" - "@webassemblyjs/helper-wasm-bytecode" "1.4.3" - "@webassemblyjs/wasm-gen" "1.4.3" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" debug "^3.1.0" -"@webassemblyjs/leb128@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.4.3.tgz#5a5e5949dbb5adfe3ae95664d0439927ac557fb8" +"@webassemblyjs/ieee754@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz#573e97c8c12e4eebb316ca5fde0203ddd90b0364" dependencies: - leb "^0.3.0" + ieee754 "^1.1.11" -"@webassemblyjs/validation@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/validation/-/validation-1.4.3.tgz#9e66c9b3079d7bbcf2070c1bf52a54af2a09aac9" +"@webassemblyjs/leb128@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.13.tgz#ab52ebab9cec283c1c1897ac1da833a04a3f4cee" dependencies: - "@webassemblyjs/ast" "1.4.3" + long "4.0.0" + +"@webassemblyjs/utf8@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.13.tgz#6b53d2cd861cf94fa99c1f12779dde692fbc2469" -"@webassemblyjs/wasm-edit@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.4.3.tgz#87febd565e0ffb5ae25f6495bb3958d17aa0a779" +"@webassemblyjs/wasm-edit@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz#c9cef5664c245cf11b3b3a73110c9155831724a8" dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/helper-buffer" "1.4.3" - "@webassemblyjs/helper-wasm-bytecode" "1.4.3" - "@webassemblyjs/helper-wasm-section" "1.4.3" - "@webassemblyjs/wasm-gen" "1.4.3" - "@webassemblyjs/wasm-opt" "1.4.3" - "@webassemblyjs/wasm-parser" "1.4.3" - "@webassemblyjs/wast-printer" "1.4.3" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/helper-wasm-section" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + "@webassemblyjs/wast-printer" "1.5.13" debug "^3.1.0" -"@webassemblyjs/wasm-gen@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.4.3.tgz#8553164d0154a6be8f74d653d7ab355f73240aa4" +"@webassemblyjs/wasm-gen@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz#8e6ea113c4b432fa66540189e79b16d7a140700e" dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/helper-wasm-bytecode" "1.4.3" - "@webassemblyjs/leb128" "1.4.3" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" -"@webassemblyjs/wasm-opt@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.4.3.tgz#26c7a23bfb136aa405b1d3410e63408ec60894b8" +"@webassemblyjs/wasm-opt@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz#147aad7717a7ee4211c36b21a5f4c30dddf33138" dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/helper-buffer" "1.4.3" - "@webassemblyjs/wasm-gen" "1.4.3" - "@webassemblyjs/wasm-parser" "1.4.3" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" debug "^3.1.0" -"@webassemblyjs/wasm-parser@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.4.3.tgz#7ddd3e408f8542647ed612019cfb780830993698" - dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/helper-wasm-bytecode" "1.4.3" - "@webassemblyjs/leb128" "1.4.3" - "@webassemblyjs/wasm-parser" "1.4.3" - webassemblyjs "1.4.3" +"@webassemblyjs/wasm-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz#6f46516c5bb23904fbdf58009233c2dd8a54c72f" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" + +"@webassemblyjs/wast-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz#5727a705d397ae6a3ae99d7f5460acf2ec646eea" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/floating-point-hex-parser" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-code-frame" "1.5.13" + "@webassemblyjs/helper-fsm" "1.5.13" + long "^3.2.0" + mamacro "^0.0.3" -"@webassemblyjs/wast-parser@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.4.3.tgz#3250402e2c5ed53dbe2233c9de1fe1f9f0d51745" +"@webassemblyjs/wast-printer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz#bb34d528c14b4f579e7ec11e793ec50ad7cd7c95" dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/floating-point-hex-parser" "1.4.3" - "@webassemblyjs/helper-code-frame" "1.4.3" - "@webassemblyjs/helper-fsm" "1.4.3" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" long "^3.2.0" - webassemblyjs "1.4.3" -"@webassemblyjs/wast-printer@1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.4.3.tgz#3d59aa8d0252d6814a3ef4e6d2a34c9ded3904e0" +"@webpack-contrib/schema-utils@^1.0.0-beta.0": + version "1.0.0-beta.0" + resolved "https://registry.yarnpkg.com/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz#bf9638c9464d177b48209e84209e23bee2eb4f65" dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/wast-parser" "1.4.3" - long "^3.2.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chalk "^2.3.2" + strip-ansi "^4.0.0" + text-table "^0.2.0" + webpack-log "^1.1.2" abbrev@1: version "1.1.1" @@ -243,11 +274,7 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.0.0: - version "5.5.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" - -acorn@^5.5.0: +acorn@^5.0.0, acorn@^5.5.0, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -1461,12 +1488,13 @@ browserify-cipher@^1.0.0: evp_bytestokey "^1.0.0" browserify-des@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.1.tgz#3343124db6d7ad53e26a8826318712bdc8450f9c" + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" dependencies: cipher-base "^1.0.1" des.js "^1.0.0" inherits "^2.0.1" + safe-buffer "^5.1.2" browserify-rsa@^4.0.0: version "4.0.1" @@ -1709,7 +1737,7 @@ chokidar@^1.6.1: optionalDependencies: fsevents "^1.0.0" -chokidar@^2.0.0, chokidar@^2.0.2: +chokidar@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" dependencies: @@ -1727,13 +1755,34 @@ chokidar@^2.0.0, chokidar@^2.0.2: optionalDependencies: fsevents "^1.1.2" +chokidar@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" -chrome-trace-event@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.3.tgz#d395af2d31c87b90a716c831fe326f69768ec084" +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + dependencies: + tslib "^1.9.0" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -1932,9 +1981,9 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@2.15.x, commander@~2.15.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" +commander@2.16.x, commander@~2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" commander@^2.11.0: version "2.12.1" @@ -2058,9 +2107,9 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" -copy-webpack-plugin@4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.1.tgz#fc4f68f4add837cc5e13d111b20715793225d29c" +copy-webpack-plugin@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.2.tgz#d53444a8fea2912d806e78937390ddd7e632ee5c" dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -2650,6 +2699,14 @@ enhanced-resolve@^4.0.0: memory-fs "^0.4.0" tapable "^1.0.0" +enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" @@ -2683,9 +2740,9 @@ error@^7.0.2: string-template "~0.2.1" xtend "~4.0.0" -es-abstract@^1.5.1, es-abstract@^1.7.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" +es-abstract@^1.5.1, es-abstract@^1.6.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2693,9 +2750,9 @@ es-abstract@^1.5.1, es-abstract@^1.7.0: is-callable "^1.1.3" is-regex "^1.0.4" -es-abstract@^1.6.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" +es-abstract@^1.7.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2830,6 +2887,13 @@ eslint-scope@3.7.1, eslint-scope@^3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" @@ -3370,7 +3434,7 @@ fsevents@^1.0.0: nan "^2.3.0" node-pre-gyp "^0.6.39" -fsevents@^1.1.2: +fsevents@^1.1.2, fsevents@^1.2.2: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: @@ -3820,16 +3884,16 @@ html-entities@^1.2.0: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" html-minifier@^3.2.3: - version "3.5.15" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.15.tgz#f869848d4543cbfd84f26d5514a2a87cbf9a05e0" + version "3.5.19" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.19.tgz#ed53c4b7326fe507bc3a1adbcc3bbb56660a2ebd" dependencies: camel-case "3.0.x" clean-css "4.1.x" - commander "2.15.x" + commander "2.16.x" he "1.1.x" param-case "2.1.x" relateurl "0.2.x" - uglify-js "3.3.x" + uglify-js "3.4.x" html-webpack-plugin@^3.2.0: version "3.2.0" @@ -3922,9 +3986,9 @@ icss-utils@^2.1.0: dependencies: postcss "^6.0.1" -ieee754@^1.1.4: - version "1.1.11" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" +ieee754@^1.1.11, ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" iferr@^0.1.5: version "0.1.5" @@ -4466,7 +4530,7 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" -json-parse-better-errors@^1.0.1: +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -4564,10 +4628,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -leb@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/leb/-/leb-0.3.0.tgz#32bee9fad168328d6aea8522d833f4180eed1da3" - less-loader@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e" @@ -4712,6 +4772,10 @@ lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -4774,6 +4838,10 @@ loglevelnext@^1.0.1: es6-symbol "^3.1.1" object.assign "^4.1.0" +long@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + long@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" @@ -4826,6 +4894,10 @@ make-dir@^1.1.0: dependencies: pify "^3.0.0" +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -5008,10 +5080,11 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -mini-css-extract-plugin@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.0.tgz#ff3bf08bee96e618e177c16ca6131bfecef707f9" +mini-css-extract-plugin@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.1.tgz#d2bcf77bb2596b8e4bd9257e43d3f9164c2e86cb" dependencies: + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" loader-utils "^1.1.0" webpack-sources "^1.1.0" @@ -5532,8 +5605,8 @@ p-lazy@^1.0.0: resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" p-limit@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" dependencies: p-try "^1.0.0" @@ -7266,8 +7339,8 @@ stream-each@^1.1.0: stream-shift "^1.0.0" stream-http@^2.7.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.2.tgz#4126e8c6b107004465918aa2fc35549e77402c87" + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" @@ -7583,6 +7656,10 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -7632,16 +7709,16 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" -uglify-js@3.3.x: - version "3.3.25" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.25.tgz#3266ccb87c5bea229f69041a0296010d6477d539" +uglify-js@3.4.x: + version "3.4.6" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.6.tgz#bc546d53f3e02b05d97d0ca5a7abfe0fb0384ddb" dependencies: - commander "~2.15.0" + commander "~2.16.0" source-map "~0.6.1" uglifyjs-webpack-plugin@^1.2.4: - version "1.2.5" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz#2ef8387c8f1a903ec5e44fa36f9f3cbdcea67641" + version "1.2.7" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.7.tgz#57638dd99c853a1ebfe9d97b42160a8a507f9d00" dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -7710,7 +7787,7 @@ untildify@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" -upath@^1.0.0: +upath@^1.0.0, upath@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" @@ -7781,12 +7858,18 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util@0.10.3, util@^0.10.3: +util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: inherits "2.0.1" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + utila@~0.3: version "0.3.3" resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" @@ -7910,16 +7993,6 @@ web3@^0.19.0: xhr2 "*" xmlhttprequest "*" -webassemblyjs@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webassemblyjs/-/webassemblyjs-1.4.3.tgz#0591893efb8fbde74498251cbe4b2d83df9239cb" - dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/validation" "1.4.3" - "@webassemblyjs/wasm-parser" "1.4.3" - "@webassemblyjs/wast-parser" "1.4.3" - long "^3.2.0" - webpack-addons@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/webpack-addons/-/webpack-addons-1.1.5.tgz#2b178dfe873fb6e75e40a819fa5c26e4a9bc837a" @@ -8011,34 +8084,30 @@ webpack-log@^1.0.1, webpack-log@^1.1.2: loglevelnext "^1.0.1" uuid "^3.1.0" -webpack-sources@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.2.tgz#d0148ec083b3b5ccef1035a6b3ec16442983b27a" - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack-sources@^1.1.0: +webpack-sources@^1.0.1, webpack-sources@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.8.3.tgz#957c8e80000f9e5cc03d775e78b472d8954f4eeb" - dependencies: - "@webassemblyjs/ast" "1.4.3" - "@webassemblyjs/wasm-edit" "1.4.3" - "@webassemblyjs/wasm-parser" "1.4.3" - acorn "^5.0.0" +webpack@^4.16.3: + version "4.16.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.3.tgz#861be3176d81e7e3d71c66c8acc9bba35588b525" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/wasm-edit" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + acorn "^5.6.2" acorn-dynamic-import "^3.0.0" ajv "^6.1.0" ajv-keywords "^3.1.0" - chrome-trace-event "^0.1.1" - enhanced-resolve "^4.0.0" - eslint-scope "^3.7.1" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" loader-runner "^2.3.0" loader-utils "^1.1.0" memory-fs "~0.4.1" From 7627aade89d0e08e4329c3a7ead1c944d4cd21d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Volek?= Date: Mon, 30 Jul 2018 12:52:13 +0200 Subject: [PATCH 03/10] Fixed some eslint problems --- .eslintignore | 1 + package.json | 2 +- src/babel/babel-plugin-import.js | 22 +- src/flowtype/css.js | 2 +- src/flowtype/index.js | 16 +- src/flowtype/npm/bignumber.js | 10 +- src/flowtype/npm/ethereum-types.js | 23 +- src/flowtype/npm/react-redux_v5.x.x.js | 16 +- src/flowtype/npm/react-router-dom_v4.x.x.js | 44 +- src/flowtype/npm/react-router-redux.js | 13 +- src/flowtype/npm/react-router_v4.x.x.js | 34 +- src/flowtype/npm/redux_v3.x.x.js | 3 +- src/flowtype/npm/web3.js | 8 +- src/js/actions/AccountsActions.js | 37 +- src/js/actions/DiscoveryActions.js | 513 ++++---- src/js/actions/HistoryActions.js | 1 - src/js/actions/LocalStorageActions.js | 122 +- src/js/actions/LogActions.js | 49 +- src/js/actions/ModalActions.js | 166 ++- src/js/actions/NotificationActions.js | 50 +- src/js/actions/PendingTxActions.js | 4 +- src/js/actions/ReceiveActions.js | 138 +-- src/js/actions/SelectedAccountActions.js | 173 ++- src/js/actions/SendFormActions.js | 1062 ++++++++--------- src/js/actions/SessionStorageActions.js | 53 +- src/js/actions/SummaryActions.js | 44 +- src/js/actions/TokenActions.js | 149 ++- src/js/actions/TrezorConnectActions.js | 491 ++++---- src/js/actions/WalletActions.js | 128 +- src/js/actions/Web3Actions.js | 329 +++-- src/js/actions/constants/TrezorConnect.js | 2 +- src/js/actions/constants/account.js | 2 +- src/js/actions/constants/discovery.js | 2 +- src/js/actions/constants/localStorage.js | 2 +- src/js/actions/constants/log.js | 2 +- src/js/actions/constants/modal.js | 2 +- src/js/actions/constants/notification.js | 2 +- src/js/actions/constants/pendingTx.js | 2 +- src/js/actions/constants/receive.js | 2 +- src/js/actions/constants/send.js | 2 +- src/js/actions/constants/summary.js | 2 +- src/js/actions/constants/token.js | 2 +- src/js/actions/constants/wallet.js | 2 +- src/js/actions/constants/web3.js | 2 +- src/js/components/common/Footer.js | 38 +- src/js/components/common/Header.js | 44 +- src/js/components/common/LoaderCircle.js | 15 +- src/js/components/common/Log.js | 33 +- src/js/components/common/Notification.js | 72 +- src/js/components/landing/ConnectDevice.js | 82 +- src/js/components/landing/InstallBridge.js | 28 +- src/js/components/landing/LandingPage.js | 61 +- .../components/landing/LocalStorageError.js | 12 +- src/js/components/landing/Preloader.js | 14 +- .../components/landing/TrezorConnectError.js | 12 +- src/js/components/landing/index.js | 34 +- src/js/components/modal/ConfirmAddress.js | 33 +- src/js/components/modal/ConfirmSignTx.js | 9 +- src/js/components/modal/DuplicateDevice.js | 45 +- src/js/components/modal/InvalidPin.js | 6 +- src/js/components/modal/Passphrase.js | 98 +- src/js/components/modal/PassphraseType.js | 5 +- src/js/components/modal/Pin.js | 79 +- src/js/components/modal/RememberDevice.js | 28 +- src/js/components/modal/index.js | 112 +- .../components/wallet/account/AccountTabs.js | 27 +- .../wallet/account/SelectedAccount.js | 95 +- .../wallet/account/receive/Receive.js | 50 +- .../wallet/account/receive/index.js | 32 +- .../wallet/account/send/AdvancedForm.js | 101 +- .../wallet/account/send/CoinSelectOption.js | 16 +- .../wallet/account/send/FeeSelect.js | 32 +- .../account/send/PendingTransactions.js | 32 +- .../wallet/account/send/SendForm.js | 108 +- .../components/wallet/account/send/index.js | 34 +- .../wallet/account/sign/SignVerify.js | 48 +- .../wallet/account/summary/Summary.js | 110 +- .../wallet/account/summary/SummaryDetails.js | 24 +- .../wallet/account/summary/SummaryTokens.js | 23 +- .../wallet/account/summary/index.js | 46 +- .../wallet/aside/AccountSelection.js | 53 +- src/js/components/wallet/aside/Aside.js | 56 +- .../components/wallet/aside/CoinSelection.js | 16 +- .../wallet/aside/DeviceSelection.js | 107 +- .../wallet/aside/StickyContainer.js | 65 +- src/js/components/wallet/aside/index.js | 54 +- src/js/components/wallet/index.js | 66 +- src/js/components/wallet/pages/Acquire.js | 36 +- src/js/components/wallet/pages/Bootloader.js | 20 +- src/js/components/wallet/pages/Dashboard.js | 24 +- .../components/wallet/pages/DeviceSettings.js | 22 +- .../wallet/pages/DeviceSettingsTabs.js | 5 +- src/js/components/wallet/pages/Initialize.js | 22 +- .../components/wallet/pages/WalletSettings.js | 12 +- src/js/index.js | 6 +- src/js/reducers/AccountsReducer.js | 63 +- src/js/reducers/DevicesReducer.js | 141 +-- src/js/reducers/DiscoveryReducer.js | 91 +- src/js/reducers/FiatRateReducer.js | 17 +- src/js/reducers/LocalStorageReducer.js | 31 +- src/js/reducers/LogReducer.js | 25 +- src/js/reducers/ModalReducer.js | 63 +- src/js/reducers/NotificationReducer.js | 24 +- src/js/reducers/PendingTxReducer.js | 35 +- src/js/reducers/ReceiveReducer.js | 31 +- src/js/reducers/SelectedAccountReducer.js | 17 +- src/js/reducers/SendFormReducer.js | 78 +- src/js/reducers/SummaryReducer.js | 23 +- src/js/reducers/TokensReducer.js | 49 +- src/js/reducers/TrezorConnectReducer.js | 42 +- src/js/reducers/WalletReducer.js | 57 +- src/js/reducers/Web3Reducer.js | 29 +- src/js/reducers/index.js | 6 +- src/js/reducers/utils/index.js | 82 +- src/js/router/index.js | 36 +- src/js/services/CoinmarketcapService.js | 54 +- src/js/services/LocalStorageService.js | 98 +- src/js/services/LogService.js | 15 +- src/js/services/RouterService.js | 49 +- src/js/services/TrezorConnectService.js | 46 +- src/js/services/WalletService.js | 23 +- src/js/services/index.js | 2 +- src/js/store/index.js | 25 +- src/js/utils/ethUtils.js | 26 +- src/js/utils/formatUtils.js | 38 +- src/js/utils/networkUtils.js | 14 +- src/js/utils/promiseUtils.js | 2 +- src/js/utils/windowUtils.js | 13 +- 128 files changed, 3398 insertions(+), 3880 deletions(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..813e13d4 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +solidity \ No newline at end of file diff --git a/package.json b/package.json index 205ff8b6..cd393092 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build": "rm -rf build && webpack --config ./webpack/config.prod.babel.js --progress", "flow": "flow check src/js", "test": "", - "lint": "npx eslint ./" + "lint": "npx eslint ./ --fix" }, "dependencies": { "color-hash": "^1.0.3", diff --git a/src/babel/babel-plugin-import.js b/src/babel/babel-plugin-import.js index 8e2c839c..adaefac9 100644 --- a/src/babel/babel-plugin-import.js +++ b/src/babel/babel-plugin-import.js @@ -8,27 +8,27 @@ const replacePrefix = (path, opts = [], sourceFile) => { const options = [].concat(opts); if (typeof path === 'string') { if (path.indexOf('~/') === 0) { - return path.replace('~/', `${ cwd }/src/`); + return path.replace('~/', `${cwd}/src/`); } } return path; -} +}; -export default ({ 'types': t }) => { +export default ({ types: t }) => { const visitor = { CallExpression(path, state) { if (path.node.callee.name !== 'require') { return; } - + const args = path.node.arguments; if (!args.length) { return; } - + const firstArg = traverseExpression(t, args[0]); - + if (firstArg) { firstArg.value = replacePrefix(firstArg.value, state.opts, state.file.opts.filename); } @@ -45,14 +45,14 @@ export default ({ 'types': t }) => { if (path.node.source) { path.node.source.value = replacePrefix(path.node.source.value, state.opts, state.file.opts.filename); } - } + }, }; return { - 'visitor': { + visitor: { Program(path, state) { path.traverse(visitor, state); - } - } + }, + }, }; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/flowtype/css.js b/src/flowtype/css.js index 624e2f4a..b06105e3 100644 --- a/src/flowtype/css.js +++ b/src/flowtype/css.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + declare module CSSModule { declare var exports: { [key: string]: string }; diff --git a/src/flowtype/index.js b/src/flowtype/index.js index 5f89d8af..a66b4135 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import type { Store as ReduxStore, @@ -9,7 +9,7 @@ import type { ThunkAction as ReduxThunkAction, AsyncAction as ReduxAsyncAction, ThunkDispatch as ReduxThunkDispatch, - PlainDispatch as ReduxPlainDispatch + PlainDispatch as ReduxPlainDispatch, } from 'redux'; import type { Reducers, ReducersState } from '~/js/reducers'; @@ -43,7 +43,7 @@ import type { import type { RouterAction, LocationState } from 'react-router-redux'; export type TrezorDevice = { - remember: boolean; // device should be remembered + remember: boolean; // device should be remembered connected: boolean; // device is connected available: boolean; // device cannot be used because of features.passphrase_protection is different then expected path: string; @@ -87,19 +87,19 @@ type IFrameHandshake = { payload: any } -export type Action = +export type Action = RouterAction | IFrameHandshake | TransportEventAction | DeviceEventAction | UiEventAction - + | SelectedAccountAction | AccountAction | DiscoveryAction - | StorageAction - | LogAction - | ModalAction + | StorageAction + | LogAction + | ModalAction | NotificationAction | PendingTxAction | ReceiveAction diff --git a/src/flowtype/npm/bignumber.js b/src/flowtype/npm/bignumber.js index 488831aa..5fa3a6fe 100644 --- a/src/flowtype/npm/bignumber.js +++ b/src/flowtype/npm/bignumber.js @@ -7,22 +7,22 @@ declare module 'bignumber.js' { declare type ROUND_HALF_EVEN = 2 declare type ROUND_UP = 3 declare type RM = ROUND_DOWN | ROUND_HALF_UP | ROUND_HALF_EVEN | ROUND_UP - + declare class T_BigNumber { // Properties static DP: number; static RM: RM; static E_NEG: number; static E_POS: number; - + c: Array; e: number; s: -1 | 1; - + // Constructors static (value: $npm$big$number$object): T_BigNumber; constructor(value: $npm$big$number$object): T_BigNumber; - + // Methods abs(): BigNumber; cmp(n: $npm$big$number$object): $npm$cmp$result; @@ -51,7 +51,7 @@ declare module 'bignumber.js' { valueOf(): string; toJSON(): string; } - + //declare module.exports: typeof T_BigNumber declare export default typeof T_BigNumber; } \ No newline at end of file diff --git a/src/flowtype/npm/ethereum-types.js b/src/flowtype/npm/ethereum-types.js index fa0a0aeb..4bdd96f5 100644 --- a/src/flowtype/npm/ethereum-types.js +++ b/src/flowtype/npm/ethereum-types.js @@ -16,16 +16,16 @@ declare module 'ethereum-types' { | 'mether' | 'gether' | 'tether' - + declare export type EthereumAddressT = string declare export type EthereumBlockNumberT = number declare export type EthereumBlockHashT = string declare export type EthereumTransactionHashT = string // end data types - + // start contract types declare export type EthereumWatchErrorT = ?Object - + declare export type EthereumEventT = { address: EthereumAddressT, args: A, @@ -38,35 +38,32 @@ declare module 'ethereum-types' { transactionLogIndex: string, type: 'mined' // TODO: what other types are there? } - + // this represents the setup object returned from truffle-contract // we use it to get a known contact `at(address)` (ie. for POATokenContract addresses) declare export type EthereumContractSetupT = { at: EthereumAddressT => Promise } - + declare export type EthereumSendTransactionOptionsT = { from: EthereumAddressT, gas: number, value?: number } - - declare export type EthereumSendTransactionT = EthereumSendTransactionOptionsT => Promise< - EthereumTransactionHashT - > - + + declare export type EthereumSendTransactionT = EthereumSendTransactionOptionsT => Promise + // TODO(mattgstevens): it would be nice to have an Generic type for a Contract instance // similar to the EthererumWatchEventT // // declare export type SendTransactionContractT = interface .sendTransaction(EthereumAddressT) // declare export type WatchableContractT = (error: Object, response: A) - + // declare export type EthereumContractWatcherT = (options: { // fromBlock?: EthereumBlockNumberT, // toBlock?: EthereumBlockNumberT, // address?: EthereumAddressT // }) => * - + // end contract data } - \ No newline at end of file diff --git a/src/flowtype/npm/react-redux_v5.x.x.js b/src/flowtype/npm/react-redux_v5.x.x.js index b5897b4a..58471492 100644 --- a/src/flowtype/npm/react-redux_v5.x.x.js +++ b/src/flowtype/npm/react-redux_v5.x.x.js @@ -1,9 +1,9 @@ // flow-typed signature: 59b0c4be0e1408f21e2446be96c79804 // flow-typed version: 9092387fd2/react-redux_v5.x.x/flow_>=v0.54.x -import type { Dispatch, Store } from "redux"; +import type { Dispatch, Store } from 'redux'; -declare module "react-redux" { +declare module 'react-redux' { /* S = State @@ -32,9 +32,7 @@ declare module "react-redux" { declare type Context = { store: Store<*, *> }; - declare type ComponentWithDefaultProps = Class< - React$Component - > & { defaultProps: DP }; + declare type ComponentWithDefaultProps = Class> & { defaultProps: DP }; declare class ConnectedComponentWithDefaultProps< OP, @@ -55,13 +53,9 @@ declare module "react-redux" { state: void } - declare type ConnectedComponentWithDefaultPropsClass = Class< - ConnectedComponentWithDefaultProps - >; + declare type ConnectedComponentWithDefaultPropsClass = Class>; - declare type ConnectedComponentClass = Class< - ConnectedComponent - >; + declare type ConnectedComponentClass = Class>; declare type Connector = (( component: ComponentWithDefaultProps diff --git a/src/flowtype/npm/react-router-dom_v4.x.x.js b/src/flowtype/npm/react-router-dom_v4.x.x.js index 304f54d7..8d0b48ba 100644 --- a/src/flowtype/npm/react-router-dom_v4.x.x.js +++ b/src/flowtype/npm/react-router-dom_v4.x.x.js @@ -1,4 +1,4 @@ -declare module "react-router-dom" { +declare module 'react-router-dom' { declare export class BrowserRouter extends React$Component<{ basename?: string, forceRefresh?: boolean, @@ -6,21 +6,21 @@ declare module "react-router-dom" { keyLength?: number, children?: React$Node }> {} - + declare export class HashRouter extends React$Component<{ basename?: string, getUserConfirmation?: GetUserConfirmation, hashType?: "slash" | "noslash" | "hashbang", children?: React$Node }> {} - + declare export class Link extends React$Component<{ className?: string, to: string | LocationShape, replace?: boolean, children?: React$Node }> {} - + declare export class NavLink extends React$Component<{ to: string | LocationShape, activeClassName?: string, @@ -32,7 +32,7 @@ declare module "react-router-dom" { exact?: boolean, strict?: boolean }> {} - + // NOTE: Below are duplicated from react-router. If updating these, please // update the react-router and react-router-native types as well. declare export type Location = { @@ -42,16 +42,16 @@ declare module "react-router-dom" { state?: any, key?: string }; - + declare export type LocationShape = { pathname?: string, search?: string, hash?: string, state?: any }; - + declare export type HistoryAction = "PUSH" | "REPLACE" | "POP"; - + declare export type RouterHistory = { length: number, location: Location, @@ -72,37 +72,37 @@ declare module "react-router-dom" { index?: number, entries?: Array }; - + declare export type Match = { params: { [key: string]: ?string }, isExact: boolean, path: string, url: string }; - + declare export type ContextRouter = {| history: RouterHistory, location: Location, match: Match, staticContext?: StaticRouterContext, |}; - + declare export type GetUserConfirmation = ( message: string, callback: (confirmed: boolean) => void ) => void; - + declare type StaticRouterContext = { url?: string }; - + declare export class StaticRouter extends React$Component<{ basename?: string, location?: string | Location, context: StaticRouterContext, children?: React$Node }> {} - + declare export class MemoryRouter extends React$Component<{ initialEntries?: Array, initialIndex?: number, @@ -110,22 +110,22 @@ declare module "react-router-dom" { keyLength?: number, children?: React$Node }> {} - + declare export class Router extends React$Component<{ history: RouterHistory, children?: React$Node }> {} - + declare export class Prompt extends React$Component<{ message: string | ((location: Location) => string | boolean), when?: boolean }> {} - + declare export class Redirect extends React$Component<{ to: string | LocationShape, push?: boolean }> {} - + declare export class Route extends React$Component<{ component?: React$ComponentType<*>, render?: (router: ContextRouter) => React$Node, @@ -134,22 +134,22 @@ declare module "react-router-dom" { exact?: boolean, strict?: boolean }> {} - + declare export class Switch extends React$Component<{ children?: React$Node }> {} - + declare export function withRouter

( Component: React$ComponentType<{| ...ContextRouter, ...P |}> ): React$ComponentType

; - + declare type MatchPathOptions = { path?: string, exact?: boolean, sensitive?: boolean, strict?: boolean }; - + declare export function matchPath( pathname: string, options?: MatchPathOptions | string diff --git a/src/flowtype/npm/react-router-redux.js b/src/flowtype/npm/react-router-redux.js index b04d0640..81c9a297 100644 --- a/src/flowtype/npm/react-router-redux.js +++ b/src/flowtype/npm/react-router-redux.js @@ -1,12 +1,11 @@ -import type { +import type { RouterHistory, - Location as RouterLocation + Location as RouterLocation, } from 'react-router'; -declare module "react-router-redux" { - +declare module 'react-router-redux' { // custom state for location - declare export type LocationState = {[key: string] : string}; + declare export type LocationState = {[key: string]: string}; declare export type Location = { pathname: string, @@ -16,7 +15,7 @@ declare module "react-router-redux" { state: LocationState } - declare export var LOCATION_CHANGE: "@@router/LOCATION_CHANGE"; + declare export var LOCATION_CHANGE: "@@router/LOCATION_CHANGE"; declare export type RouterAction = { type: typeof LOCATION_CHANGE, @@ -32,7 +31,7 @@ declare module "react-router-redux" { declare export function go(a: string): RouterAction; declare export function goBack(): RouterAction; declare export function goForward(): RouterAction; - + //declare export function routerReducer(state?: S, action: A): S; declare export function routerReducer(state?: State, action: any): State; declare export function routerMiddleware(history: any): any; diff --git a/src/flowtype/npm/react-router_v4.x.x.js b/src/flowtype/npm/react-router_v4.x.x.js index 86489aae..a115b15a 100644 --- a/src/flowtype/npm/react-router_v4.x.x.js +++ b/src/flowtype/npm/react-router_v4.x.x.js @@ -1,4 +1,4 @@ -declare module "react-router" { +declare module 'react-router' { // NOTE: many of these are re-exported by react-router-dom and // react-router-native, so when making changes, please be sure to update those // as well. @@ -9,16 +9,16 @@ declare module "react-router" { state?: any, key?: string }; - + declare export type LocationShape = { pathname?: string, search?: string, hash?: string, state?: any }; - + declare export type HistoryAction = "PUSH" | "REPLACE" | "POP"; - + declare export type RouterHistory = { length: number, location: Location, @@ -39,37 +39,37 @@ declare module "react-router" { index?: number, entries?: Array }; - + declare export type Match = { params: { [key: string]: ?string }, isExact: boolean, path: string, url: string }; - + declare export type ContextRouter = {| history: RouterHistory, location: Location, match: Match, staticContext?: StaticRouterContext |}; - + declare export type GetUserConfirmation = ( message: string, callback: (confirmed: boolean) => void ) => void; - + declare type StaticRouterContext = { url?: string }; - + declare export class StaticRouter extends React$Component<{ basename?: string, location?: string | Location, context: StaticRouterContext, children?: React$Node }> {} - + declare export class MemoryRouter extends React$Component<{ initialEntries?: Array, initialIndex?: number, @@ -77,22 +77,22 @@ declare module "react-router" { keyLength?: number, children?: React$Node }> {} - + declare export class Router extends React$Component<{ history: RouterHistory, children?: React$Node }> {} - + declare export class Prompt extends React$Component<{ message: string | ((location: Location) => string | true), when?: boolean }> {} - + declare export class Redirect extends React$Component<{ to: string | LocationShape, push?: boolean }> {} - + declare export class Route extends React$Component<{ component?: React$ComponentType<*>, render?: (router: ContextRouter) => React$Node, @@ -101,15 +101,15 @@ declare module "react-router" { exact?: boolean, strict?: boolean }> {} - + declare export class Switch extends React$Component<{ children?: React$Node }> {} - + declare export function withRouter

( Component: React$ComponentType<{| ...ContextRouter, ...P |}> ): React$ComponentType

; - + declare type MatchPathOptions = { path?: string, exact?: boolean, diff --git a/src/flowtype/npm/redux_v3.x.x.js b/src/flowtype/npm/redux_v3.x.x.js index d51acdc5..d0717bdf 100644 --- a/src/flowtype/npm/redux_v3.x.x.js +++ b/src/flowtype/npm/redux_v3.x.x.js @@ -1,5 +1,4 @@ declare module 'redux' { - /* S = State @@ -19,7 +18,7 @@ declare module 'redux' { declare export type AsyncDispatch = (action: AsyncAction) => Promise; declare export type PlainDispatch}> = DispatchAPI; /* NEW: Dispatch is now a combination of these different dispatch types */ - declare export type ReduxDispatch = PlainDispatch & ThunkDispatch & AsyncDispatch; + declare export type ReduxDispatch = PlainDispatch & ThunkDispatch & AsyncDispatch; declare export type MiddlewareAPI = { // dispatch: Dispatch; diff --git a/src/flowtype/npm/web3.js b/src/flowtype/npm/web3.js index 8af20550..81e27543 100644 --- a/src/flowtype/npm/web3.js +++ b/src/flowtype/npm/web3.js @@ -33,7 +33,7 @@ declare module 'web3' { network: string; // and many more } - + } declare export type EstimateGasOptions = { @@ -124,10 +124,8 @@ declare module 'web3' { } - -// -// - +// +// /*declare module 'web3' { diff --git a/src/js/actions/AccountsActions.js b/src/js/actions/AccountsActions.js index 74b8a99e..19ab2af7 100644 --- a/src/js/actions/AccountsActions.js +++ b/src/js/actions/AccountsActions.js @@ -1,5 +1,4 @@ /* @flow */ -'use strict'; import * as ACCOUNT from './constants/account'; import type { Action, TrezorDevice } from '~/flowtype'; @@ -22,7 +21,7 @@ export type AccountCreateAction = { network: string, index: number, path: Array, - address: string + address: string } export type AccountSetBalanceAction = { @@ -41,22 +40,18 @@ export type AccountSetNonceAction = { nonce: number } -export const setBalance = (address: string, network: string, deviceState: string, balance: string): Action => { - return { - type: ACCOUNT.SET_BALANCE, - address, - network, - deviceState, - balance - } -} - -export const setNonce = (address: string, network: string, deviceState: string, nonce: number): Action => { - return { - type: ACCOUNT.SET_NONCE, - address, - network, - deviceState, - nonce - } -} \ No newline at end of file +export const setBalance = (address: string, network: string, deviceState: string, balance: string): Action => ({ + type: ACCOUNT.SET_BALANCE, + address, + network, + deviceState, + balance, +}); + +export const setNonce = (address: string, network: string, deviceState: string, nonce: number): Action => ({ + type: ACCOUNT.SET_NONCE, + address, + network, + deviceState, + nonce, +}); \ No newline at end of file diff --git a/src/js/actions/DiscoveryActions.js b/src/js/actions/DiscoveryActions.js index 1b40ccda..57c857c3 100644 --- a/src/js/actions/DiscoveryActions.js +++ b/src/js/actions/DiscoveryActions.js @@ -1,19 +1,21 @@ /* @flow */ -'use strict'; import TrezorConnect from 'trezor-connect'; +import HDKey from 'hdkey'; +import EthereumjsUtil from 'ethereumjs-util'; import * as DISCOVERY from './constants/discovery'; import * as ACCOUNT from './constants/account'; import * as TOKEN from './constants/token'; import * as NOTIFICATION from './constants/notification'; -import * as AccountsActions from '../actions/AccountsActions'; +import * as AccountsActions from './AccountsActions'; -import HDKey from 'hdkey'; -import EthereumjsUtil from 'ethereumjs-util'; import { getNonceAsync, getBalanceAsync, getTokenBalanceAsync } from './Web3Actions'; import { setBalance as setTokenBalance } from './TokenActions'; -import type { ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '~/flowtype'; +import type { + ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice, +} from '~/flowtype'; + import type { Discovery, State } from '../reducers/DiscoveryReducer'; export type DiscoveryAction = { @@ -50,320 +52,297 @@ export type DiscoveryCompleteAction = { network: string } -export const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const selected = getState().wallet.selectedDevice; - if (!selected) { - // TODO: throw error - console.error("Start discovery: no selected device", device) - return; - } else if (selected.path !== device.path) { - console.error("Start discovery: requested device is not selected", device, selected) - return; - } else if (!selected.state) { - console.warn("Start discovery: Selected device wasn't authenticated yet...") - return; - } else if (selected.connected && !selected.available) { - console.warn("Start discovery: Selected device is unavailable...") - return; - } - - const web3 = getState().web3.find(w3 => w3.network === network); - if (!web3) { - console.error("Start discovery: Web3 does not exist", network) - return; - } - - if (!web3.web3.currentProvider.isConnected()) { - console.error("Start discovery: Web3 is not connected", network) - dispatch({ - type: DISCOVERY.WAITING_FOR_BACKEND, - device, - network - }); - return; - } - - const discovery: State = getState().discovery; - let discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network); +export const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const selected = getState().wallet.selectedDevice; + if (!selected) { + // TODO: throw error + console.error('Start discovery: no selected device', device); + return; + } if (selected.path !== device.path) { + console.error('Start discovery: requested device is not selected', device, selected); + return; + } if (!selected.state) { + console.warn("Start discovery: Selected device wasn't authenticated yet..."); + return; + } if (selected.connected && !selected.available) { + console.warn('Start discovery: Selected device is unavailable...'); + return; + } - - - if (!selected.connected && (!discoveryProcess || !discoveryProcess.completed)) { - dispatch({ - type: DISCOVERY.WAITING_FOR_DEVICE, - device, - network - }); - return; - } + const web3 = getState().web3.find(w3 => w3.network === network); + if (!web3) { + console.error('Start discovery: Web3 does not exist', network); + return; + } - if (!discoveryProcess) { - dispatch( begin(device, network) ); - return; - } else { - if (discoveryProcess.completed && !ignoreCompleted) { - dispatch({ - type: DISCOVERY.COMPLETE, - device, - network - }); - } else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice) { - // discovery cycle was interrupted - // start from beginning - dispatch( begin(device, network) ); - } else { - dispatch( discoverAccount(device, discoveryProcess) ); - } - } + if (!web3.web3.currentProvider.isConnected()) { + console.error('Start discovery: Web3 is not connected', network); + dispatch({ + type: DISCOVERY.WAITING_FOR_BACKEND, + device, + network, + }); + return; } -} -const begin = (device: TrezorDevice, network: string): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { + const discovery: State = getState().discovery; + const discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network); - const { config } = getState().localStorage; - const coinToDiscover = config.coins.find(c => c.network === network); - if (!coinToDiscover) return; + if (!selected.connected && (!discoveryProcess || !discoveryProcess.completed)) { dispatch({ type: DISCOVERY.WAITING_FOR_DEVICE, device, - network + network, }); + return; + } - // get xpub from TREZOR - const response = await TrezorConnect.getPublicKey({ - device: { - path: device.path, - instance: device.instance, - state: device.state - }, - path: coinToDiscover.bip44, - keepSession: true, // acquire and hold session - useEmptyPassphrase: !device.instance, + if (!discoveryProcess) { + dispatch(begin(device, network)); + } else if (discoveryProcess.completed && !ignoreCompleted) { + dispatch({ + type: DISCOVERY.COMPLETE, + device, + network, }); + } else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice) { + // discovery cycle was interrupted + // start from beginning + dispatch(begin(device, network)); + } else { + dispatch(discoverAccount(device, discoveryProcess)); + } +}; + +const begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const { config } = getState().localStorage; + const coinToDiscover = config.coins.find(c => c.network === network); + if (!coinToDiscover) return; + + dispatch({ + type: DISCOVERY.WAITING_FOR_DEVICE, + device, + network, + }); + + // get xpub from TREZOR + const response = await TrezorConnect.getPublicKey({ + device: { + path: device.path, + instance: device.instance, + state: device.state, + }, + path: coinToDiscover.bip44, + keepSession: true, // acquire and hold session + useEmptyPassphrase: !device.instance, + }); // handle TREZOR response error - if (!response.success) { - // TODO: check message - console.warn("DISCOVERY ERROR", response) + if (!response.success) { + // TODO: check message + console.warn('DISCOVERY ERROR', response); + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Discovery error', + message: response.payload.error, + cancelable: true, + actions: [ + { + label: 'Try again', + callback: () => { + dispatch(start(device, network)); + }, + }, + ], + }, + }); + return; + } + + // check for interruption + const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === device.state && d.network === network); + if (discoveryProcess && discoveryProcess.interrupted) return; + + const basePath: Array = response.payload.path; + + // send data to reducer + dispatch({ + type: DISCOVERY.START, + network: coinToDiscover.network, + device, + publicKey: response.payload.publicKey, + chainCode: response.payload.chainCode, + basePath, + }); + + dispatch(start(device, network)); +}; + +const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const completed: boolean = discoveryProcess.completed; + discoveryProcess.completed = false; + + const derivedKey = discoveryProcess.hdKey.derive(`m/${discoveryProcess.accountIndex}`); + const path = discoveryProcess.basePath.concat(discoveryProcess.accountIndex); + const publicAddress: string = EthereumjsUtil.publicToAddress(derivedKey.publicKey, true).toString('hex'); + const ethAddress: string = EthereumjsUtil.toChecksumAddress(publicAddress); + const network = discoveryProcess.network; + + + // TODO: check if address was created before + + // verify address with TREZOR + const verifyAddress = await TrezorConnect.ethereumGetAddress({ + device: { + path: device.path, + instance: device.instance, + state: device.state, + }, + path, + showOnTrezor: false, + keepSession: true, + useEmptyPassphrase: !device.instance, + }); + if (discoveryProcess.interrupted) return; + + // TODO: with block-book (Martin) + // const discoveryA = await TrezorConnect.accountDiscovery({ + // device: { + // path: device.path, + // instance: device.instance, + // state: device.state + // }, + // }); + // if (discoveryProcess.interrupted) return; + + if (verifyAddress && verifyAddress.success) { + //const trezorAddress: string = '0x' + verifyAddress.payload.address; + const trezorAddress: string = EthereumjsUtil.toChecksumAddress(verifyAddress.payload.address); + if (trezorAddress !== ethAddress) { + // throw inconsistent state error + console.warn('Inconsistent state', trezorAddress, ethAddress); + dispatch({ type: NOTIFICATION.ADD, payload: { type: 'error', - title: 'Discovery error', - message: response.payload.error, + title: 'Address validation error', + message: `Addresses are different. TREZOR: ${trezorAddress} HDKey: ${ethAddress}`, cancelable: true, actions: [ { label: 'Try again', callback: () => { - dispatch(start(device, network)) - } - } - ] - } - }) + dispatch(start(device, discoveryProcess.network)); + }, + }, + ], + }, + }); return; } - - // check for interruption - let discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === device.state && d.network === network); - if (discoveryProcess && discoveryProcess.interrupted) return; - - const basePath: Array = response.payload.path; - - // send data to reducer + } else { + // handle TREZOR communication error dispatch({ - type: DISCOVERY.START, - network: coinToDiscover.network, - device, - publicKey: response.payload.publicKey, - chainCode: response.payload.chainCode, - basePath, + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Address validation error', + message: verifyAddress.payload.error, + cancelable: true, + actions: [ + { + label: 'Try again', + callback: () => { + dispatch(start(device, discoveryProcess.network)); + }, + }, + ], + }, }); - - dispatch( start(device, network) ); + return; } -} -const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { + const web3instance = getState().web3.find(w3 => w3.network === network); + if (!web3instance) return; - const completed: boolean = discoveryProcess.completed; - discoveryProcess.completed = false; + const balance = await getBalanceAsync(web3instance.web3, ethAddress); + if (discoveryProcess.interrupted) return; + const nonce: number = await getNonceAsync(web3instance.web3, ethAddress); + if (discoveryProcess.interrupted) return; - const derivedKey = discoveryProcess.hdKey.derive(`m/${discoveryProcess.accountIndex}`); - const path = discoveryProcess.basePath.concat(discoveryProcess.accountIndex); - const publicAddress: string = EthereumjsUtil.publicToAddress(derivedKey.publicKey, true).toString('hex'); - const ethAddress: string = EthereumjsUtil.toChecksumAddress(publicAddress); - const network = discoveryProcess.network; + const addressIsEmpty = nonce < 1 && !balance.greaterThan(0); - + if (!addressIsEmpty || (addressIsEmpty && completed) || (addressIsEmpty && discoveryProcess.accountIndex === 0)) { + dispatch({ + type: ACCOUNT.CREATE, + device, + network, + index: discoveryProcess.accountIndex, + path, + address: ethAddress, + }); + dispatch( + AccountsActions.setBalance(ethAddress, network, device.state || 'undefined', web3instance.web3.fromWei(balance.toString(), 'ether')), + ); + dispatch(AccountsActions.setNonce(ethAddress, network, device.state || 'undefined', nonce)); - // TODO: check if address was created before + if (!completed) { dispatch(discoverAccount(device, discoveryProcess)); } + } - // verify address with TREZOR - const verifyAddress = await TrezorConnect.ethereumGetAddress({ + if (addressIsEmpty) { + // release acquired sesssion + await TrezorConnect.getFeatures({ device: { path: device.path, instance: device.instance, - state: device.state + state: device.state, }, - path, - showOnTrezor: false, - keepSession: true, + keepSession: false, useEmptyPassphrase: !device.instance, }); if (discoveryProcess.interrupted) return; - // TODO: with block-book (Martin) - // const discoveryA = await TrezorConnect.accountDiscovery({ - // device: { - // path: device.path, - // instance: device.instance, - // state: device.state - // }, - // }); - // if (discoveryProcess.interrupted) return; - - if (verifyAddress && verifyAddress.success) { - //const trezorAddress: string = '0x' + verifyAddress.payload.address; - const trezorAddress: string = EthereumjsUtil.toChecksumAddress(verifyAddress.payload.address); - if (trezorAddress !== ethAddress) { - // throw inconsistent state error - console.warn("Inconsistent state", trezorAddress, ethAddress); - - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Address validation error', - message: `Addresses are different. TREZOR: ${ trezorAddress } HDKey: ${ ethAddress }`, - cancelable: true, - actions: [ - { - label: 'Try again', - callback: () => { - dispatch(start(device, discoveryProcess.network)) - } - } - ] - } - }); - return; - } - } else { - // handle TREZOR communication error - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Address validation error', - message: verifyAddress.payload.error, - cancelable: true, - actions: [ - { - label: 'Try again', - callback: () => { - dispatch(start(device, discoveryProcess.network)) - } - } - ] - } - }); - return; - } - - const web3instance = getState().web3.find(w3 => w3.network === network); - if (!web3instance) return; - - const balance = await getBalanceAsync(web3instance.web3, ethAddress); - if (discoveryProcess.interrupted) return; - const nonce: number = await getNonceAsync(web3instance.web3, ethAddress); - if (discoveryProcess.interrupted) return; - - const addressIsEmpty = nonce < 1 && !balance.greaterThan(0); - - if (!addressIsEmpty || (addressIsEmpty && completed) || (addressIsEmpty && discoveryProcess.accountIndex === 0)) { - dispatch({ - type: ACCOUNT.CREATE, - device, - network, - index: discoveryProcess.accountIndex, - path, - address: ethAddress - }); - dispatch( - AccountsActions.setBalance(ethAddress, network, device.state || 'undefined', web3instance.web3.fromWei(balance.toString(), 'ether')) - ); - dispatch(AccountsActions.setNonce(ethAddress, network, device.state || 'undefined', nonce)); - - if (!completed) - dispatch( discoverAccount(device, discoveryProcess) ); - } - - if (addressIsEmpty) { - // release acquired sesssion - await TrezorConnect.getFeatures({ - device: { - path: device.path, - instance: device.instance, - state: device.state - }, - keepSession: false, - useEmptyPassphrase: !device.instance, - }); - if (discoveryProcess.interrupted) return; - - dispatch({ - type: DISCOVERY.COMPLETE, - device, - network - }); - } + dispatch({ + type: DISCOVERY.COMPLETE, + device, + network, + }); } -} +}; -export const restore = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const selected = getState().wallet.selectedDevice; +export const restore = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const selected = getState().wallet.selectedDevice; - if (selected && selected.connected && selected.features) { - const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.waitingForDevice); - if (discoveryProcess) { - dispatch( start(selected, discoveryProcess.network) ); - } + if (selected && selected.connected && selected.features) { + const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.waitingForDevice); + if (discoveryProcess) { + dispatch(start(selected, discoveryProcess.network)); } } -} +}; // TODO: rename method to something intuitive // there is no discovery process but it should be // this is possible race condition when "network" was changed in url but device was not authenticated yet // try to start discovery after CONNECT.AUTH_DEVICE action -export const check = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const selected = getState().wallet.selectedDevice; - if (!selected) return; - - const urlParams = getState().router.location.state; - if (urlParams.network) { - const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.network === urlParams.network); - if (!discoveryProcess) { - dispatch( start(selected, urlParams.network) ); - } +export const check = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const selected = getState().wallet.selectedDevice; + if (!selected) return; + + const urlParams = getState().router.location.state; + if (urlParams.network) { + const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.network === urlParams.network); + if (!discoveryProcess) { + dispatch(start(selected, urlParams.network)); } } -} +}; -export const stop = (device: TrezorDevice): Action => { - // TODO: release devices session - // corner case switch /eth to /etc (discovery start stop - should not be async) - return { - type: DISCOVERY.STOP, - device - } -} \ No newline at end of file +export const stop = (device: TrezorDevice): Action => ({ + type: DISCOVERY.STOP, + device, +}); diff --git a/src/js/actions/HistoryActions.js b/src/js/actions/HistoryActions.js index 0f324a80..e667c471 100644 --- a/src/js/actions/HistoryActions.js +++ b/src/js/actions/HistoryActions.js @@ -1,2 +1 @@ /* @flow */ -'use strict'; diff --git a/src/js/actions/LocalStorageActions.js b/src/js/actions/LocalStorageActions.js index b25ca328..b66a1b33 100644 --- a/src/js/actions/LocalStorageActions.js +++ b/src/js/actions/LocalStorageActions.js @@ -1,15 +1,17 @@ /* @flow */ -'use strict'; + import * as CONNECT from './constants/TrezorConnect'; import * as ACCOUNT from './constants/account'; import * as TOKEN from './constants/token'; import * as DISCOVERY from './constants/discovery'; import * as STORAGE from './constants/localStorage'; -import * as PENDING from '../actions/constants/pendingTx'; +import * as PENDING from './constants/pendingTx'; import { JSONRequest, httpRequest } from '../utils/networkUtils'; -import type { ThunkAction, AsyncAction, GetState, Dispatch, TrezorDevice } from '~/flowtype'; +import type { + ThunkAction, AsyncAction, GetState, Dispatch, TrezorDevice, +} from '~/flowtype'; import type { Config, Coin, TokensCollection } from '../reducers/LocalStorageReducer'; import AppConfigJSON from '~/data/appConfig.json'; @@ -28,24 +30,21 @@ export type StorageAction = { error: string, }; -export const loadData = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - // check if local storage is available - // let available: boolean = true; - // if (typeof window.localStorage === 'undefined') { - // available = false; - // } else { - // try { - // window.localStorage.setItem('ethereum_wallet', true); - // } catch (error) { - // available = false; - // } - // } - - dispatch( loadTokensFromJSON() ); - } -} +export const loadData = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + // check if local storage is available + // let available: boolean = true; + // if (typeof window.localStorage === 'undefined') { + // available = false; + // } else { + // try { + // window.localStorage.setItem('ethereum_wallet', true); + // } catch (error) { + // available = false; + // } + // } + + dispatch(loadTokensFromJSON()); +}; // const parseConfig = (json: JSON): Config => { @@ -68,13 +67,13 @@ export const loadData = (): ThunkAction => { // if (json.config && json.hasOwnProperty('coins') && Array.isArray(json.coins)) { // json.coins.map(c => { // return { - + // } // }) // } else { // throw new Error(`Property "coins" is missing in appConfig.json`); // } - + // return { // coins: [], @@ -84,22 +83,21 @@ export const loadData = (): ThunkAction => { export function loadTokensFromJSON(): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - if (typeof window.localStorage === 'undefined') return; try { const config: Config = await httpRequest(AppConfigJSON, 'json'); const ERC20Abi = await httpRequest(Erc20AbiJSON, 'json'); - window.addEventListener('storage', event => { - dispatch( update(event) ); - }) + window.addEventListener('storage', (event) => { + dispatch(update(event)); + }); // load tokens const tokens = await config.coins.reduce(async (promise: Promise, coin: Coin): Promise => { const collection: TokensCollection = await promise; const json = await httpRequest(coin.tokens, 'json'); - collection[ coin.network ] = json; + collection[coin.network] = json; return collection; }, Promise.resolve({})); @@ -107,62 +105,60 @@ export function loadTokensFromJSON(): AsyncAction { if (devices) { dispatch({ type: CONNECT.DEVICE_FROM_STORAGE, - payload: JSON.parse(devices) - }) + payload: JSON.parse(devices), + }); } const accounts: ?string = get('accounts'); if (accounts) { dispatch({ type: ACCOUNT.FROM_STORAGE, - payload: JSON.parse(accounts) - }) + payload: JSON.parse(accounts), + }); } const userTokens: ?string = get('tokens'); if (userTokens) { dispatch({ type: TOKEN.FROM_STORAGE, - payload: JSON.parse(userTokens) - }) + payload: JSON.parse(userTokens), + }); } const pending: ?string = get('pending'); if (pending) { dispatch({ type: PENDING.FROM_STORAGE, - payload: JSON.parse(pending) - }) + payload: JSON.parse(pending), + }); } const discovery: ?string = get('discovery'); if (discovery) { dispatch({ type: DISCOVERY.FROM_STORAGE, - payload: JSON.parse(discovery) - }) + payload: JSON.parse(discovery), + }); } - - + + dispatch({ type: STORAGE.READY, config, tokens, - ERC20Abi - }) - - } catch(error) { + ERC20Abi, + }); + } catch (error) { dispatch({ type: STORAGE.ERROR, - error - }) + error, + }); } - } + }; } export function update(event: StorageEvent): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - if (!event.newValue) return; if (event.key === 'devices') { @@ -183,46 +179,44 @@ export function update(event: StorageEvent): AsyncAction { if (event.key === 'accounts') { dispatch({ type: ACCOUNT.FROM_STORAGE, - payload: JSON.parse(event.newValue) + payload: JSON.parse(event.newValue), }); } if (event.key === 'tokens') { dispatch({ type: TOKEN.FROM_STORAGE, - payload: JSON.parse(event.newValue) + payload: JSON.parse(event.newValue), }); } if (event.key === 'pending') { dispatch({ type: PENDING.FROM_STORAGE, - payload: JSON.parse(event.newValue) + payload: JSON.parse(event.newValue), }); } if (event.key === 'discovery') { dispatch({ type: DISCOVERY.FROM_STORAGE, - payload: JSON.parse(event.newValue) + payload: JSON.parse(event.newValue), }); } - } + }; } -export const save = (key: string, value: string): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - if (typeof window.localStorage !== 'undefined') { - try { - window.localStorage.setItem(key, value); - } catch (error) { - // available = false; - console.error("Local Storage ERROR: " + error) - } +export const save = (key: string, value: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + if (typeof window.localStorage !== 'undefined') { + try { + window.localStorage.setItem(key, value); + } catch (error) { + // available = false; + console.error(`Local Storage ERROR: ${error}`); } } -} +}; export const get = (key: string): ?string => { try { @@ -231,4 +225,4 @@ export const get = (key: string): ?string => { // available = false; return null; } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/js/actions/LogActions.js b/src/js/actions/LogActions.js index d645fe9d..be9b3b13 100644 --- a/src/js/actions/LogActions.js +++ b/src/js/actions/LogActions.js @@ -1,9 +1,11 @@ /* @flow */ -'use strict'; + import * as LOG from './constants/log'; -import type { Action, ThunkAction, GetState, Dispatch } from '~/flowtype'; +import type { + Action, ThunkAction, GetState, Dispatch, +} from '~/flowtype'; import type { LogEntry } from '../reducers/LogReducer'; export type LogAction = { @@ -15,31 +17,26 @@ export type LogAction = { payload: LogEntry }; -export const toggle = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - if (!getState().log.opened) { - window.scrollTo(0, 0); +export const toggle = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + if (!getState().log.opened) { + window.scrollTo(0, 0); - dispatch({ - type: LOG.OPEN - }); - } else { - dispatch({ - type: LOG.CLOSE - }); - } + dispatch({ + type: LOG.OPEN, + }); + } else { + dispatch({ + type: LOG.CLOSE, + }); } -} +}; // export const add = (type: string, message: string): Action => { -export const add = (type: string, message: any): Action => { - return { - type: LOG.ADD, - payload: { - time: new Date().getTime(), - type, - message - } - } -} +export const add = (type: string, message: any): Action => ({ + type: LOG.ADD, + payload: { + time: new Date().getTime(), + type, + message, + }, +}); diff --git a/src/js/actions/ModalActions.js b/src/js/actions/ModalActions.js index 137c1465..ba73a0dd 100644 --- a/src/js/actions/ModalActions.js +++ b/src/js/actions/ModalActions.js @@ -1,13 +1,15 @@ /* @flow */ -'use strict'; + import TrezorConnect, { UI, UI_EVENT } from 'trezor-connect'; +import type { Device } from 'trezor-connect'; import * as MODAL from './constants/modal'; import * as CONNECT from './constants/TrezorConnect'; -import type { ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '~/flowtype'; +import type { + ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice, +} from '~/flowtype'; import type { State } from '../reducers/ModalReducer'; -import type { Device } from 'trezor-connect'; export type ModalAction = { type: typeof MODAL.CLOSE @@ -19,25 +21,23 @@ export type ModalAction = { export const onPinSubmit = (value: string): Action => { TrezorConnect.uiResponse({ type: UI.RECEIVE_PIN, payload: value }); return { - type: MODAL.CLOSE - } -} - -export const onPassphraseSubmit = (passphrase: string): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const resp = await TrezorConnect.uiResponse({ - type: UI.RECEIVE_PASSPHRASE, - payload: { - value: passphrase, - save: true - } - }); + type: MODAL.CLOSE, + }; +}; - dispatch({ - type: MODAL.CLOSE - }); - } -} +export const onPassphraseSubmit = (passphrase: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const resp = await TrezorConnect.uiResponse({ + type: UI.RECEIVE_PASSPHRASE, + payload: { + value: passphrase, + save: true, + }, + }); + + dispatch({ + type: MODAL.CLOSE, + }); +}; // export const askForRemember = (device: TrezorDevice): Action => { // return { @@ -46,88 +46,72 @@ export const onPassphraseSubmit = (passphrase: string): AsyncAction => { // } // } -export const onRememberDevice = (device: TrezorDevice): Action => { - return { - type: CONNECT.REMEMBER, - device - } -} +export const onRememberDevice = (device: TrezorDevice): Action => ({ + type: CONNECT.REMEMBER, + device, +}); -export const onForgetDevice = (device: TrezorDevice): Action => { - return { - type: CONNECT.FORGET, - device, - } -} +export const onForgetDevice = (device: TrezorDevice): Action => ({ + type: CONNECT.FORGET, + device, +}); -export const onForgetSingleDevice = (device: TrezorDevice): Action => { - return { - type: CONNECT.FORGET_SINGLE, - device, - } -} +export const onForgetSingleDevice = (device: TrezorDevice): Action => ({ + type: CONNECT.FORGET_SINGLE, + device, +}); -export const onCancel = (): Action => { - return { - type: MODAL.CLOSE - } -} +export const onCancel = (): Action => ({ + type: MODAL.CLOSE, +}); + +export const onDuplicateDevice = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + dispatch(onCancel()); -export const onDuplicateDevice = (device: TrezorDevice): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { + dispatch({ + type: CONNECT.DUPLICATE, + device, + }); +}; - dispatch( onCancel() ); +export const onRememberRequest = (prevState: State): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state: State = getState().modal; + // handle case where forget modal is already opened + // TODO: 2 modals at once (two devices disconnected in the same time) + if (prevState.opened && prevState.windowType === CONNECT.REMEMBER_REQUEST) { + // forget current (new) + if (state.opened) { + dispatch({ + type: CONNECT.FORGET, + device: state.device, + }); + } + // forget previous (old) dispatch({ - type: CONNECT.DUPLICATE, - device + type: CONNECT.FORGET, + device: prevState.device, }); } -} - -export const onRememberRequest = (prevState: State): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const state: State = getState().modal; - // handle case where forget modal is already opened - // TODO: 2 modals at once (two devices disconnected in the same time) - if (prevState.opened && prevState.windowType === CONNECT.REMEMBER_REQUEST) { - // forget current (new) - if (state.opened) { - dispatch({ - type: CONNECT.FORGET, - device: state.device - }); - } - - // forget previous (old) +}; + +export const onDeviceConnect = (device: Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + // interrupt process of remembering device (force forget) + // TODO: the same for disconnect more than 1 device at once + const { modal } = getState(); + if (modal.opened && modal.windowType === CONNECT.REMEMBER_REQUEST) { + if (device.features && modal.device && modal.device.features && modal.device.features.device_id === device.features.device_id) { + dispatch({ + type: MODAL.CLOSE, + }); + } else { dispatch({ type: CONNECT.FORGET, - device: prevState.device + device: modal.device, }); } } -} - -export const onDeviceConnect = (device: Device): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - // interrupt process of remembering device (force forget) - // TODO: the same for disconnect more than 1 device at once - const { modal } = getState(); - if (modal.opened && modal.windowType === CONNECT.REMEMBER_REQUEST) { - if (device.features && modal.device && modal.device.features && modal.device.features.device_id === device.features.device_id) { - dispatch({ - type: MODAL.CLOSE, - }); - } else { - dispatch({ - type: CONNECT.FORGET, - device: modal.device - }); - } - } - - } -} +}; export default { onPinSubmit, @@ -137,5 +121,5 @@ export default { onForgetDevice, onForgetSingleDevice, onCancel, - onDuplicateDevice -} \ No newline at end of file + onDuplicateDevice, +}; \ No newline at end of file diff --git a/src/js/actions/NotificationActions.js b/src/js/actions/NotificationActions.js index e199cd14..ae6c9557 100644 --- a/src/js/actions/NotificationActions.js +++ b/src/js/actions/NotificationActions.js @@ -1,9 +1,11 @@ /* @flow */ -'use strict'; + import * as NOTIFICATION from './constants/notification'; -import type { Action, AsyncAction, GetState, Dispatch, RouterLocationState } from '~/flowtype'; +import type { + Action, AsyncAction, GetState, Dispatch, RouterLocationState, +} from '~/flowtype'; import type { CallbackAction } from '../reducers/NotificationReducer'; export type NotificationAction = { @@ -23,31 +25,27 @@ export type NotificationAction = { } } -export const close = (payload: any = {}): Action => { - return { - type: NOTIFICATION.CLOSE, - payload - } -} +export const close = (payload: any = {}): Action => ({ + type: NOTIFICATION.CLOSE, + payload, +}); // called from RouterService -export const clear = (currentParams: RouterLocationState, requestedParams: RouterLocationState): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - // if route has been changed from device view into something else (like other device, settings...) - // try to remove all Notifications which are linked to previous device (they are not cancelable by user) - if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) { - const entries = getState().notifications.filter(entry => typeof entry.devicePath === 'string'); - entries.forEach(entry => { - if (typeof entry.devicePath === 'string') { - dispatch({ - type: NOTIFICATION.CLOSE, - payload: { - devicePath: entry.devicePath - } - }) - } - }); - } +export const clear = (currentParams: RouterLocationState, requestedParams: RouterLocationState): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + // if route has been changed from device view into something else (like other device, settings...) + // try to remove all Notifications which are linked to previous device (they are not cancelable by user) + if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) { + const entries = getState().notifications.filter(entry => typeof entry.devicePath === 'string'); + entries.forEach((entry) => { + if (typeof entry.devicePath === 'string') { + dispatch({ + type: NOTIFICATION.CLOSE, + payload: { + devicePath: entry.devicePath, + }, + }); + } + }); } -} +}; diff --git a/src/js/actions/PendingTxActions.js b/src/js/actions/PendingTxActions.js index c0f38520..ece7c37c 100644 --- a/src/js/actions/PendingTxActions.js +++ b/src/js/actions/PendingTxActions.js @@ -1,8 +1,8 @@ /* @flow */ -'use strict'; + import * as PENDING from './constants/pendingTx'; -import type { State, PendingTx } from '../reducers/PendingTxReducer' +import type { State, PendingTx } from '../reducers/PendingTxReducer'; export type PendingTxAction = { type: typeof PENDING.FROM_STORAGE, diff --git a/src/js/actions/ReceiveActions.js b/src/js/actions/ReceiveActions.js index 11a38058..60a8a087 100644 --- a/src/js/actions/ReceiveActions.js +++ b/src/js/actions/ReceiveActions.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import TrezorConnect from 'trezor-connect'; import * as RECEIVE from './constants/receive'; @@ -8,7 +8,9 @@ import * as NOTIFICATION from './constants/notification'; import { initialState } from '../reducers/ReceiveReducer'; import type { State } from '../reducers/ReceiveReducer'; -import type { TrezorDevice, ThunkAction, AsyncAction, Action, GetState, Dispatch } from '~/flowtype'; +import type { + TrezorDevice, ThunkAction, AsyncAction, Action, GetState, Dispatch, +} from '~/flowtype'; export type ReceiveAction = { type: typeof RECEIVE.INIT, @@ -26,90 +28,80 @@ export type ReceiveAction = { type: typeof RECEIVE.SHOW_UNVERIFIED_ADDRESS } -export const init = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const state: State = { - ...initialState, - }; +export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state: State = { + ...initialState, + }; - dispatch({ - type: RECEIVE.INIT, - state: state - }); - } -} + dispatch({ + type: RECEIVE.INIT, + state, + }); +}; -export const dispose = (): Action => { - return { - type: RECEIVE.DISPOSE - } -} +export const dispose = (): Action => ({ + type: RECEIVE.DISPOSE, +}); -export const showUnverifiedAddress = (): Action => { - return { - type: RECEIVE.SHOW_UNVERIFIED_ADDRESS - } -} +export const showUnverifiedAddress = (): Action => ({ + type: RECEIVE.SHOW_UNVERIFIED_ADDRESS, +}); //export const showAddress = (address_n: string): AsyncAction => { -export const showAddress = (address_n: Array): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { +export const showAddress = (address_n: Array): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const selected = getState().wallet.selectedDevice; + if (!selected) return; + + if (selected && (!selected.connected || !selected.available)) { + dispatch({ + type: RECEIVE.REQUEST_UNVERIFIED, + device: selected, + }); + return; + } - const selected = getState().wallet.selectedDevice; - if (!selected) return; + const response = await TrezorConnect.ethereumGetAddress({ + device: { + path: selected.path, + instance: selected.instance, + state: selected.state, + }, + path: address_n, + useEmptyPassphrase: !selected.instance, + }); - if (selected && (!selected.connected || !selected.available)) { - dispatch({ - type: RECEIVE.REQUEST_UNVERIFIED, - device: selected - }); - return; - } + if (response && response.success) { + dispatch({ + type: RECEIVE.SHOW_ADDRESS, + }); + } else { + dispatch({ + type: RECEIVE.HIDE_ADDRESS, + }); - const response = await TrezorConnect.ethereumGetAddress({ - device: { - path: selected.path, - instance: selected.instance, - state: selected.state + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Verifying address error', + message: response.payload.error, + cancelable: true, + actions: [ + { + label: 'Try again', + callback: () => { + dispatch(showAddress(address_n)); + }, + }, + ], }, - path: address_n, - useEmptyPassphrase: !selected.instance, }); - - if (response && response.success) { - dispatch({ - type: RECEIVE.SHOW_ADDRESS - }) - } else { - dispatch({ - type: RECEIVE.HIDE_ADDRESS - }) - - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Verifying address error', - message: response.payload.error, - cancelable: true, - actions: [ - { - label: 'Try again', - callback: () => { - dispatch(showAddress(address_n)) - } - } - ] - } - }) - } } -} +}; export default { init, dispose, showAddress, - showUnverifiedAddress -} \ No newline at end of file + showUnverifiedAddress, +}; \ No newline at end of file diff --git a/src/js/actions/SelectedAccountActions.js b/src/js/actions/SelectedAccountActions.js index 44ca0b3e..9d18709a 100644 --- a/src/js/actions/SelectedAccountActions.js +++ b/src/js/actions/SelectedAccountActions.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import { LOCATION_CHANGE } from 'react-router-redux'; import * as ACCOUNT from './constants/account'; @@ -18,8 +18,8 @@ import type { TrezorDevice, AsyncAction, ThunkAction, - Action, - GetState, + Action, + GetState, Dispatch, State, } from '~/flowtype'; @@ -32,110 +32,101 @@ export type SelectedAccountAction = { payload: $ElementType }; -export const updateSelectedValues = (prevState: State, action: Action): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - - const locationChange: boolean = action.type === LOCATION_CHANGE; - const state: State = getState(); - const location = state.router.location; - const prevLocation = prevState.router.location; +export const updateSelectedValues = (prevState: State, action: Action): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const locationChange: boolean = action.type === LOCATION_CHANGE; + const state: State = getState(); + const location = state.router.location; + const prevLocation = prevState.router.location; - let needUpdate: boolean = false; + const needUpdate: boolean = false; - // reset form to default - if (action.type === SEND.TX_COMPLETE) { - // dispatch( SendFormActions.init() ); - // linear action - // SessionStorageActions.clear(location.pathname); - } + // reset form to default + if (action.type === SEND.TX_COMPLETE) { + // dispatch( SendFormActions.init() ); + // linear action + // SessionStorageActions.clear(location.pathname); + } - // handle devices state change (from trezor-connect events or location change) - if (locationChange + // handle devices state change (from trezor-connect events or location change) + if (locationChange || prevState.accounts !== state.accounts || prevState.discovery !== state.discovery || prevState.tokens !== state.tokens || prevState.pending !== state.pending || prevState.web3 !== state.web3) { + if (locationChange) { + // dispose current account view + dispatch(dispose()); + } + const account = stateUtils.getSelectedAccount(state); + const network = stateUtils.getSelectedNetwork(state); + const discovery = stateUtils.getDiscoveryProcess(state); + const tokens = stateUtils.getAccountTokens(state, account); + const pending = stateUtils.getAccountPendingTx(state.pending, account); + const web3 = stateUtils.getWeb3(state); + + const payload: $ElementType = { + // location: location.pathname, + account, + network, + discovery, + tokens, + pending, + web3, + }; - if (locationChange) { - // dispose current account view - dispatch( dispose() ); - } - - const account = stateUtils.getSelectedAccount(state); - const network = stateUtils.getSelectedNetwork(state); - const discovery = stateUtils.getDiscoveryProcess(state); - const tokens = stateUtils.getAccountTokens(state, account); - const pending = stateUtils.getAccountPendingTx(state.pending, account); - const web3 = stateUtils.getWeb3(state); - - const payload: $ElementType = { - // location: location.pathname, - account, - network, - discovery, - tokens, - pending, - web3 - } - - let needUpdate: boolean = false; - Object.keys(payload).forEach((key) => { - if (Array.isArray(payload[key])) { - if (Array.isArray(state.selectedAccount[key]) && payload[key].length !== state.selectedAccount[key].length) { - needUpdate = true; - } - } else { - if (payload[key] !== state.selectedAccount[key]) { - needUpdate = true; - } + let needUpdate: boolean = false; + Object.keys(payload).forEach((key) => { + if (Array.isArray(payload[key])) { + if (Array.isArray(state.selectedAccount[key]) && payload[key].length !== state.selectedAccount[key].length) { + needUpdate = true; } - }) + } else if (payload[key] !== state.selectedAccount[key]) { + needUpdate = true; + } + }); - if (needUpdate) { - dispatch({ - type: ACCOUNT.UPDATE_SELECTED_ACCOUNT, - payload, - }); + if (needUpdate) { + dispatch({ + type: ACCOUNT.UPDATE_SELECTED_ACCOUNT, + payload, + }); - // initialize SendFormReducer - if (location.state.send && getState().sendForm.currency === "") { - dispatch( SendFormActions.init() ); - } + // initialize SendFormReducer + if (location.state.send && getState().sendForm.currency === '') { + dispatch(SendFormActions.init()); + } - if (location.state.send) { - const rejectedTxs = pending.filter(tx => tx.rejected); - rejectedTxs.forEach(tx => { - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: "warning", - title: "Pending transaction rejected", - message: `Transaction with id: ${ tx.id } not found.`, - cancelable: true, - actions: [ - { - label: 'OK', - callback: () => { - dispatch({ - type: PENDING.TX_RESOLVED, - tx, - }); - } - } - ] - } - }) + if (location.state.send) { + const rejectedTxs = pending.filter(tx => tx.rejected); + rejectedTxs.forEach((tx) => { + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'warning', + title: 'Pending transaction rejected', + message: `Transaction with id: ${tx.id} not found.`, + cancelable: true, + actions: [ + { + label: 'OK', + callback: () => { + dispatch({ + type: PENDING.TX_RESOLVED, + tx, + }); + }, + }, + ], + }, }); - } + }); } } } -} +}; -export const dispose = (): Action => { - return { - type: ACCOUNT.DISPOSE - } -} \ No newline at end of file +export const dispose = (): Action => ({ + type: ACCOUNT.DISPOSE, +}); \ No newline at end of file diff --git a/src/js/actions/SendFormActions.js b/src/js/actions/SendFormActions.js index aca7959f..e1e6a5e7 100644 --- a/src/js/actions/SendFormActions.js +++ b/src/js/actions/SendFormActions.js @@ -1,20 +1,17 @@ /* @flow */ -'use strict'; -import * as SEND from './constants/send'; -import * as NOTIFICATION from './constants/notification'; - -import * as SessionStorageActions from './SessionStorageActions'; - -import { estimateGas, getGasPrice, pushTx } from './Web3Actions'; import EthereumjsUtil from 'ethereumjs-util'; import EthereumjsUnits from 'ethereumjs-units'; import EthereumjsTx from 'ethereumjs-tx'; import TrezorConnect from 'trezor-connect'; -import { strip } from '../utils/ethUtils'; import { push } from 'react-router-redux'; import BigNumber from 'bignumber.js'; +import { strip } from '../utils/ethUtils'; +import { estimateGas, getGasPrice, pushTx } from './Web3Actions'; +import * as SessionStorageActions from './SessionStorageActions'; +import * as NOTIFICATION from './constants/notification'; +import * as SEND from './constants/send'; import { initialState } from '../reducers/SendFormReducer'; import { findAccount } from '../reducers/AccountsReducer'; @@ -22,7 +19,7 @@ import { findToken } from '../reducers/TokensReducer'; import { findDevice } from '../reducers/utils'; import * as stateUtils from '../reducers/utils'; -import type { +import type { PendingTx, Dispatch, GetState, @@ -30,7 +27,7 @@ import type { ThunkAction, AsyncAction, RouterLocationState, - TrezorDevice + TrezorDevice, } from '~/flowtype'; import type { State as AccountState } from '../reducers/SelectedAccountReducer'; import type { Web3Instance } from '../reducers/Web3Reducer'; @@ -124,19 +121,19 @@ const numberRegExp: RegExp = new RegExp('^(0|0\\.([0-9]+)?|[1-9][0-9]*\\.?([0-9] export const calculateFee = (gasPrice: string, gasLimit: string): string => { try { - return EthereumjsUnits.convert( new BigNumber(gasPrice).times(gasLimit), 'gwei', 'ether'); + return EthereumjsUnits.convert(new BigNumber(gasPrice).times(gasLimit), 'gwei', 'ether'); } catch (error) { return '0'; } -} +}; export const calculateTotal = (amount: string, gasPrice: string, gasLimit: string): string => { try { - return new BigNumber(amount).plus( calculateFee(gasPrice, gasLimit) ).toString(10); + return new BigNumber(amount).plus(calculateFee(gasPrice, gasLimit)).toString(10); } catch (error) { return '0'; } -} +}; export const calculateMaxAmount = (balance: BigNumber, gasPrice: string, gasLimit: string): string => { try { @@ -148,8 +145,7 @@ export const calculateMaxAmount = (balance: BigNumber, gasPrice: string, gasLimi } catch (error) { return '0'; } - -} +}; export const calculate = (prevProps: Props, props: Props) => { const { @@ -166,14 +162,13 @@ export const calculate = (prevProps: Props, props: Props) => { // account balance // token balance // gasLimit, gasPrice changed - - // const shouldRecalculateAmount = + + // const shouldRecalculateAmount = // (prevProps.selectedAccount.account !== account) // || (prevProps.) - - - if (state.setMax) { + + if (state.setMax) { const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency, isToken); if (isToken) { @@ -192,160 +187,152 @@ export const calculate = (prevProps: Props, props: Props) => { state.total = calculateTotal(isToken ? '0' : state.amount, state.gasPrice, state.gasLimit); if (state.selectedFeeLevel.value === 'Custom') { - state.selectedFeeLevel.label = `${ calculateFee(state.gasPrice, state.gasLimit) } ${ state.networkSymbol }`; + state.selectedFeeLevel.label = `${calculateFee(state.gasPrice, state.gasLimit)} ${state.networkSymbol}`; state.selectedFeeLevel.gasPrice = state.gasPrice; } -} +}; export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLimit: string, selected?: FeeLevel): Array => { - const price: BigNumber = typeof gasPrice === 'string' ? new BigNumber(gasPrice) : gasPrice + const price: BigNumber = typeof gasPrice === 'string' ? new BigNumber(gasPrice) : gasPrice; const quarter: BigNumber = price.dividedBy(4); const high: string = price.plus(quarter.times(2)).toString(10); const low: string = price.minus(quarter.times(2)).toString(10); - + const customLevel: FeeLevel = selected && selected.value === 'Custom' ? { value: 'Custom', - gasPrice: selected.gasPrice, + gasPrice: selected.gasPrice, // label: `${ calculateFee(gasPrice, gasLimit) } ${ symbol }` - label: `${ calculateFee(selected.gasPrice, gasLimit) } ${ symbol }` + label: `${calculateFee(selected.gasPrice, gasLimit)} ${symbol}`, } : { value: 'Custom', gasPrice: low, - label: '' - } + label: '', + }; return [ - { + { value: 'High', gasPrice: high, - label: `${ calculateFee(high, gasLimit) } ${ symbol }` + label: `${calculateFee(high, gasLimit)} ${symbol}`, }, - { + { value: 'Normal', gasPrice: gasPrice.toString(), - label: `${ calculateFee(price.toString(10), gasLimit) } ${ symbol }` + label: `${calculateFee(price.toString(10), gasLimit)} ${symbol}`, }, - { + { value: 'Low', gasPrice: low, - label: `${ calculateFee(low, gasLimit) } ${ symbol }` + label: `${calculateFee(low, gasLimit)} ${symbol}`, }, - customLevel - ] -} + customLevel, + ]; +}; // initialize component -export const init = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const { - account, - network, - web3 - } = getState().selectedAccount; - - if (!account || !network || !web3) return; - - const stateFromStorage = SessionStorageActions.load( getState().router.location.pathname ); - if (stateFromStorage) { - dispatch({ - type: SEND.INIT, - state: stateFromStorage - }); - return; - } - - // TODO: check if there are some unfinished tx in localStorage - - const gasPrice: BigNumber = new BigNumber( EthereumjsUnits.convert(web3.gasPrice, 'wei', 'gwei') ) || new BigNumber(network.defaultGasPrice); - const gasLimit: string = network.defaultGasLimit.toString(); - const feeLevels: Array = getFeeLevels(network.symbol, gasPrice, gasLimit); - - // TODO: get nonce - // TODO: LOAD DATA FROM SESSION STORAGE +export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const { + account, + network, + web3, + } = getState().selectedAccount; - const state: State = { - ...initialState, - networkName: network.network, - networkSymbol: network.symbol, - currency: network.symbol, - feeLevels, - selectedFeeLevel: feeLevels.find(f => f.value === 'Normal'), - recommendedGasPrice: gasPrice.toString(), - gasLimit, - gasPrice: gasPrice.toString(), - }; + if (!account || !network || !web3) return; + const stateFromStorage = SessionStorageActions.load(getState().router.location.pathname); + if (stateFromStorage) { dispatch({ type: SEND.INIT, - state + state: stateFromStorage, }); + return; } -} -export const toggleAdvanced = (address: string): Action => { - return { - type: SEND.TOGGLE_ADVANCED - } -} + // TODO: check if there are some unfinished tx in localStorage + + const gasPrice: BigNumber = new BigNumber(EthereumjsUnits.convert(web3.gasPrice, 'wei', 'gwei')) || new BigNumber(network.defaultGasPrice); + const gasLimit: string = network.defaultGasLimit.toString(); + const feeLevels: Array = getFeeLevels(network.symbol, gasPrice, gasLimit); + + // TODO: get nonce + // TODO: LOAD DATA FROM SESSION STORAGE + + const state: State = { + ...initialState, + networkName: network.network, + networkSymbol: network.symbol, + currency: network.symbol, + feeLevels, + selectedFeeLevel: feeLevels.find(f => f.value === 'Normal'), + recommendedGasPrice: gasPrice.toString(), + gasLimit, + gasPrice: gasPrice.toString(), + }; + + dispatch({ + type: SEND.INIT, + state, + }); +}; +export const toggleAdvanced = (address: string): Action => ({ + type: SEND.TOGGLE_ADVANCED, +}); -const addressValidation = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const { - account, - network, - tokens, - } = getState().selectedAccount; - if (!account || !network) return; - - const state: State = getState().sendForm; - const infos = { ...state.infos }; - const warnings = { ...state.warnings }; - - - if (state.untouched || !state.touched.address) return; - - const savedAccounts = getState().accounts.filter(a => a.address.toLowerCase() === state.address.toLowerCase()); - if (savedAccounts.length > 0) { - // check if found account belongs to this network - // corner-case: when same derivation path is used on different networks - const currentNetworkAccount = savedAccounts.find(a => a.network === network.network); - if (currentNetworkAccount) { - const device: ?TrezorDevice = findDevice(getState().devices, currentNetworkAccount.deviceID, currentNetworkAccount.deviceState); - if (device) { - infos.address = `${ device.instanceLabel } Account #${ (currentNetworkAccount.index + 1) }`; - } - } else { - const otherNetworkAccount = savedAccounts[0]; - const device: ?TrezorDevice = findDevice(getState().devices, otherNetworkAccount.deviceID, otherNetworkAccount.deviceState); - const coins = getState().localStorage.config.coins; - const otherNetwork: ?Coin = coins.find(c => c.network === otherNetworkAccount.network) - if (device && otherNetwork) { - warnings.address = `Looks like it's ${ device.instanceLabel } Account #${ (otherNetworkAccount.index + 1) } address of ${ otherNetwork.name } network`; - } + +const addressValidation = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const { + account, + network, + tokens, + } = getState().selectedAccount; + if (!account || !network) return; + + const state: State = getState().sendForm; + const infos = { ...state.infos }; + const warnings = { ...state.warnings }; + + + if (state.untouched || !state.touched.address) return; + + const savedAccounts = getState().accounts.filter(a => a.address.toLowerCase() === state.address.toLowerCase()); + if (savedAccounts.length > 0) { + // check if found account belongs to this network + // corner-case: when same derivation path is used on different networks + const currentNetworkAccount = savedAccounts.find(a => a.network === network.network); + if (currentNetworkAccount) { + const device: ?TrezorDevice = findDevice(getState().devices, currentNetworkAccount.deviceID, currentNetworkAccount.deviceState); + if (device) { + infos.address = `${device.instanceLabel} Account #${(currentNetworkAccount.index + 1)}`; } } else { - delete warnings.address; - delete infos.address; - } - - dispatch({ - type: SEND.ADDRESS_VALIDATION, - state: { - ...state, - infos, - warnings + const otherNetworkAccount = savedAccounts[0]; + const device: ?TrezorDevice = findDevice(getState().devices, otherNetworkAccount.deviceID, otherNetworkAccount.deviceState); + const coins = getState().localStorage.config.coins; + const otherNetwork: ?Coin = coins.find(c => c.network === otherNetworkAccount.network); + if (device && otherNetwork) { + warnings.address = `Looks like it's ${device.instanceLabel} Account #${(otherNetworkAccount.index + 1)} address of ${otherNetwork.name} network`; } - }) + } + } else { + delete warnings.address; + delete infos.address; } -} + + dispatch({ + type: SEND.ADDRESS_VALIDATION, + state: { + ...state, + infos, + warnings, + }, + }); +}; export const validation = (props: Props): void => { - const { account, network, @@ -388,7 +375,6 @@ export const validation = (props: Props): void => { } else if (state.amount.length > 0 && !state.amount.match(numberRegExp)) { errors.amount = 'Amount is not a number'; } else { - let decimalRegExp: RegExp; const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency, state.currency !== state.networkSymbol); @@ -397,34 +383,33 @@ export const validation = (props: Props): void => { if (token) { if (parseInt(token.decimals) > 0) { //decimalRegExp = new RegExp('^(0|0\\.([0-9]{0,' + token.decimals + '})?|[1-9]+\\.?([0-9]{0,' + token.decimals + '})?|\\.[0-9]{1,' + token.decimals + '})$'); - decimalRegExp = new RegExp('^(0|0\\.([0-9]{0,' + token.decimals + '})?|[1-9][0-9]*\\.?([0-9]{0,' + token.decimals + '})?|\\.[0-9]{1,' + token.decimals + '})$'); + decimalRegExp = new RegExp(`^(0|0\\.([0-9]{0,${token.decimals}})?|[1-9][0-9]*\\.?([0-9]{0,${token.decimals}})?|\\.[0-9]{1,${token.decimals}})$`); } else { // decimalRegExp = new RegExp('^(0|0\\.?|[1-9]+\\.?)$'); decimalRegExp = new RegExp('^[0-9]+$'); } if (!state.amount.match(decimalRegExp)) { - errors.amount = `Maximum ${ token.decimals } decimals allowed`; + errors.amount = `Maximum ${token.decimals} decimals allowed`; } else if (new BigNumber(state.total).greaterThan(account.balance)) { - errors.amount = `Not enough ${ state.networkSymbol } to cover transaction fee`; - } else if (new BigNumber(state.amount).greaterThan( new BigNumber(token.balance).minus(pendingAmount) )) { + errors.amount = `Not enough ${state.networkSymbol} to cover transaction fee`; + } else if (new BigNumber(state.amount).greaterThan(new BigNumber(token.balance).minus(pendingAmount))) { errors.amount = 'Not enough funds'; } else if (new BigNumber(state.amount).lessThanOrEqualTo('0')) { errors.amount = 'Amount is too low'; } } - } else { decimalRegExp = new RegExp('^(0|0\\.([0-9]{0,18})?|[1-9][0-9]*\\.?([0-9]{0,18})?|\\.[0-9]{0,18})$'); if (!state.amount.match(decimalRegExp)) { - errors.amount = `Maximum 18 decimals allowed`; - } else if (new BigNumber(state.total).greaterThan( new BigNumber(account.balance).minus(pendingAmount) )) { + errors.amount = 'Maximum 18 decimals allowed'; + } else if (new BigNumber(state.total).greaterThan(new BigNumber(account.balance).minus(pendingAmount))) { errors.amount = 'Not enough funds'; } } } } - + // valid gas limit if (state.touched.gasLimit) { if (state.gasLimit.length < 1) { @@ -435,7 +420,7 @@ export const validation = (props: Props): void => { const gl: BigNumber = new BigNumber(state.gasLimit); if (gl.lessThan(1)) { errors.gasLimit = 'Gas limit is too low'; - } else if (gl.lessThan( state.currency !== state.networkSymbol ? network.defaultGasLimitTokens : network.defaultGasLimit )) { + } else if (gl.lessThan(state.currency !== state.networkSymbol ? network.defaultGasLimitTokens : network.defaultGasLimit)) { warnings.gasLimit = 'Gas limit is below recommended'; } } @@ -487,483 +472,446 @@ export const validation = (props: Props): void => { state.errors = errors; state.warnings = warnings; state.infos = infos; +}; -} - - - - -export const onAddressChange = (address: string): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const state: State = getState().sendForm; - const touched = { ...state.touched }; - touched.address = true; - - dispatch({ - type: SEND.ADDRESS_CHANGE, - state: { - ...state, - untouched: false, - touched, - address - } - }); - - dispatch( addressValidation() ); - } -} -export const onAmountChange = (amount: string): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const state = getState().sendForm; - const touched = { ...state.touched }; - touched.amount = true; +export const onAddressChange = (address: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state: State = getState().sendForm; + const touched = { ...state.touched }; + touched.address = true; - dispatch({ - type: SEND.AMOUNT_CHANGE, - state: { - ...state, - untouched: false, - touched, - setMax: false, - amount, - } - }); - } -} + dispatch({ + type: SEND.ADDRESS_CHANGE, + state: { + ...state, + untouched: false, + touched, + address, + }, + }); -export const onCurrencyChange = (currency: { value: string, label: string }): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const { - account, - network - } = getState().selectedAccount; - if (!account || !network) return; - - const currentState: State = getState().sendForm; - const isToken: boolean = currency.value !== currentState.networkSymbol; - const gasLimit: string = isToken ? network.defaultGasLimitTokens.toString() : network.defaultGasLimit.toString(); - - const feeLevels: Array = getFeeLevels(network.symbol, currentState.recommendedGasPrice, gasLimit, currentState.selectedFeeLevel); - const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value); - if (!selectedFeeLevel) return; - - const state: State = { - ...currentState, - currency: currency.value, - // amount, - // total, - feeLevels, - selectedFeeLevel, - gasLimit, - }; + dispatch(addressValidation()); +}; - dispatch({ - type: SEND.CURRENCY_CHANGE, - state - }); - } -} +export const onAmountChange = (amount: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state = getState().sendForm; + const touched = { ...state.touched }; + touched.amount = true; -export const onSetMax = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const state = getState().sendForm; - const touched = { ...state.touched }; - touched.amount = true; + dispatch({ + type: SEND.AMOUNT_CHANGE, + state: { + ...state, + untouched: false, + touched, + setMax: false, + amount, + }, + }); +}; - dispatch({ - type: SEND.SET_MAX, - state: { - ...state, - untouched: false, - touched, - setMax: !state.setMax, - } - }); - } -} +export const onCurrencyChange = (currency: { value: string, label: string }): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const { + account, + network, + } = getState().selectedAccount; + if (!account || !network) return; -export const onFeeLevelChange = (feeLevel: FeeLevel): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const { - network - } = getState().selectedAccount; - if (!network) return; + const currentState: State = getState().sendForm; + const isToken: boolean = currency.value !== currentState.networkSymbol; + const gasLimit: string = isToken ? network.defaultGasLimitTokens.toString() : network.defaultGasLimit.toString(); + + const feeLevels: Array = getFeeLevels(network.symbol, currentState.recommendedGasPrice, gasLimit, currentState.selectedFeeLevel); + const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value); + if (!selectedFeeLevel) return; + + const state: State = { + ...currentState, + currency: currency.value, + // amount, + // total, + feeLevels, + selectedFeeLevel, + gasLimit, + }; + + dispatch({ + type: SEND.CURRENCY_CHANGE, + state, + }); +}; - const currentState: State = getState().sendForm; - const isToken: boolean = currentState.currency !== currentState.networkSymbol; +export const onSetMax = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state = getState().sendForm; + const touched = { ...state.touched }; + touched.amount = true; - const state: State = { - ...currentState, + dispatch({ + type: SEND.SET_MAX, + state: { + ...state, untouched: false, - selectedFeeLevel: feeLevel, - }; + touched, + setMax: !state.setMax, + }, + }); +}; - if (feeLevel.value === 'Custom') { - state.advanced = true; - feeLevel.gasPrice = state.gasPrice; - feeLevel.label = `${ calculateFee(state.gasPrice, state.gasLimit) } ${ state.networkSymbol }`; +export const onFeeLevelChange = (feeLevel: FeeLevel): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const { + network, + } = getState().selectedAccount; + if (!network) return; + + const currentState: State = getState().sendForm; + const isToken: boolean = currentState.currency !== currentState.networkSymbol; + + const state: State = { + ...currentState, + untouched: false, + selectedFeeLevel: feeLevel, + }; + + if (feeLevel.value === 'Custom') { + state.advanced = true; + feeLevel.gasPrice = state.gasPrice; + feeLevel.label = `${calculateFee(state.gasPrice, state.gasLimit)} ${state.networkSymbol}`; + } else { + const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom'); + if (customLevel) customLevel.label = ''; + state.gasPrice = feeLevel.gasPrice; + if (isToken) { + state.gasLimit = network.defaultGasLimitTokens.toString(); } else { - const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom'); - if (customLevel) - customLevel.label = ''; - state.gasPrice = feeLevel.gasPrice; - if (isToken) { - state.gasLimit = network.defaultGasLimitTokens.toString() - } else { - state.gasLimit = state.data.length > 0 ? state.gasLimit : network.defaultGasLimit.toString(); - } + state.gasLimit = state.data.length > 0 ? state.gasLimit : network.defaultGasLimit.toString(); } - - dispatch({ - type: SEND.FEE_LEVEL_CHANGE, - state - }); } -} + + dispatch({ + type: SEND.FEE_LEVEL_CHANGE, + state, + }); +}; // Manually triggered from user // Update gasPrice to recommended value -export const updateFeeLevels = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const { - account, - network - } = getState().selectedAccount; - if (!account || !network) return; - - const currentState: State = getState().sendForm; - const isToken: boolean = currentState.currency !== currentState.networkSymbol; - let gasLimit: string = isToken ? network.defaultGasLimitTokens.toString() : network.defaultGasLimit.toString(); - - // override custom settings - if (currentState.selectedFeeLevel.value === 'Custom') { - // update only gasPrice - currentState.selectedFeeLevel.gasPrice = currentState.recommendedGasPrice; - // leave gas limit as it was - gasLimit = currentState.gasLimit; - } - - const feeLevels: Array = getFeeLevels(network.symbol, currentState.recommendedGasPrice, gasLimit, currentState.selectedFeeLevel); - const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value); - if (!selectedFeeLevel) return; - - const state: State = { - ...currentState, - feeLevels, - selectedFeeLevel, - gasPrice: selectedFeeLevel.gasPrice, - gasPriceNeedsUpdate: false, - }; +export const updateFeeLevels = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const { + account, + network, + } = getState().selectedAccount; + if (!account || !network) return; - dispatch({ - type: SEND.UPDATE_FEE_LEVELS, - state - }); + const currentState: State = getState().sendForm; + const isToken: boolean = currentState.currency !== currentState.networkSymbol; + let gasLimit: string = isToken ? network.defaultGasLimitTokens.toString() : network.defaultGasLimit.toString(); + + // override custom settings + if (currentState.selectedFeeLevel.value === 'Custom') { + // update only gasPrice + currentState.selectedFeeLevel.gasPrice = currentState.recommendedGasPrice; + // leave gas limit as it was + gasLimit = currentState.gasLimit; } -} -export const onGasPriceChange = (gasPrice: string): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const currentState: State = getState().sendForm; - const isToken: boolean = currentState.currency !== currentState.networkSymbol; + const feeLevels: Array = getFeeLevels(network.symbol, currentState.recommendedGasPrice, gasLimit, currentState.selectedFeeLevel); + const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value); + if (!selectedFeeLevel) return; + + const state: State = { + ...currentState, + feeLevels, + selectedFeeLevel, + gasPrice: selectedFeeLevel.gasPrice, + gasPriceNeedsUpdate: false, + }; + + dispatch({ + type: SEND.UPDATE_FEE_LEVELS, + state, + }); +}; - const touched = { ...currentState.touched }; - touched.gasPrice = true; +export const onGasPriceChange = (gasPrice: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const currentState: State = getState().sendForm; + const isToken: boolean = currentState.currency !== currentState.networkSymbol; - const state: State = { - ...currentState, - untouched: false, - touched, - gasPrice: gasPrice, - }; + const touched = { ...currentState.touched }; + touched.gasPrice = true; - if (currentState.selectedFeeLevel.value !== 'Custom') { - const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); - if (!customLevel) return; - state.selectedFeeLevel = customLevel; - } + const state: State = { + ...currentState, + untouched: false, + touched, + gasPrice, + }; - dispatch({ - type: SEND.GAS_PRICE_CHANGE, - state - }); + if (currentState.selectedFeeLevel.value !== 'Custom') { + const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); + if (!customLevel) return; + state.selectedFeeLevel = customLevel; } -} -export const onGasLimitChange = (gasLimit: string, updateFeeLevels: boolean = false): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const currentState: State = getState().sendForm; - const isToken: boolean = currentState.currency !== currentState.networkSymbol; + dispatch({ + type: SEND.GAS_PRICE_CHANGE, + state, + }); +}; - const touched = { ...currentState.touched }; - touched.gasLimit = true; +export const onGasLimitChange = (gasLimit: string, updateFeeLevels: boolean = false): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const currentState: State = getState().sendForm; + const isToken: boolean = currentState.currency !== currentState.networkSymbol; + + const touched = { ...currentState.touched }; + touched.gasLimit = true; + + const state: State = { + ...currentState, + calculatingGasLimit: false, + untouched: false, + touched, + gasLimit, + }; + + if (currentState.selectedFeeLevel.value !== 'Custom') { + const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); + if (!customLevel) return; + state.selectedFeeLevel = customLevel; + } - const state: State = { - ...currentState, - calculatingGasLimit: false, - untouched: false, - touched, - gasLimit, - }; + dispatch({ + type: SEND.GAS_LIMIT_CHANGE, + state, + }); +}; - if (currentState.selectedFeeLevel.value !== 'Custom') { - const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); - if (!customLevel) return; - state.selectedFeeLevel = customLevel; - } +export const onNonceChange = (nonce: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const currentState: State = getState().sendForm; + const touched = { ...currentState.touched }; + touched.nonce = true; + + const state: State = { + ...currentState, + untouched: false, + touched, + nonce, + }; + + dispatch({ + type: SEND.NONCE_CHANGE, + state, + }); +}; - dispatch({ - type: SEND.GAS_LIMIT_CHANGE, - state - }); +export const onDataChange = (data: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const currentState: State = getState().sendForm; + const touched = { ...currentState.touched }; + touched.data = true; + + const state: State = { + ...currentState, + calculatingGasLimit: true, + untouched: false, + touched, + data, + }; + + if (currentState.selectedFeeLevel.value !== 'Custom') { + const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); + if (!customLevel) return; + state.selectedFeeLevel = customLevel; } -} -export const onNonceChange = (nonce: string): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const currentState: State = getState().sendForm; - const touched = { ...currentState.touched }; - touched.nonce = true; + dispatch({ + type: SEND.DATA_CHANGE, + state, + }); - const state: State = { - ...currentState, - untouched: false, - touched, - nonce, - }; + dispatch(estimateGasPrice()); +}; - dispatch({ - type: SEND.NONCE_CHANGE, - state - }); - } -} -export const onDataChange = (data: string): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const currentState: State = getState().sendForm; - const touched = { ...currentState.touched }; - touched.data = true; +const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const { + web3, + network, + } = getState().selectedAccount; + if (!web3 || !network) return; - const state: State = { - ...currentState, - calculatingGasLimit: true, - untouched: false, - touched, - data, - }; + const w3 = web3.web3; - if (currentState.selectedFeeLevel.value !== 'Custom') { - const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); - if (!customLevel) return; - state.selectedFeeLevel = customLevel; - } + const state: State = getState().sendForm; + const requestedData = state.data; - dispatch({ - type: SEND.DATA_CHANGE, - state - }); + const re = /^[0-9A-Fa-f]+$/g; + if (!re.test(requestedData)) { + // to stop calculating + dispatch(onGasLimitChange(requestedData.length > 0 ? state.gasLimit : network.defaultGasLimit.toString())); + return; + } - dispatch( estimateGasPrice() ); + if (state.data.length < 1) { + // set default + dispatch(onGasLimitChange(network.defaultGasLimit.toString())); + return; } -} + // TODO: allow data starting with 0x ... + const data: string = `0x${state.data.length % 2 === 0 ? state.data : `0${state.data}`}`; + const gasLimit = await estimateGas(w3, { + to: '0x0000000000000000000000000000000000000000', + data, + value: w3.toHex(w3.toWei(state.amount, 'ether')), + gasPrice: w3.toHex(EthereumjsUnits.convert(state.gasPrice, 'gwei', 'wei')), + }); + + if (getState().sendForm.data === requestedData) { + dispatch(onGasLimitChange(gasLimit.toString())); + } +}; -const estimateGasPrice = (): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { +export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const { + account, + network, + web3, + pending, + } = getState().selectedAccount; + if (!account || !web3 || !network) return; - const { - web3, - network - } = getState().selectedAccount; - if (!web3 || !network) return; + const currentState: State = getState().sendForm; - const w3 = web3.web3; + const isToken: boolean = currentState.currency !== currentState.networkSymbol; + const w3 = web3.web3; - const state: State = getState().sendForm; - const requestedData = state.data; + const address_n = account.addressPath; - const re = /^[0-9A-Fa-f]+$/g; - if (!re.test(requestedData)) { - // to stop calculating - dispatch( onGasLimitChange(requestedData.length > 0 ? state.gasLimit : network.defaultGasLimit.toString()) ); - return; - } + let data: string = `0x${currentState.data}`; + let txAmount: string = w3.toHex(w3.toWei(currentState.amount, 'ether')); + let txAddress: string = currentState.address; + if (isToken) { + const token: ?Token = findToken(getState().tokens, account.address, currentState.currency, account.deviceState); + if (!token) return; - if (state.data.length < 1) { - // set default - dispatch( onGasLimitChange(network.defaultGasLimit.toString()) ); - return; - } + const contract = web3.erc20.at(token.address); + const amountValue: string = new BigNumber(currentState.amount).times(Math.pow(10, token.decimals)).toString(10); - // TODO: allow data starting with 0x ... - const data: string = '0x' + (state.data.length % 2 === 0 ? state.data : '0' + state.data); - const gasLimit = await estimateGas(w3, { - to: '0x0000000000000000000000000000000000000000', - data, - value: w3.toHex(w3.toWei(state.amount, 'ether')), - gasPrice: w3.toHex( EthereumjsUnits.convert(state.gasPrice, 'gwei', 'wei') ), + data = contract.transfer.getData(currentState.address, amountValue, { + from: account.address, + gasLimit: currentState.gasLimit, + gasPrice: currentState.gasPrice, }); - - if (getState().sendForm.data === requestedData) { - dispatch( onGasLimitChange(gasLimit.toString()) ); - } + txAmount = '0x00'; + txAddress = token.address; } - -} -export const onSend = (): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { + const pendingNonce: number = stateUtils.getPendingNonce(pending); + const nonce = pendingNonce > 0 && pendingNonce >= account.nonce ? pendingNonce : account.nonce; + + console.warn('NONCE', nonce, account.nonce, pendingNonce); + + const txData = { + address_n, + // from: currentAddress.address + to: txAddress, + value: txAmount, + data, + chainId: web3.chainId, + nonce: w3.toHex(nonce), + gasLimit: w3.toHex(currentState.gasLimit), + gasPrice: w3.toHex(EthereumjsUnits.convert(currentState.gasPrice, 'gwei', 'wei')), + r: '', + s: '', + v: '', + }; + + const selected: ?TrezorDevice = getState().wallet.selectedDevice; + if (!selected) return; + + const signedTransaction = await TrezorConnect.ethereumSignTransaction({ + device: { + path: selected.path, + instance: selected.instance, + state: selected.state, + }, + useEmptyPassphrase: !selected.instance, + path: txData.address_n, + nonce: strip(txData.nonce), + gasPrice: strip(txData.gasPrice), + gasLimit: strip(txData.gasLimit), + to: strip(txData.to), + value: strip(txData.value), + data: strip(txData.data), + chainId: txData.chainId, + }); + + if (!signedTransaction || !signedTransaction.success) { + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Transaction error', + message: signedTransaction.payload.error, + cancelable: true, + actions: [], + }, + }); + return; + } - const { - account, - network, - web3, - pending - } = getState().selectedAccount; - if (!account || !web3 || !network) return; - - const currentState: State = getState().sendForm; - - const isToken: boolean = currentState.currency !== currentState.networkSymbol; - const w3 = web3.web3; - - const address_n = account.addressPath; - - let data: string = '0x' + currentState.data; - let txAmount: string = w3.toHex(w3.toWei(currentState.amount, 'ether')); - let txAddress: string = currentState.address; - if (isToken) { - const token: ?Token = findToken(getState().tokens, account.address, currentState.currency, account.deviceState); - if (!token) return; - - const contract = web3.erc20.at(token.address); - const amountValue: string = new BigNumber(currentState.amount).times( Math.pow(10, token.decimals) ).toString(10); - - data = contract.transfer.getData(currentState.address, amountValue, { - from: account.address, - gasLimit: currentState.gasLimit, - gasPrice: currentState.gasPrice - }); - txAmount = '0x00'; - txAddress = token.address; - } + txData.r = `0x${signedTransaction.payload.r}`; + txData.s = `0x${signedTransaction.payload.s}`; + txData.v = w3.toHex(signedTransaction.payload.v); - const pendingNonce: number = stateUtils.getPendingNonce(pending); - const nonce = pendingNonce > 0 && pendingNonce >= account.nonce ? pendingNonce : account.nonce; - - console.warn("NONCE", nonce, account.nonce, pendingNonce) - - const txData = { - address_n, - // from: currentAddress.address - to: txAddress, - value: txAmount, - data, - chainId: web3.chainId, - nonce: w3.toHex(nonce), - gasLimit: w3.toHex(currentState.gasLimit), - gasPrice: w3.toHex( EthereumjsUnits.convert(currentState.gasPrice, 'gwei', 'wei') ), - r: '', - s: '', - v: '' - } - const selected: ?TrezorDevice = getState().wallet.selectedDevice; - if (!selected) return; + try { + const tx = new EthereumjsTx(txData); + const serializedTx = `0x${tx.serialize().toString('hex')}`; + const txid: string = await pushTx(w3, serializedTx); - let signedTransaction = await TrezorConnect.ethereumSignTransaction({ - device: { - path: selected.path, - instance: selected.instance, - state: selected.state - }, - useEmptyPassphrase: !selected.instance, - path: txData.address_n, - nonce: strip(txData.nonce), - gasPrice: strip(txData.gasPrice), - gasLimit: strip(txData.gasLimit), - to: strip(txData.to), - value: strip(txData.value), - data: strip(txData.data), - chainId: txData.chainId + dispatch({ + type: SEND.TX_COMPLETE, + account, + selectedCurrency: currentState.currency, + amount: currentState.amount, + total: currentState.total, + tx, + nonce, + txid, + txData, }); - if (!signedTransaction || !signedTransaction.success) { + // clear session storage + dispatch(SessionStorageActions.clear()); - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Transaction error', - message: signedTransaction.payload.error, - cancelable: true, - actions: [ ] - } - }) - return; - } + // reset form + dispatch(init()); - txData.r = '0x' + signedTransaction.payload.r; - txData.s = '0x' + signedTransaction.payload.s; - txData.v = w3.toHex(signedTransaction.payload.v); - - - - try { - const tx = new EthereumjsTx(txData); - const serializedTx = '0x' + tx.serialize().toString('hex'); - const txid: string = await pushTx(w3, serializedTx); - - dispatch({ - type: SEND.TX_COMPLETE, - account: account, - selectedCurrency: currentState.currency, - amount: currentState.amount, - total: currentState.total, - tx, - nonce, - txid, - txData, - }); - - // clear session storage - dispatch( SessionStorageActions.clear() ); - - // reset form - dispatch( init() ); - - - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'success', - title: 'Transaction success', - message: `See transaction detail`, - cancelable: true, - actions: [] - } - }); - - } catch (error) { - - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Transaction error', - message: error.message || error, - cancelable: true, - actions: [ ] - } - }); - } + + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'success', + title: 'Transaction success', + message: `See transaction detail`, + cancelable: true, + actions: [], + }, + }); + } catch (error) { + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Transaction error', + message: error.message || error, + cancelable: true, + actions: [], + }, + }); } -} +}; export default { toggleAdvanced, @@ -978,4 +926,4 @@ export default { onNonceChange, onDataChange, onSend, -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/js/actions/SessionStorageActions.js b/src/js/actions/SessionStorageActions.js index a7fe9526..5aeed2b6 100644 --- a/src/js/actions/SessionStorageActions.js +++ b/src/js/actions/SessionStorageActions.js @@ -1,33 +1,30 @@ /* @flow */ -'use strict'; + import type { State as SendFormState } from '../reducers/SendFormReducer'; import type { ThunkAction, - GetState, + GetState, Dispatch, } from '~/flowtype'; const PREFIX: string = 'trezor:draft-tx:'; -export const save = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - if (typeof window.localStorage === 'undefined') return; - - const location = getState().router.location.pathname; - const state = getState().sendForm; - if (!state.untouched) { - try { - window.sessionStorage.setItem(`${PREFIX}${location}`, JSON.stringify(state) ); - } catch (error) { - console.error("Saving sessionStorage error: " + error) - } +export const save = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + if (typeof window.localStorage === 'undefined') return; + + const location = getState().router.location.pathname; + const state = getState().sendForm; + if (!state.untouched) { + try { + window.sessionStorage.setItem(`${PREFIX}${location}`, JSON.stringify(state)); + } catch (error) { + console.error(`Saving sessionStorage error: ${error}`); } } -} +}; export const load = (location: string): ?SendFormState => { - if (typeof window.localStorage === 'undefined') return; try { @@ -39,20 +36,16 @@ export const load = (location: string): ?SendFormState => { } return state; } catch (error) { - console.error("Loading sessionStorage error: " + error) + console.error(`Loading sessionStorage error: ${error}`); } +}; - return; -} - -export const clear = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - if (typeof window.localStorage === 'undefined') return; - const location = getState().router.location.pathname; - try { - window.sessionStorage.removeItem(`${PREFIX}${location}`); - } catch (error) { - console.error("Clearing sessionStorage error: " + error) - } +export const clear = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + if (typeof window.localStorage === 'undefined') return; + const location = getState().router.location.pathname; + try { + window.sessionStorage.removeItem(`${PREFIX}${location}`); + } catch (error) { + console.error(`Clearing sessionStorage error: ${error}`); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/js/actions/SummaryActions.js b/src/js/actions/SummaryActions.js index 05dee428..9d3d3c91 100644 --- a/src/js/actions/SummaryActions.js +++ b/src/js/actions/SummaryActions.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import EthereumjsUtil from 'ethereumjs-util'; import * as SUMMARY from './constants/summary'; @@ -7,7 +7,9 @@ import * as TOKEN from './constants/token'; import { resolveAfter } from '../utils/promiseUtils'; import { initialState } from '../reducers/SummaryReducer'; -import type { ThunkAction, AsyncAction, Action, GetState, Dispatch } from '~/flowtype'; +import type { + ThunkAction, AsyncAction, Action, GetState, Dispatch, +} from '~/flowtype'; import type { State } from '../reducers/SummaryReducer'; import type { Token } from '../reducers/TokensReducer'; @@ -20,29 +22,21 @@ export type SummaryAction = { type: typeof SUMMARY.DETAILS_TOGGLE } -export const init = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const state: State = { - ...initialState, - }; - - dispatch({ - type: SUMMARY.INIT, - state: state - }); - } -} +export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state: State = { + ...initialState, + }; -export const dispose = (): Action => { - return { - type: SUMMARY.DISPOSE - } -} + dispatch({ + type: SUMMARY.INIT, + state, + }); +}; -export const onDetailsToggle = (): Action => { - return { - type: SUMMARY.DETAILS_TOGGLE - } -} +export const dispose = (): Action => ({ + type: SUMMARY.DISPOSE, +}); +export const onDetailsToggle = (): Action => ({ + type: SUMMARY.DETAILS_TOGGLE, +}); diff --git a/src/js/actions/TokenActions.js b/src/js/actions/TokenActions.js index c6f37d9f..3918fdfa 100644 --- a/src/js/actions/TokenActions.js +++ b/src/js/actions/TokenActions.js @@ -1,10 +1,12 @@ /* @flow */ -'use strict'; + import * as TOKEN from './constants/token'; import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions'; -import type { GetState, AsyncAction, Action, Dispatch } from '~/flowtype'; +import type { + GetState, AsyncAction, Action, Dispatch, +} from '~/flowtype'; import type { State, Token } from '../reducers/TokensReducer'; import type { Account } from '../reducers/AccountsReducer'; import type { NetworkToken } from '../reducers/LocalStorageReducer'; @@ -29,86 +31,71 @@ type SelectOptions = { // action from component -export const load = (input: string, network: string): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - - if (input.length < 1) return; - - const tokens = getState().localStorage.tokens[ network ]; - const value = input.toLowerCase(); - const result = tokens.filter(t => - t.symbol.toLowerCase().indexOf(value) >= 0 || - t.address.toLowerCase().indexOf(value) >= 0 || - t.name.toLowerCase().indexOf(value) >= 0 - ); - - if (result.length > 0) { - return { options: result }; - } else { - const web3instance = getState().web3.find(w3 => w3.network === network); - if (!web3instance) return; - - const info = await getTokenInfoAsync(web3instance.erc20, input); - if (info) { - return { - options: [ info ] - } - } - //await resolveAfter(300000); - //await resolveAfter(3000); - - } - return; - } -} +export const load = (input: string, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + if (input.length < 1) return; -export const add = (token: NetworkToken, account: Account): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - - const web3instance = getState().web3.find(w3 => w3.network === account.network); - if (!web3instance) return; - - const tkn: Token = { - loaded: false, - deviceState: account.deviceState, - network: account.network, - name: token.name, - symbol: token.symbol, - address: token.address, - ethAddress: account.address, - decimals: token.decimals, - balance: '0' - } - - dispatch({ - type: TOKEN.ADD, - payload: tkn - }); - - const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, tkn); - dispatch( setBalance(token.address, account.address, tokenBalance) ) - } -} + const tokens = getState().localStorage.tokens[network]; + const value = input.toLowerCase(); + const result = tokens.filter(t => t.symbol.toLowerCase().indexOf(value) >= 0 + || t.address.toLowerCase().indexOf(value) >= 0 + || t.name.toLowerCase().indexOf(value) >= 0); -export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const newState: Array = [ ...getState().tokens ]; - let token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress); - if (token) { - token.loaded = true; - token.balance = balance; - } - - dispatch({ - type: TOKEN.SET_BALANCE, - payload: newState - }) + if (result.length > 0) { + return { options: result }; } -} - -export const remove = (token: Token): Action => { - return { - type: TOKEN.REMOVE, - token + const web3instance = getState().web3.find(w3 => w3.network === network); + if (!web3instance) return; + + const info = await getTokenInfoAsync(web3instance.erc20, input); + if (info) { + return { + options: [info], + }; + } + //await resolveAfter(300000); + //await resolveAfter(3000); +}; + +export const add = (token: NetworkToken, account: Account): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const web3instance = getState().web3.find(w3 => w3.network === account.network); + if (!web3instance) return; + + const tkn: Token = { + loaded: false, + deviceState: account.deviceState, + network: account.network, + name: token.name, + symbol: token.symbol, + address: token.address, + ethAddress: account.address, + decimals: token.decimals, + balance: '0', + }; + + dispatch({ + type: TOKEN.ADD, + payload: tkn, + }); + + const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, tkn); + dispatch(setBalance(token.address, account.address, tokenBalance)); +}; + +export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const newState: Array = [...getState().tokens]; + const token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress); + if (token) { + token.loaded = true; + token.balance = balance; } -} \ No newline at end of file + + dispatch({ + type: TOKEN.SET_BALANCE, + payload: newState, + }); +}; + +export const remove = (token: Token): Action => ({ + type: TOKEN.REMOVE, + token, +}); \ No newline at end of file diff --git a/src/js/actions/TrezorConnectActions.js b/src/js/actions/TrezorConnectActions.js index 97824034..72278921 100644 --- a/src/js/actions/TrezorConnectActions.js +++ b/src/js/actions/TrezorConnectActions.js @@ -1,7 +1,9 @@ /* @flow */ -'use strict'; -import TrezorConnect, { UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT } from 'trezor-connect'; + +import TrezorConnect, { + UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, +} from 'trezor-connect'; import * as TOKEN from './constants/token'; import * as CONNECT from './constants/TrezorConnect'; import * as NOTIFICATION from './constants/notification'; @@ -20,17 +22,17 @@ import type { TransportMessage, DeviceMessageType, TransportMessageType, - UiMessageType + UiMessageType, } from 'trezor-connect'; -import type { +import type { Dispatch, GetState, Action, ThunkAction, AsyncAction, TrezorDevice, - RouterLocationState + RouterLocationState, } from '~/flowtype'; @@ -81,301 +83,276 @@ export type TrezorConnectAction = { }; -export const init = (): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - // set listeners - TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => { - // post event to reducers - const type: DeviceMessageType = event.type; // assert flow type - dispatch({ - type, - device: event.payload - }); +export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + // set listeners + TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => { + // post event to reducers + const type: DeviceMessageType = event.type; // assert flow type + dispatch({ + type, + device: event.payload, }); + }); - TrezorConnect.on(UI_EVENT, (event: UiMessage): void => { - // post event to reducers - const type: UiMessageType = event.type; // assert flow type - dispatch({ - type, - payload: event.payload - }); + TrezorConnect.on(UI_EVENT, (event: UiMessage): void => { + // post event to reducers + const type: UiMessageType = event.type; // assert flow type + dispatch({ + type, + payload: event.payload, }); + }); - TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => { - // post event to reducers - const type: TransportMessageType = event.type; // assert flow type - dispatch({ - type, - payload: event.payload - }); + TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => { + // post event to reducers + const type: TransportMessageType = event.type; // assert flow type + dispatch({ + type, + payload: event.payload, }); + }); - try { - await TrezorConnect.init({ - transportReconnect: true, - // connectSrc: 'https://localhost:8088/', - connectSrc: 'https://sisyfos.trezor.io/', - debug: false, - popup: false, - webusb: true, - pendingTransportEvent: (getState().devices.length < 1) - }); - } catch (error) { - // dispatch({ - // type: CONNECT.INITIALIZATION_ERROR, - // error - // }) - } + try { + await TrezorConnect.init({ + transportReconnect: true, + // connectSrc: 'https://localhost:8088/', + connectSrc: 'https://sisyfos.trezor.io/', + debug: false, + popup: false, + webusb: true, + pendingTransportEvent: (getState().devices.length < 1), + }); + } catch (error) { + // dispatch({ + // type: CONNECT.INITIALIZATION_ERROR, + // error + // }) } -} +}; // called after backend was initialized // set listeners for connect/disconnect -export const postInit = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { +export const postInit = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const handleDeviceConnect = (device: Device) => { + dispatch(initConnectedDevice(device)); + }; - const handleDeviceConnect = (device: Device) => { - dispatch( initConnectedDevice(device) ); - } + TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect); + TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect); - TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect); - TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect); + TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect); + TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect); - TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect); - TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect); + const { devices } = getState(); - const { devices } = getState(); + const { initialPathname, initialParams } = getState().wallet; - const { initialPathname, initialParams } = getState().wallet; + if (initialPathname) { + dispatch({ + type: WALLET.SET_INITIAL_URL, + // pathname: null, + // params: null + }); + } - if (initialPathname) { - dispatch({ - type: WALLET.SET_INITIAL_URL, - // pathname: null, - // params: null - }); - } + if (devices.length > 0) { + const unacquired: ?TrezorDevice = devices.find(d => d.unacquired); + if (unacquired) { + dispatch(onSelectDevice(unacquired)); + } else { + const latest: Array = sortDevices(devices); + const firstConnected: ?TrezorDevice = latest.find(d => d.connected); + dispatch(onSelectDevice(firstConnected || latest[0])); + + // TODO + if (initialParams) { + if (!initialParams.hasOwnProperty('network') && initialPathname !== getState().router.location.pathname) { + // dispatch( push(initialPathname) ); + } else { - if (devices.length > 0) { - const unacquired: ?TrezorDevice = devices.find(d => d.unacquired); - if (unacquired) { - dispatch( onSelectDevice(unacquired) ); - } else { - const latest: Array = sortDevices(devices); - const firstConnected: ?TrezorDevice = latest.find(d => d.connected); - dispatch( onSelectDevice(firstConnected || latest[0]) ); - - // TODO - if (initialParams) { - if (!initialParams.hasOwnProperty("network") && initialPathname !== getState().router.location.pathname) { - // dispatch( push(initialPathname) ); - } else { - - } } } } } -} - -const sortDevices = (devices: Array): Array => { - return devices.sort((a, b) => { - if (!a.ts || !b.ts) { - return -1; - } else { - return a.ts > b.ts ? -1 : 1; - } - }); -} +}; -export const initConnectedDevice = (device: TrezorDevice | Device): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const selected = getState().wallet.selectedDevice; - // if (!selected || (selected && selected.state)) { - dispatch( onSelectDevice(device) ); - // } - // if (device.unacquired && selected && selected.path !== device.path && !selected.connected) { - // dispatch( onSelectDevice(device) ); - // } else if (!selected) { - // dispatch( onSelectDevice(device) ); - // } +const sortDevices = (devices: Array): Array => devices.sort((a, b) => { + if (!a.ts || !b.ts) { + return -1; } -} + return a.ts > b.ts ? -1 : 1; +}); + +export const initConnectedDevice = (device: TrezorDevice | Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const selected = getState().wallet.selectedDevice; + // if (!selected || (selected && selected.state)) { + dispatch(onSelectDevice(device)); + // } + // if (device.unacquired && selected && selected.path !== device.path && !selected.connected) { + // dispatch( onSelectDevice(device) ); + // } else if (!selected) { + // dispatch( onSelectDevice(device) ); + // } +}; // selection from Aside dropdown button // after device_connect event // or after acquiring device // device type could be local TrezorDevice or Device (from trezor-connect device_connect event) -export const onSelectDevice = (device: TrezorDevice | Device): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - // || device.isUsedElsewhere - - // switch to initial url and reset this value - - if (!device.features) { - dispatch( push(`/device/${ device.path }/acquire`) ); - } else if (device.features.bootloader_mode) { - dispatch( push(`/device/${ device.path }/bootloader`) ); - } else if (!device.features.initialized) { - dispatch( push(`/device/${ device.features.device_id }/initialize`) ); - } else if (typeof device.instance === 'number') { - dispatch( push(`/device/${ device.features.device_id }:${ device.instance }`) ); - } else { - - const deviceId: string = device.features.device_id; - const urlParams: RouterLocationState = getState().router.location.state; - // let url: string = `/device/${ device.features.device_id }/network/ethereum/account/0`; - let url: string = `/device/${ deviceId }`; - let instance: ?number; - // check if device is not TrezorDevice type - if (!device.hasOwnProperty('ts')) { - // its device from trezor-connect (called in initConnectedDevice triggered by device_connect event) - // need to lookup if there are unavailable instances - const available: Array = getState().devices.filter(d => d.path === device.path); - const latest: Array = sortDevices(available); - - if (latest.length > 0 && latest[0].instance) { - url += `:${ latest[0].instance }`; - instance = latest[0].instance; - } +export const onSelectDevice = (device: TrezorDevice | Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + // || device.isUsedElsewhere + + // switch to initial url and reset this value + + if (!device.features) { + dispatch(push(`/device/${device.path}/acquire`)); + } else if (device.features.bootloader_mode) { + dispatch(push(`/device/${device.path}/bootloader`)); + } else if (!device.features.initialized) { + dispatch(push(`/device/${device.features.device_id}/initialize`)); + } else if (typeof device.instance === 'number') { + dispatch(push(`/device/${device.features.device_id}:${device.instance}`)); + } else { + const deviceId: string = device.features.device_id; + const urlParams: RouterLocationState = getState().router.location.state; + // let url: string = `/device/${ device.features.device_id }/network/ethereum/account/0`; + let url: string = `/device/${deviceId}`; + let instance: ?number; + // check if device is not TrezorDevice type + if (!device.hasOwnProperty('ts')) { + // its device from trezor-connect (called in initConnectedDevice triggered by device_connect event) + // need to lookup if there are unavailable instances + const available: Array = getState().devices.filter(d => d.path === device.path); + const latest: Array = sortDevices(available); + + if (latest.length > 0 && latest[0].instance) { + url += `:${latest[0].instance}`; + instance = latest[0].instance; } - // check if current location is not set to this device - //dispatch( push(`/device/${ device.features.device_id }/network/etc/account/0`) ); + } + // check if current location is not set to this device + //dispatch( push(`/device/${ device.features.device_id }/network/etc/account/0`) ); - if (urlParams.deviceInstance !== instance || urlParams.device !== deviceId) { - dispatch( push(url) ); - } + if (urlParams.deviceInstance !== instance || urlParams.device !== deviceId) { + dispatch(push(url)); } } -} - -export const switchToFirstAvailableDevice = (): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { +}; - const { devices } = getState(); - if (devices.length > 0) { - // TODO: Priority: - // 1. First Unacquired - // 2. First connected - // 3. Saved with latest timestamp - const unacquired = devices.find(d => d.unacquired); - if (unacquired) { - dispatch( initConnectedDevice(unacquired) ); - } else { - const latest: Array = sortDevices(devices); - const firstConnected: ?TrezorDevice = latest.find(d => d.connected); - dispatch( onSelectDevice(firstConnected || latest[0]) ); - } +export const switchToFirstAvailableDevice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const { devices } = getState(); + if (devices.length > 0) { + // TODO: Priority: + // 1. First Unacquired + // 2. First connected + // 3. Saved with latest timestamp + const unacquired = devices.find(d => d.unacquired); + if (unacquired) { + dispatch(initConnectedDevice(unacquired)); } else { - dispatch( push('/') ); + const latest: Array = sortDevices(devices); + const firstConnected: ?TrezorDevice = latest.find(d => d.connected); + dispatch(onSelectDevice(firstConnected || latest[0])); } + } else { + dispatch(push('/')); } -} +}; -export const getSelectedDeviceState = (): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const selected = getState().wallet.selectedDevice; - if (selected +export const getSelectedDeviceState = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const selected = getState().wallet.selectedDevice; + if (selected && selected.connected && (selected.features && !selected.features.bootloader_mode && selected.features.initialized) && !selected.state) { + const response = await TrezorConnect.getDeviceState({ + device: { + path: selected.path, + instance: selected.instance, + state: selected.state, + }, + useEmptyPassphrase: !selected.instance, + }); - const response = await TrezorConnect.getDeviceState({ - device: { - path: selected.path, - instance: selected.instance, - state: selected.state + if (response && response.success) { + dispatch({ + type: CONNECT.AUTH_DEVICE, + device: selected, + state: response.payload.state, + }); + } else { + dispatch({ + type: NOTIFICATION.ADD, + payload: { + devicePath: selected.path, + type: 'error', + title: 'Authentication error', + message: response.payload.error, + cancelable: false, + actions: [ + { + label: 'Try again', + callback: () => { + dispatch({ + type: NOTIFICATION.CLOSE, + payload: { devicePath: selected.path }, + }); + dispatch(getSelectedDeviceState()); + }, + }, + ], }, - useEmptyPassphrase: !selected.instance, }); - - if (response && response.success) { - dispatch({ - type: CONNECT.AUTH_DEVICE, - device: selected, - state: response.payload.state - }); - } else { - dispatch({ - type: NOTIFICATION.ADD, - payload: { - devicePath: selected.path, - type: 'error', - title: 'Authentication error', - message: response.payload.error, - cancelable: false, - actions: [ - { - label: 'Try again', - callback: () => { - dispatch( { - type: NOTIFICATION.CLOSE, - payload: { devicePath: selected.path } - }); - dispatch( getSelectedDeviceState() ); - } - } - ] - } - }); - } } } -} +}; -export const deviceDisconnect = (device: Device): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { +export const deviceDisconnect = (device: Device): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const selected: ?TrezorDevice = getState().wallet.selectedDevice; - const selected: ?TrezorDevice = getState().wallet.selectedDevice; - - if (device && device.features) { - if (selected && selected.features && selected.features.device_id === device.features.device_id) { - dispatch( DiscoveryActions.stop(selected) ); - } + if (device && device.features) { + if (selected && selected.features && selected.features.device_id === device.features.device_id) { + dispatch(DiscoveryActions.stop(selected)); + } - const instances = getState().devices.filter(d => d.features && d.state && !d.remember && d.features.device_id === device.features.device_id); - if (instances.length > 0) { - dispatch({ - type: CONNECT.REMEMBER_REQUEST, - device: instances[0], - instances, - }); - } + const instances = getState().devices.filter(d => d.features && d.state && !d.remember && d.features.device_id === device.features.device_id); + if (instances.length > 0) { + dispatch({ + type: CONNECT.REMEMBER_REQUEST, + device: instances[0], + instances, + }); } } -} +}; -export const coinChanged = (network: ?string): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - const selected: ?TrezorDevice = getState().wallet.selectedDevice; - if (!selected) return; +export const coinChanged = (network: ?string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const selected: ?TrezorDevice = getState().wallet.selectedDevice; + if (!selected) return; - dispatch( DiscoveryActions.stop(selected) ); + dispatch(DiscoveryActions.stop(selected)); - if (network) { - dispatch( DiscoveryActions.start(selected, network) ); - } + if (network) { + dispatch(DiscoveryActions.start(selected, network)); } -} +}; export function reload(): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - } + }; } export function acquire(): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - const selected: ?TrezorDevice = getState().wallet.selectedDevice; if (!selected) return; dispatch({ type: CONNECT.START_ACQUIRING, - }) + }); - const response = await TrezorConnect.getFeatures({ + const response = await TrezorConnect.getFeatures({ device: { path: selected.path, }, @@ -398,47 +375,41 @@ export function acquire(): AsyncAction { // } // } // ] - } - }) + }, + }); } dispatch({ type: CONNECT.STOP_ACQUIRING, - }) - } + }); + }; } -export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - if (device.features) { - const devUrl: string = `${device.features.device_id}${ device.instance ? `:${ device.instance}` : '' }`; - dispatch( push( `/device/${ devUrl }/settings` ) ); - } +export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + if (device.features) { + const devUrl: string = `${device.features.device_id}${device.instance ? `:${device.instance}` : ''}`; + dispatch(push(`/device/${devUrl}/settings`)); } -} +}; // called from Aside - device menu (forget single instance) -export const forget = (device: TrezorDevice): Action => { - return { - type: CONNECT.FORGET_REQUEST, - device - }; -} - -export const duplicateDevice = (device: TrezorDevice): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - dispatch({ - type: CONNECT.TRY_TO_DUPLICATE, - device - }) - } -} +export const forget = (device: TrezorDevice): Action => ({ + type: CONNECT.FORGET_REQUEST, + device, +}); + +export const duplicateDevice = (device: TrezorDevice): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + dispatch({ + type: CONNECT.TRY_TO_DUPLICATE, + device, + }); +}; export function addAccount(): ThunkAction { return (dispatch: Dispatch, getState: GetState): void => { const selected = getState().wallet.selectedDevice; if (!selected) return; - dispatch( DiscoveryActions.start(selected, getState().router.location.state.network, true) ); // TODO: network nicer - } + dispatch(DiscoveryActions.start(selected, getState().router.location.state.network, true)); // TODO: network nicer + }; } diff --git a/src/js/actions/WalletActions.js b/src/js/actions/WalletActions.js index 067e6bd4..763bb8db 100644 --- a/src/js/actions/WalletActions.js +++ b/src/js/actions/WalletActions.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import { LOCATION_CHANGE } from 'react-router-redux'; import * as WALLET from './constants/wallet'; @@ -8,20 +8,20 @@ import * as stateUtils from '../reducers/utils'; import type { Device } from 'trezor-connect'; import type - { +{ Account, Coin, Discovery, Token, Web3Instance, - TrezorDevice, - RouterLocationState, + TrezorDevice, + RouterLocationState, ThunkAction, AsyncAction, Action, - Dispatch, + Dispatch, GetState, - State + State, } from '~/flowtype'; export type WalletAction = { @@ -47,82 +47,66 @@ export type WalletAction = { devices: Array } -export const init = (): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - const updateOnlineStatus = (event) => { - dispatch({ - type: WALLET.ONLINE_STATUS, - online: navigator.onLine - }) - } - window.addEventListener('online', updateOnlineStatus); - window.addEventListener('offline', updateOnlineStatus); - } -} - -export const onBeforeUnload = (): WalletAction => { - return { - type: WALLET.ON_BEFORE_UNLOAD - } -} - -export const toggleDeviceDropdown = (opened: boolean): WalletAction => { - return { - type: WALLET.TOGGLE_DEVICE_DROPDOWN, - opened - } -} +export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const updateOnlineStatus = (event) => { + dispatch({ + type: WALLET.ONLINE_STATUS, + online: navigator.onLine, + }); + }; + window.addEventListener('online', updateOnlineStatus); + window.addEventListener('offline', updateOnlineStatus); +}; + +export const onBeforeUnload = (): WalletAction => ({ + type: WALLET.ON_BEFORE_UNLOAD, +}); + +export const toggleDeviceDropdown = (opened: boolean): WalletAction => ({ + type: WALLET.TOGGLE_DEVICE_DROPDOWN, + opened, +}); // This method will be called after each DEVICE.CONNECT action // if connected device has different "passphrase_protection" settings than saved instances // all saved instances will be removed immediately inside DevicesReducer // This method will clear leftovers associated with removed instances from reducers. // (DiscoveryReducer, AccountReducer, TokensReducer) -export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => { - return (dispatch: Dispatch, getState: GetState): void => { - - if (!device.features) return; +export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + if (!device.features) return; - const affectedDevices = prevState.devices.filter(d => - d.features + const affectedDevices = prevState.devices.filter(d => d.features && d.features.device_id === device.features.device_id - && d.features.passphrase_protection !== device.features.passphrase_protection - ); + && d.features.passphrase_protection !== device.features.passphrase_protection); - if (affectedDevices.length > 0) { - dispatch({ - type: WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA, - devices: affectedDevices, - }) - } + if (affectedDevices.length > 0) { + dispatch({ + type: WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA, + devices: affectedDevices, + }); } -} - - -export const updateSelectedValues = (prevState: State, action: Action): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { - - const locationChange: boolean = action.type === LOCATION_CHANGE; - const state: State = getState(); - - // handle devices state change (from trezor-connect events or location change) - if (locationChange || prevState.devices !== state.devices) { - const device = stateUtils.getSelectedDevice(state); - if (state.wallet.selectedDevice !== device) { - if (device && stateUtils.isSelectedDevice(state.wallet.selectedDevice, device)) { - dispatch({ - type: WALLET.UPDATE_SELECTED_DEVICE, - device - }); - } else { - dispatch({ - type: WALLET.SET_SELECTED_DEVICE, - device - }); - } +}; + + +export const updateSelectedValues = (prevState: State, action: Action): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const locationChange: boolean = action.type === LOCATION_CHANGE; + const state: State = getState(); + + // handle devices state change (from trezor-connect events or location change) + if (locationChange || prevState.devices !== state.devices) { + const device = stateUtils.getSelectedDevice(state); + if (state.wallet.selectedDevice !== device) { + if (device && stateUtils.isSelectedDevice(state.wallet.selectedDevice, device)) { + dispatch({ + type: WALLET.UPDATE_SELECTED_DEVICE, + device, + }); + } else { + dispatch({ + type: WALLET.SET_SELECTED_DEVICE, + device, + }); } } - } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/js/actions/Web3Actions.js b/src/js/actions/Web3Actions.js index a65ff05b..056f9ab4 100644 --- a/src/js/actions/Web3Actions.js +++ b/src/js/actions/Web3Actions.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import Web3 from 'web3'; import HDKey from 'hdkey'; @@ -7,27 +7,27 @@ import HDKey from 'hdkey'; import EthereumjsUtil from 'ethereumjs-util'; import EthereumjsTx from 'ethereumjs-tx'; import TrezorConnect from 'trezor-connect'; +import type { ContractFactory, EstimateGasOptions } from 'web3'; +import type BigNumber from 'bignumber.js'; +import type { TransactionStatus, TransactionReceipt } from 'web3'; import { strip } from '../utils/ethUtils'; import * as WEB3 from './constants/web3'; import * as PENDING from './constants/pendingTx'; -import * as AccountsActions from '../actions/AccountsActions'; -import * as TokenActions from '../actions/TokenActions'; +import * as AccountsActions from './AccountsActions'; +import * as TokenActions from './TokenActions'; -import type { +import type { Dispatch, GetState, Action, AsyncAction, } from '~/flowtype'; -import type { ContractFactory, EstimateGasOptions } from 'web3'; -import type BigNumber from 'bignumber.js'; import type { Account } from '../reducers/AccountsReducer'; import type { PendingTx } from '../reducers/PendingTxReducer'; import type { Web3Instance } from '../reducers/Web3Reducer'; import type { Token } from '../reducers/TokensReducer'; import type { NetworkToken } from '../reducers/LocalStorageReducer'; -import type { TransactionStatus, TransactionReceipt } from 'web3'; export type Web3Action = { type: typeof WEB3.READY, @@ -53,10 +53,9 @@ export type Web3UpdateGasPriceAction = { export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - const { config, ERC20Abi } = getState().localStorage; - const coin = config.coins[ coinIndex ]; + const coin = config.coins[coinIndex]; if (!coin) { // all instances done dispatch({ @@ -72,12 +71,12 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { if (instance) { const currentHost = instance.currentProvider.host; - let currentHostIndex: number = urls.indexOf(currentHost); + const currentHostIndex: number = urls.indexOf(currentHost); if (currentHostIndex + 1 < urls.length) { web3host = urls[currentHostIndex + 1]; } else { - console.error("TODO: Backend " + network + " not working", instance.currentProvider ); + console.error(`TODO: Backend ${network} not working`, instance.currentProvider); dispatch({ type: WEB3.CREATE, @@ -88,17 +87,17 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { erc20: instance.eth.contract(ERC20Abi), latestBlock: '0', gasPrice: '0', - } + }, }); // try next coin - dispatch( init(null, coinIndex + 1) ); + dispatch(init(null, coinIndex + 1)); return; } } //const instance = new Web3(window.web3.currentProvider); - const web3 = new Web3( new Web3.providers.HttpProvider(web3host) ); + const web3 = new Web3(new Web3.providers.HttpProvider(web3host)); // instance = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') ); // UBQ //instance = new Web3( new Web3.providers.HttpProvider('https://node.expanse.tech/') ); // EXP @@ -112,7 +111,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { // initial check if backend is running if (!web3.currentProvider.isConnected()) { // try different url - dispatch( init(web3, coinIndex) ); + dispatch(init(web3, coinIndex)); return; } @@ -122,12 +121,12 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { type: WEB3.CREATE, instance: { network, - web3: web3, + web3, chainId: coin.chainId, erc20, latestBlock: '0', gasPrice: '0', - } + }, }); // dispatch({ @@ -136,15 +135,13 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { // gasPrice // }); - - // console.log("GET CHAIN", instance.version.network) // instance.version.getWhisper((err, shh) => { // console.log("-----whisperrr", error, shh) // }) - + // const sshFilter = instance.ssh.filter('latest'); // sshFilter.watch((error, blockHash) => { @@ -157,10 +154,9 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { const onBlockMined = async (error: ?Error, blockHash: ?string) => { if (error) { - window.setTimeout(() => { // try again - onBlockMined(new Error("manually_triggered_error"), undefined); + onBlockMined(new Error('manually_triggered_error'), undefined); }, 30000); } @@ -168,7 +164,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { dispatch({ type: WEB3.BLOCK_UPDATED, network, - blockHash + blockHash, }); } @@ -181,70 +177,66 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { // dispatch( getBalance(account) ); // TODO: check if nonce was updated, - // update tokens balance, + // update tokens balance, // update account balance, // update pending transactions } - dispatch( getBalance(account) ); + dispatch(getBalance(account)); // dispatch( getNonce(account) ); - } const tokens = getState().tokens.filter(t => t.network === network); for (const token of tokens) { - dispatch( getTokenBalance(token) ); + dispatch(getTokenBalance(token)); } - dispatch( getGasPrice(network) ); + dispatch(getGasPrice(network)); const pending = getState().pending.filter(p => p.network === network); for (const tx of pending) { - dispatch( getTransactionReceipt(tx) ); + dispatch(getTransactionReceipt(tx)); } - - } + }; // latestBlockFilter.watch(onBlockMined); - onBlockMined(new Error("manually_triggered_error"), undefined); + onBlockMined(new Error('manually_triggered_error'), undefined); // init next coin - dispatch( init(web3, coinIndex + 1) ); - + dispatch(init(web3, coinIndex + 1)); + // let instance2 = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') ); // console.log("INIT WEB3", instance, instance2); // instance2.eth.getGasPrice((error, gasPrice) => { // console.log("---gasss price from UBQ", gasPrice) // }); - } + }; } export function getGasPrice(network: string): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - const index: number = getState().web3.findIndex(w3 => w3.network === network); - const web3instance = getState().web3[ index ]; + const web3instance = getState().web3[index]; const web3 = web3instance.web3; web3.eth.getGasPrice((error, gasPrice) => { if (!error) { if (web3instance.gasPrice && web3instance.gasPrice.toString() !== gasPrice.toString()) { dispatch({ type: WEB3.GAS_PRICE_UPDATED, - network: network, - gasPrice + network, + gasPrice, }); } } }); - } + }; } export function getBalance(account: Account): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0]; const web3: Web3 = web3instance.web3; @@ -256,42 +248,39 @@ export function getBalance(account: Account): AsyncAction { account.address, account.network, account.deviceState, - newBalance + newBalance, )); // dispatch( loadHistory(addr) ); } } }); - } + }; } export function getTokenBalance(token: Token): AsyncAction { return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === token.network)[0]; const web3 = web3instance.web3; const contract = web3instance.erc20.at(token.address); contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => { if (balance) { - const newBalance: string = balance.dividedBy( Math.pow(10, token.decimals) ).toString(10); + const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10); if (newBalance !== token.balance) { dispatch(TokenActions.setBalance( token.address, token.ethAddress, - newBalance + newBalance, )); } } }); - } + }; } export function getNonce(account: Account): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0]; const web3 = web3instance.web3; @@ -302,158 +291,138 @@ export function getNonce(account: Account): AsyncAction { } } }); - } + }; } -export const getTransactionReceipt = (tx: PendingTx): AsyncAction => { - return async (dispatch: Dispatch, getState: GetState): Promise => { +export const getTransactionReceipt = (tx: PendingTx): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0]; + const web3 = web3instance.web3; - const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0]; - const web3 = web3instance.web3; - - web3.eth.getTransaction(tx.id, (error: Error, status: TransactionStatus) => { - if (!error && !status) { - dispatch({ - type: PENDING.TX_NOT_FOUND, - tx, - }) - } else if (status && status.blockNumber) { - web3.eth.getTransactionReceipt(tx.id, (error: Error, receipt: TransactionReceipt) => { - if (receipt) { - if (status.gas !== receipt.gasUsed) { - dispatch({ - type: PENDING.TX_TOKEN_ERROR, - tx - }) - } + web3.eth.getTransaction(tx.id, (error: Error, status: TransactionStatus) => { + if (!error && !status) { + dispatch({ + type: PENDING.TX_NOT_FOUND, + tx, + }); + } else if (status && status.blockNumber) { + web3.eth.getTransactionReceipt(tx.id, (error: Error, receipt: TransactionReceipt) => { + if (receipt) { + if (status.gas !== receipt.gasUsed) { dispatch({ - type: PENDING.TX_RESOLVED, + type: PENDING.TX_TOKEN_ERROR, tx, - receipt - }) + }); } - - }); - } - }); - } -} - -export const getTransaction = (web3: Web3, txid: string): Promise => { - return new Promise((resolve, reject) => { - web3.eth.getTransaction(txid, (error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); + dispatch({ + type: PENDING.TX_RESOLVED, + tx, + receipt, + }); + } + }); + } }); -} +}; -export const getBalanceAsync = (web3: Web3, address: string): Promise => { - return new Promise((resolve, reject) => { - web3.eth.getBalance(address, (error: Error, result: BigNumber) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); +export const getTransaction = (web3: Web3, txid: string): Promise => new Promise((resolve, reject) => { + web3.eth.getTransaction(txid, (error, result) => { + if (error) { + reject(error); + } else { + resolve(result); + } }); -} - -export const getTokenBalanceAsync = (erc20: ContractFactory, token: Token): Promise => { - return new Promise((resolve, reject) => { - - const contract = erc20.at(token.address); - contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => { - if (error) { - reject(error); - } else { - const newBalance: string = balance.dividedBy( Math.pow(10, token.decimals) ).toString(10); - resolve(newBalance); - } - }); +}); + +export const getBalanceAsync = (web3: Web3, address: string): Promise => new Promise((resolve, reject) => { + web3.eth.getBalance(address, (error: Error, result: BigNumber) => { + if (error) { + reject(error); + } else { + resolve(result); + } }); -} +}); + +export const getTokenBalanceAsync = (erc20: ContractFactory, token: Token): Promise => new Promise((resolve, reject) => { + const contract = erc20.at(token.address); + contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => { + if (error) { + reject(error); + } else { + const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10); + resolve(newBalance); + } + }); +}); + +export const getNonceAsync = (web3: Web3, address: string): Promise => new Promise((resolve, reject) => { + web3.eth.getTransactionCount(address, (error: Error, result: number) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); +}); -export const getNonceAsync = (web3: Web3, address: string): Promise => { - return new Promise((resolve, reject) => { - web3.eth.getTransactionCount(address, (error: Error, result: number) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); + +export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise => new Promise((resolve, reject) => { + const contract = erc20.at(address, (error, res) => { + // console.warn("callback", error, res) }); -} + const info: NetworkToken = { + address, + name: '', + symbol: '', + decimals: 0, + }; -export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise => { - return new Promise((resolve, reject) => { + contract.name.call((error: Error, name: string) => { + if (error) { + resolve(null); + return; + } + info.name = name; - const contract = erc20.at(address, (error, res) => { - // console.warn("callback", error, res) - }); - const info: NetworkToken = { - address, - name: '', - symbol: '', - decimals: 0 - }; - - contract.name.call((error: Error, name: string) => { + contract.symbol.call((error: Error, symbol: string) => { if (error) { resolve(null); return; - } else { - info.name = name; } - - contract.symbol.call((error: Error, symbol: string) => { - if (error) { - resolve(null); - return; + info.symbol = symbol; + + + contract.decimals.call((error: Error, decimals: BigNumber) => { + if (decimals) { + info.decimals = decimals.toNumber(); + resolve(info); } else { - info.symbol = symbol; + resolve(null); } - - contract.decimals.call((error: Error, decimals: BigNumber) => { - if (decimals) { - info.decimals = decimals.toNumber(); - resolve(info); - } else { - resolve(null); - } - }); - }) + }); }); }); -} - -export const estimateGas = (web3: Web3, options: EstimateGasOptions): Promise => { - return new Promise((resolve, reject) => { - web3.eth.estimateGas(options, (error: ?Error, gas: ?number) => { - if (error) { - reject(error); - } else if (typeof gas === 'number'){ - resolve(gas); - } - }); - }) -} - -export const pushTx = (web3: Web3, tx: any): Promise => { - return new Promise((resolve, reject) => { - web3.eth.sendRawTransaction(tx, (error: Error, result: string) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - }) -} \ No newline at end of file +}); + +export const estimateGas = (web3: Web3, options: EstimateGasOptions): Promise => new Promise((resolve, reject) => { + web3.eth.estimateGas(options, (error: ?Error, gas: ?number) => { + if (error) { + reject(error); + } else if (typeof gas === 'number') { + resolve(gas); + } + }); +}); + +export const pushTx = (web3: Web3, tx: any): Promise => new Promise((resolve, reject) => { + web3.eth.sendRawTransaction(tx, (error: Error, result: string) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); +}); \ No newline at end of file diff --git a/src/js/actions/constants/TrezorConnect.js b/src/js/actions/constants/TrezorConnect.js index 0e4f3cd7..a49371c5 100644 --- a/src/js/actions/constants/TrezorConnect.js +++ b/src/js/actions/constants/TrezorConnect.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + //regExp1 : string = '(.*)' //regExp2 : '$1' = '$1' diff --git a/src/js/actions/constants/account.js b/src/js/actions/constants/account.js index 11c72a4d..18075a00 100644 --- a/src/js/actions/constants/account.js +++ b/src/js/actions/constants/account.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const INIT: 'account__init' = 'account__init'; export const DISPOSE: 'account__dispose' = 'account__dispose'; diff --git a/src/js/actions/constants/discovery.js b/src/js/actions/constants/discovery.js index 977f6e00..1fca3045 100644 --- a/src/js/actions/constants/discovery.js +++ b/src/js/actions/constants/discovery.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const START: 'discovery__start' = 'discovery__start'; export const STOP: 'discovery__stop' = 'discovery__stop'; diff --git a/src/js/actions/constants/localStorage.js b/src/js/actions/constants/localStorage.js index 9c73badd..402a23a8 100644 --- a/src/js/actions/constants/localStorage.js +++ b/src/js/actions/constants/localStorage.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const SAVE: 'storage__save' = 'storage__save'; export const READY: 'storage__ready' = 'storage__ready'; diff --git a/src/js/actions/constants/log.js b/src/js/actions/constants/log.js index 9c33fb60..a08a84cf 100644 --- a/src/js/actions/constants/log.js +++ b/src/js/actions/constants/log.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const OPEN: 'log__open' = 'log__open'; export const CLOSE: 'log__close' = 'log__close'; diff --git a/src/js/actions/constants/modal.js b/src/js/actions/constants/modal.js index a0949ebd..917b2029 100644 --- a/src/js/actions/constants/modal.js +++ b/src/js/actions/constants/modal.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const ON_PASSPHRASE_CHANGE: 'action__on_passphrase_change' = 'action__on_passphrase_change'; export const ON_PASSPHRASE_SHOW: 'action__on_passphrase_show' = 'action__on_passphrase_show'; diff --git a/src/js/actions/constants/notification.js b/src/js/actions/constants/notification.js index 0b14d504..c9147409 100644 --- a/src/js/actions/constants/notification.js +++ b/src/js/actions/constants/notification.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const ADD: 'notification__add' = 'notification__add'; export const CLOSE: 'notification__close' = 'notification__close'; diff --git a/src/js/actions/constants/pendingTx.js b/src/js/actions/constants/pendingTx.js index 08a58b36..c2cfc0c2 100644 --- a/src/js/actions/constants/pendingTx.js +++ b/src/js/actions/constants/pendingTx.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const FROM_STORAGE: 'pending__from_storage' = 'pending__from_storage'; export const TX_RESOLVED: 'pending__tx_resolved' = 'pending__tx_resolved'; diff --git a/src/js/actions/constants/receive.js b/src/js/actions/constants/receive.js index cbf243e2..21d39d15 100644 --- a/src/js/actions/constants/receive.js +++ b/src/js/actions/constants/receive.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const INIT: 'receive__init' = 'receive__init'; export const DISPOSE: 'receive__dispose' = 'receive__dispose'; diff --git a/src/js/actions/constants/send.js b/src/js/actions/constants/send.js index 35c70969..08528692 100644 --- a/src/js/actions/constants/send.js +++ b/src/js/actions/constants/send.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const INIT: 'send__init' = 'send__init'; export const DISPOSE: 'send__dispose' = 'send__dispose'; diff --git a/src/js/actions/constants/summary.js b/src/js/actions/constants/summary.js index ebb82c95..ae002582 100644 --- a/src/js/actions/constants/summary.js +++ b/src/js/actions/constants/summary.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const INIT: 'summary__init' = 'summary__init'; export const DISPOSE: 'summary__dispose' = 'summary__dispose'; diff --git a/src/js/actions/constants/token.js b/src/js/actions/constants/token.js index 5878c5b5..f2ce1ebc 100644 --- a/src/js/actions/constants/token.js +++ b/src/js/actions/constants/token.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const ADD: 'token__add' = 'token__add'; export const REMOVE: 'token__remove' = 'token__remove'; diff --git a/src/js/actions/constants/wallet.js b/src/js/actions/constants/wallet.js index c19c73ba..4aa8cd4f 100644 --- a/src/js/actions/constants/wallet.js +++ b/src/js/actions/constants/wallet.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const ON_BEFORE_UNLOAD: 'wallet__on_before_unload' = 'wallet__on_before_unload'; export const TOGGLE_DEVICE_DROPDOWN: 'wallet__toggle_dropdown' = 'wallet__toggle_dropdown'; diff --git a/src/js/actions/constants/web3.js b/src/js/actions/constants/web3.js index ad55001f..232db739 100644 --- a/src/js/actions/constants/web3.js +++ b/src/js/actions/constants/web3.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + export const START: 'web3__start' = 'web3__start'; export const STOP: 'web3__stop' = 'web3__stop'; diff --git a/src/js/components/common/Footer.js b/src/js/components/common/Footer.js index c32a6159..b61f2003 100644 --- a/src/js/components/common/Footer.js +++ b/src/js/components/common/Footer.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import React from 'react'; import { bindActionCreators } from 'redux'; @@ -12,26 +12,20 @@ type Props = { toggle: typeof LogActions.toggle } -const Footer = (props: Props): React$Element => { - return ( -

- ); -} +const Footer = (props: Props): React$Element => ( + +); + +export default connect( + (state: State) => ({ -export default connect( - (state: State) => { - return { - - } - }, - (dispatch: Dispatch) => { - return { - toggle: bindActionCreators(LogActions.toggle, dispatch), - }; - } + }), + (dispatch: Dispatch) => ({ + toggle: bindActionCreators(LogActions.toggle, dispatch), + }), )(Footer); diff --git a/src/js/components/common/Header.js b/src/js/components/common/Header.js index 9ebbd0df..318da14d 100644 --- a/src/js/components/common/Header.js +++ b/src/js/components/common/Header.js @@ -1,30 +1,28 @@ /* @flow */ -'use strict'; + import React from 'react'; -const Header = (): React$Element => { - return ( -
-
- - - - - - - - - -
- TREZOR - Docs - Blog - Support -
+const Header = (): React$Element => ( +
+
+ + + + + + + + + + -
- ); -} +
+
+); export default Header; \ No newline at end of file diff --git a/src/js/components/common/LoaderCircle.js b/src/js/components/common/LoaderCircle.js index 9a780b25..fe4f4827 100644 --- a/src/js/components/common/LoaderCircle.js +++ b/src/js/components/common/LoaderCircle.js @@ -1,17 +1,16 @@ /* @flow */ -'use strict'; + import React from 'react'; export default (props: { size: string, label?: string }): React$Element => { - const style = { - width: `${props.size}px`, - height: `${props.size}px`, - } - + width: `${props.size}px`, + height: `${props.size}px`, + }; + return ( -
+

{ props.label }

@@ -19,4 +18,4 @@ export default (props: { size: string, label?: string }): React$Element
); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/js/components/common/Log.js b/src/js/components/common/Log.js index dbfdc7a0..e0b8ef2d 100644 --- a/src/js/components/common/Log.js +++ b/src/js/components/common/Log.js @@ -1,5 +1,5 @@ /* @flow */ -'use strict'; + import React from 'react'; import { bindActionCreators } from 'redux'; @@ -14,34 +14,29 @@ type Props = { } const Log = (props: Props): ?React$Element => { - if (!props.log.opened) - return null; + if (!props.log.opened) return null; // const entries = props.log.entries.map(entry => { // return ( // ) // }) - + return (
- +
-
-

Verify message

- - - - - - -
- - ); -} +const SignVerify = () => ( +
+
+

Sign message

+ +