on master help sign in
Merge pull request #152 from urbit/feat/simpler-routing
77325bbMatt Condon
package-lock.json+11−103
@@ -7702,28 +7702,6 @@
7702 "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
7702 "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
7703 "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
7703 "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
7704 },
7704 },
7705− "history": {
7706− "version": "4.7.2",
7707− "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
7708− "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
7709− "requires": {
7710− "invariant": "^2.2.1",
7711− "loose-envify": "^1.2.0",
7712− "resolve-pathname": "^2.2.0",
7713− "value-equal": "^0.4.0",
7714− "warning": "^3.0.0"
7715− },
7716− "dependencies": {
7717− "warning": {
7718− "version": "3.0.0",
7719− "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
7720− "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
7721− "requires": {
7722− "loose-envify": "^1.0.0"
7723− }
7724− }
7725− }
7726− },
7727 "hmac-drbg": {
7705 "hmac-drbg": {
7728 "version": "1.0.1",
7706 "version": "1.0.1",
7729 "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
7707 "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -7739,11 +7717,6 @@
7739 "resolved": "http://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
7717 "resolved": "http://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
7740 "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
7718 "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
7741 },
7719 },
7742− "hoist-non-react-statics": {
7743− "version": "2.5.5",
7744− "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
7745− "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
7746− },
7747 "home-or-tmp": {
7720 "home-or-tmp": {
7748 "version": "2.0.0",
7721 "version": "2.0.0",
7749 "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
7722 "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -8515,11 +8488,6 @@
8515 "resolved": "https://registry.npmjs.org/immer/-/immer-1.7.2.tgz",
8488 "resolved": "https://registry.npmjs.org/immer/-/immer-1.7.2.tgz",
8516 "integrity": "sha512-4Urocwu9+XLDJw4Tc6ZCg7APVjjLInCFvO4TwGsAYV5zT6YYSor14dsZR0+0tHlDIN92cFUOq+i7fC00G5vTxA=="
8489 "integrity": "sha512-4Urocwu9+XLDJw4Tc6ZCg7APVjjLInCFvO4TwGsAYV5zT6YYSor14dsZR0+0tHlDIN92cFUOq+i7fC00G5vTxA=="
8517 },
8490 },
8518− "immutable": {
8519− "version": "4.0.0-rc.12",
8520− "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz",
8521− "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A=="
8522− },
8523 "import-cwd": {
8491 "import-cwd": {
8524 "version": "2.1.0",
8492 "version": "2.1.0",
8525 "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
8493 "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@@ -15979,14 +15947,14 @@
15979 }
15947 }
15980 },
15948 },
15981 "react": {
15949 "react": {
15982− "version": "16.6.3",
15950+ "version": "16.8.6",
15983− "resolved": "https://registry.npmjs.org/react/-/react-16.6.3.tgz",
15951+ "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz",
15984− "integrity": "sha512-zCvmH2vbEolgKxtqXL2wmGCUxUyNheYn/C+PD1YAjfxHC54+MhdruyhO7QieQrYsYeTxrn93PM2y0jRH1zEExw==",
15952+ "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==",
15985 "requires": {
15953 "requires": {
15986 "loose-envify": "^1.1.0",
15954 "loose-envify": "^1.1.0",
15987 "object-assign": "^4.1.1",
15955 "object-assign": "^4.1.1",
15988 "prop-types": "^15.6.2",
15956 "prop-types": "^15.6.2",
15989− "scheduler": "^0.11.2"
15957+ "scheduler": "^0.13.6"
15990 }
15958 }
15991 },
15959 },
15992 "react-app-polyfill": {
15960 "react-app-polyfill": {
@@ -16188,14 +16156,14 @@
16188 }
16156 }
16189 },
16157 },
16190 "react-dom": {
16158 "react-dom": {
16191− "version": "16.6.3",
16159+ "version": "16.8.6",
16192− "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.6.3.tgz",
16160+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz",
16193− "integrity": "sha512-8ugJWRCWLGXy+7PmNh8WJz3g1TaTUt1XyoIcFN+x0Zbkoz+KKdUyx1AQLYJdbFXjuF41Nmjn5+j//rxvhFjgSQ==",
16161+ "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==",
16194 "requires": {
16162 "requires": {
16195 "loose-envify": "^1.1.0",
16163 "loose-envify": "^1.1.0",
16196 "object-assign": "^4.1.1",
16164 "object-assign": "^4.1.1",
16197 "prop-types": "^15.6.2",
16165 "prop-types": "^15.6.2",
16198− "scheduler": "^0.11.2"
16166+ "scheduler": "^0.13.6"
16199 }
16167 }
16200 },
16168 },
16201 "react-error-overlay": {
16169 "react-error-overlay": {
@@ -16203,48 +16171,6 @@
16203 "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.1.tgz",
16171 "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.1.tgz",
16204 "integrity": "sha512-gJcOyak5ri9mzhpFObSAkCqNNBCVZE8LaR/mX37agULgSL0dobgX11NVSIetvNzhHMkr6CIqV0xiutvvcjBtkw=="
16172 "integrity": "sha512-gJcOyak5ri9mzhpFObSAkCqNNBCVZE8LaR/mX37agULgSL0dobgX11NVSIetvNzhHMkr6CIqV0xiutvvcjBtkw=="
16205 },
16173 },
16206− "react-router": {
16207− "version": "4.3.1",
16208− "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
16209− "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==",
16210− "requires": {
16211− "history": "^4.7.2",
16212− "hoist-non-react-statics": "^2.5.0",
16213− "invariant": "^2.2.4",
16214− "loose-envify": "^1.3.1",
16215− "path-to-regexp": "^1.7.0",
16216− "prop-types": "^15.6.1",
16217− "warning": "^4.0.1"
16218− },
16219− "dependencies": {
16220− "isarray": {
16221− "version": "0.0.1",
16222− "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
16223− "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
16224− },
16225− "path-to-regexp": {
16226− "version": "1.7.0",
16227− "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
16228− "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
16229− "requires": {
16230− "isarray": "0.0.1"
16231− }
16232− }
16233− }
16234− },
16235− "react-router-dom": {
16236− "version": "4.3.1",
16237− "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz",
16238− "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==",
16239− "requires": {
16240− "history": "^4.7.2",
16241− "invariant": "^2.2.4",
16242− "loose-envify": "^1.3.1",
16243− "prop-types": "^15.6.1",
16244− "react-router": "^4.3.1",
16245− "warning": "^4.0.1"
16246− }
16247− },
16248 "react-scripts": {
16174 "react-scripts": {
16249 "version": "2.1.2",
16175 "version": "2.1.2",
16250 "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-2.1.2.tgz",
16176 "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-2.1.2.tgz",
@@ -16951,11 +16877,6 @@
16951 "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
16877 "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
16952 "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
16878 "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
16953 },
16879 },
16954− "resolve-pathname": {
16955− "version": "2.2.0",
16956− "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
16957− "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
16958− },
16959 "resolve-url": {
16880 "resolve-url": {
16960 "version": "0.2.1",
16881 "version": "0.2.1",
16961 "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
16882 "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@@ -17432,9 +17353,9 @@
17432 }
17353 }
17433 },
17354 },
17434 "scheduler": {
17355 "scheduler": {
17435− "version": "0.11.3",
17356+ "version": "0.13.6",
17436− "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.11.3.tgz",
17357+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz",
17437− "integrity": "sha512-i9X9VRRVZDd3xZw10NY5Z2cVMbdYg6gqFecfj79USv1CFN+YrJ3gIPRKf1qlY+Sxly4djoKdfx1T+m9dnRB8kQ==",
17358+ "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==",
17438 "requires": {
17359 "requires": {
17439 "loose-envify": "^1.1.0",
17360 "loose-envify": "^1.1.0",
17440 "object-assign": "^4.1.1"
17361 "object-assign": "^4.1.1"
@@ -19517,11 +19438,6 @@
19517 "spdx-expression-parse": "^3.0.0"
19438 "spdx-expression-parse": "^3.0.0"
19518 }
19439 }
19519 },
19440 },
19520− "value-equal": {
19521− "version": "0.4.0",
19522− "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
19523− "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
19524− },
19525 "vary": {
19441 "vary": {
19526 "version": "1.1.2",
19442 "version": "1.1.2",
19527 "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
19443 "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -19576,14 +19492,6 @@
19576 "makeerror": "1.0.x"
19492 "makeerror": "1.0.x"
19577 }
19493 }
19578 },
19494 },
19579− "warning": {
19580− "version": "4.0.3",
19581− "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
19582− "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
19583− "requires": {
19584− "loose-envify": "^1.0.0"
19585− }
19586− },
19587 "watch": {
19495 "watch": {
19588 "version": "0.18.0",
19496 "version": "0.18.0",
19589 "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
19497 "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
package.json+2−4
@@ -29,16 +29,14 @@
29 "ethereumjs-tx": "^1.3.7",
29 "ethereumjs-tx": "^1.3.7",
30 "file-saver": "^2.0.0",
30 "file-saver": "^2.0.0",
31 "folktale": "^2.3.1",
31 "folktale": "^2.3.1",
32− "immutable": "^4.0.0-rc.12",
33 "jszip": "^3.1.5",
32 "jszip": "^3.1.5",
34 "keccak": "^1.4.0",
33 "keccak": "^1.4.0",
35 "keythereum": "^1.0.4",
34 "keythereum": "^1.0.4",
36 "lodash": "^4.17.11",
35 "lodash": "^4.17.11",
37 "more-entropy": "^0.0.7",
36 "more-entropy": "^0.0.7",
38 "prop-types": "^15.6.2",
37 "prop-types": "^15.6.2",
39− "react": "^16.6.0",
38+ "react": "^16.8.6",
40− "react-dom": "^16.6.0",
39+ "react-dom": "^16.8.6",
41− "react-router-dom": "^4.3.1",
42 "react-scripts": "^2.1.1",
40 "react-scripts": "^2.1.1",
43 "secp256k1": "^3.5.2",
41 "secp256k1": "^3.5.2",
44 "sigil-js": "github:urbit/sigil-js#f7f29c5",
42 "sigil-js": "github:urbit/sigil-js#f7f29c5",
src/bridge/Bridge.js+116−192
@@ -1,16 +1,16 @@
1−import { Just, Nothing } from 'folktale/maybe';
2−import * as lodash from 'lodash';
3−import * as azimuth from 'azimuth-js';
4−import { Stack } from 'immutable';
5−import { CONTRACT_ADDRESSES } from './lib/contracts';
6import React from 'react';
1import React from 'react';
2+import { Just, Nothing } from 'folktale/maybe';
3+import { includes } from 'lodash';
7
4
8−import Web3 from 'web3';
9import Footer from './components/Footer';
5import Footer from './components/Footer';
10import Header from './components/Header';
6import Header from './components/Header';
11import { Container, Row, Col } from './components/Base';
7import { Container, Row, Col } from './components/Base';
12
8
13−import { ROUTE_NAMES, router } from './lib/router';
9+import { router } from './lib/router';
10+import { initWeb3 } from './lib/web3';
11+import { ROUTE_NAMES } from './lib/routeNames';
12+import { HistoryProvider, withHistory, useHistory } from './store/history';
13+import { TxnConfirmationsProvider } from './store/txnConfirmations';
14import { NETWORK_NAMES } from './lib/network';
14import { NETWORK_NAMES } from './lib/network';
15import {
15import {
16 WALLET_NAMES,
16 WALLET_NAMES,
@@ -19,35 +19,54 @@ import {
19 addressFromSecp256k1Public,
19 addressFromSecp256k1Public,
20} from './lib/wallet';
20} from './lib/wallet';
21import { BRIDGE_ERROR } from './lib/error';
21import { BRIDGE_ERROR } from './lib/error';
22−
22+import { isLocal } from './lib/flags';
23−const initWeb3 = networkType => {
23+
24− if (networkType === NETWORK_NAMES.MAINNET) {
24+// NB(shrugs): toggle this variable to use the default local state.
25− const endpoint = `https://mainnet.infura.io/v3/${
25+// don't commit changes to this line, but there shouldn't be a problem
26− process.env.REACT_APP_INFURA_ENDPOINT
26+// if you do because we'll never stub on a production build.
27− }`;
27+const shouldStubLocal = false;
28−
28+const isStubbed = isLocal && shouldStubLocal;
29− const provider = new Web3.providers.HttpProvider(endpoint);
29+const kInitialRoutes = isStubbed
30− const web3 = new Web3(provider);
30+ ? [
31− const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.MAINNET);
31+ { name: ROUTE_NAMES.SHIPS },
32− return { web3: web3, contracts: contracts };
32+ { name: ROUTE_NAMES.WALLET },
33− } else if (networkType === NETWORK_NAMES.LOCAL) {
33+ { name: ROUTE_NAMES.NETWORK },
34− const protocol = process.env.NODE_ENV === 'development' ? 'ws' : 'wss';
34+ { name: ROUTE_NAMES.LANDING },
35− const endpoint = `${protocol}://localhost:8545`;
35+ ]
36− const provider = new Web3.providers.WebsocketProvider(endpoint);
36+ : [{ name: ROUTE_NAMES.LANDING }];
37− const web3 = new Web3(provider);
37+
38− const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.DEV);
38+// the router itself is a component that renders a specific view
39− return { web3: web3, contracts: contracts };
39+// based on the latest history state
40− }
40+const Router = function(props) {
41+ const history = useHistory();
42+ const Route = router(history.peek());
43+
44+ return <Route {...props} />;
41};
45};
42
46
47+// NB(shrugs): separate component because it needs withHistory
48+// this will be must better structured as part of the UI overhaul
49+const VariableWidthColumn = withHistory(({ history, children }) => (
50+ // For the invite acceptance flow, widen the screen to use the full
51+ // container, and hide the breadcrumbs
52+ <Col
53+ className={
54+ history.includes(ROUTE_NAMES.INVITE_TICKET)
55+ ? 'col-md-12'
56+ : 'col-md-offset-1 col-md-10'
57+ }
58+ style={
59+ history.includes(ROUTE_NAMES.INVITE_TICKET) ? {} : { maxWidth: '620px' }
60+ }>
61+ {children}
62+ </Col>
63+));
64+
43class Bridge extends React.Component {
65class Bridge extends React.Component {
44 constructor(props) {
66 constructor(props) {
45 super(props);
67 super(props);
46
68
47− const networkType =
48− process.env.NODE_ENV === 'development'
49− ? NETWORK_NAMES.LOCAL
50− : NETWORK_NAMES.MAINNET;
69+ const networkType = isLocal ? NETWORK_NAMES.LOCAL : NETWORK_NAMES.MAINNET;
51
70
52 // Sidestepping full network selection to allow for point viewing,
71 // Sidestepping full network selection to allow for point viewing,
53 // but still respecting the networkType
72 // but still respecting the networkType
@@ -67,9 +86,6 @@ class Bridge extends React.Component {
67 // 'EthereumWallet'.
86 // 'EthereumWallet'.
68
87
69 this.state = {
88 this.state = {
70− // routes
71− routeCrumbs: Stack([ROUTE_NAMES.LANDING]),
72− routeData: {},
73 // network
89 // network
74 networkType: networkType,
90 networkType: networkType,
75 web3: Just(web3),
91 web3: Just(web3),
@@ -90,9 +106,6 @@ class Bridge extends React.Component {
90 txnConfirmations: {},
106 txnConfirmations: {},
91 };
107 };
92
108
93− this.pushRoute = this.pushRoute.bind(this);
94− this.popRoute = this.popRoute.bind(this);
95− this.skipRoute = this.skipRoute.bind(this);
96 this.setNetworkType = this.setNetworkType.bind(this);
109 this.setNetworkType = this.setNetworkType.bind(this);
97 this.setNetwork = this.setNetwork.bind(this);
110 this.setNetwork = this.setNetwork.bind(this);
98 this.setWalletType = this.setWalletType.bind(this);
111 this.setWalletType = this.setWalletType.bind(this);
@@ -102,84 +115,31 @@ class Bridge extends React.Component {
102 this.setAuthMnemonic = this.setAuthMnemonic.bind(this);
115 this.setAuthMnemonic = this.setAuthMnemonic.bind(this);
103 this.setPointCursor = this.setPointCursor.bind(this);
116 this.setPointCursor = this.setPointCursor.bind(this);
104 this.setTxnHashCursor = this.setTxnHashCursor.bind(this);
117 this.setTxnHashCursor = this.setTxnHashCursor.bind(this);
105− this.setTxnConfirmations = this.setTxnConfirmations.bind(this);
106 this.setNetworkSeedCache = this.setNetworkSeedCache.bind(this);
118 this.setNetworkSeedCache = this.setNetworkSeedCache.bind(this);
107 this.addToPointCache = this.addToPointCache.bind(this);
119 this.addToPointCache = this.addToPointCache.bind(this);
108 }
120 }
109
121
110 componentDidMount() {
122 componentDidMount() {
111− window.history.pushState(null, null, null);
112−
113− window.onpopstate = e => {
114− window.history.pushState(null, null, null);
115− this.popRoute();
116− };
117−
118− // NB (jtobin):
123+ // NB (jtobin, shrugs):
119 //
124 //
120 // If running in development, the following can be tweaked to get you set
125 // If running in development, the following can be tweaked to get you set
121 // up with a desirable initial state.
126 // up with a desirable initial state.
127+ if (isStubbed) {
128+ const mnemonic = process.env.REACT_APP_DEV_MNEMONIC;
129+ const hdpath = process.env.REACT_APP_HD_PATH;
122
130
123− // if (process.env.NODE_ENV === 'development') {
124− //
125− // const socket = 'ws://localhost:8545'
126− // const provider = new Web3.providers.WebsocketProvider(socket)
127− // const web3 = new Web3(provider)
128− // const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.DEV)
129− //
130− // const mnemonic = process.env.REACT_APP_DEV_MNEMONIC
131− // const hdpath = process.env.REACT_APP_HD_PATH
132− //
133− // this.setState({
131+ this.setState({
134− // routeCrumbs: Stack([
135− // // ROUTE_NAMES.CREATE_GALAXY,
136− // // ROUTE_NAMES.SHIP,
137− // ROUTE_NAMES.SHIPS,
138− // // ROUTE_NAMES.MNEMONIC,
139− // ROUTE_NAMES.WALLET,
140− // ROUTE_NAMES.NETWORK,
141− // ROUTE_NAMES.LANDING
142− // ]),
143− // networkType: NETWORK_NAMES.LOCAL,
144− // pointCursor: Just(0),
132+ pointCursor: Just(0),
145− // web3: Just(web3),
146− // contracts: Just(contracts),
147− // walletType: WALLET_NAMES.MNEMONIC,
133+ walletType: WALLET_NAMES.MNEMONIC,
148− // wallet: walletFromMnemonic(mnemonic, hdpath),
134+ wallet: walletFromMnemonic(mnemonic, hdpath),
149− // urbitWallet: Nothing(),
135+ urbitWallet: Nothing(),
150− // authMnemonic: Just('benefit crew supreme gesture quantum web media hazard theory mercy wing kitten')
136+ authMnemonic: Just(mnemonic),
151− // })
152− // }
153− }
154−
155− pushRoute(symbol, routeData) {
156− if (lodash.includes(ROUTE_NAMES, symbol)) {
157− this.setState((state, _) => ({
158− routeCrumbs: state.routeCrumbs.push(symbol),
159− routeData: routeData,
160− }));
137+ });
161−
162− // Scroll to top of page with each route transition.
163− window.scrollTo(0, 0);
164− } else {
165− throw BRIDGE_ERROR.INVALID_ROUTE;
166 }
138 }
167 }
139 }
168
140
169− skipRoute(len) {
170− this.setState((state, _) => ({
171− routeCrumbs: state.routeCrumbs.skip(len),
172− }));
173− }
174−
175− popRoute() {
176− this.setState((state, _) => ({
177− routeCrumbs: state.routeCrumbs.shift(),
178− }));
179− }
180−
181 setNetworkType(symbol) {
141 setNetworkType(symbol) {
182− if (lodash.includes(NETWORK_NAMES, symbol)) {
142+ if (includes(NETWORK_NAMES, symbol)) {
183 this.setState({
143 this.setState({
184 networkType: symbol,
144 networkType: symbol,
185 });
145 });
@@ -203,7 +163,7 @@ class Bridge extends React.Component {
203 }
163 }
204
164
205 setWalletType(symbol) {
165 setWalletType(symbol) {
206− if (lodash.includes(WALLET_NAMES, symbol)) {
166+ if (includes(WALLET_NAMES, symbol)) {
207 this.setState({
167 this.setState({
208 walletType: symbol,
168 walletType: symbol,
209 });
169 });
@@ -260,23 +220,8 @@ class Bridge extends React.Component {
260 this.setState({ txnHashCursor });
220 this.setState({ txnHashCursor });
261 }
221 }
262
222
263− setTxnConfirmations(txnHash, txnConfirmations) {
264− this.setState((prevState, _) => {
265− return prevState.routeCrumbs.peek() === ROUTE_NAMES.SENT_TRANSACTION
266− ? {
267− txnConfirmations: {
268− ...prevState.txnConfirmations,
269− [txnHash]: txnConfirmations,
270− },
271− }
272− : null;
273− });
274− }
275−
276 render() {
223 render() {
277 const {
224 const {
278− routeCrumbs,
279− routeData,
280 networkType,
225 networkType,
281 walletType,
226 walletType,
282 walletHdPath,
227 walletHdPath,
@@ -288,87 +233,66 @@ class Bridge extends React.Component {
288 pointCursor,
233 pointCursor,
289 pointCache,
234 pointCache,
290 txnHashCursor,
235 txnHashCursor,
291− txnConfirmations,
292 web3,
236 web3,
293 contracts,
237 contracts,
294 } = this.state;
238 } = this.state;
295
239
296− const View = router(routeCrumbs.peek());
297−
298− // For the invite acceptance flow, widen the screen to use the full
299− // container, and hide the breadcrumbs
300− const colClass = routeCrumbs.contains(ROUTE_NAMES.INVITE_TICKET)
301− ? 'col-md-12'
302− : 'col-md-offset-1 col-md-10';
303−
304− const colStyle = routeCrumbs.contains(ROUTE_NAMES.INVITE_TICKET)
305− ? {}
306− : { maxWidth: '620px' };
307−
308− const showCrumbs = routeCrumbs.contains(ROUTE_NAMES.INVITE_TICKET)
309− ? false
310− : true;
311−
312 return (
240 return (
313− <Container>
241+ <HistoryProvider initialRoutes={kInitialRoutes}>
314− <Row>
242+ <TxnConfirmationsProvider>
315− <Col className={colClass} style={colStyle}>
243+ <Container>
244+ <Row>
245+ <VariableWidthColumn>
316− <Header
246+ <Header
317− routeCrumbs={routeCrumbs}
318− skipRoute={this.skipRoute}
247+ skipRoute={this.skipRoute}
319− networkType={networkType}
248+ networkType={networkType}
320− wallet={wallet}
249+ wallet={wallet}
321− showCrumbs={showCrumbs}
322− pointCursor={pointCursor}
250+ pointCursor={pointCursor}
323− />
251+ />
324−
252+
325− <Row className={'row wrapper'}>
253+ <Row className={'row wrapper'}>
326− <View
254+ <Router
327− // router
328− pushRoute={this.pushRoute}
329− popRoute={this.popRoute}
330− routeData={routeData}
331− // network
255+ // network
332− setNetworkType={this.setNetworkType}
256+ setNetworkType={this.setNetworkType}
333− setNetwork={this.setNetwork}
257+ setNetwork={this.setNetwork}
334− networkType={networkType}
258+ networkType={networkType}
335− web3={web3}
259+ web3={web3}
336− contracts={contracts}
260+ contracts={contracts}
337− // wallet
261+ // wallet
338− setWalletType={this.setWalletType}
262+ setWalletType={this.setWalletType}
339− setWalletHdPath={this.setWalletHdPath}
263+ setWalletHdPath={this.setWalletHdPath}
340− setWallet={this.setWallet}
264+ setWallet={this.setWallet}
341− walletType={walletType}
265+ walletType={walletType}
342− walletHdPath={walletHdPath}
266+ walletHdPath={walletHdPath}
343− wallet={wallet}
267+ wallet={wallet}
344− // urbit wallet
268+ // urbit wallet
345− urbitWallet={urbitWallet}
269+ urbitWallet={urbitWallet}
346− setUrbitWallet={this.setUrbitWallet}
270+ setUrbitWallet={this.setUrbitWallet}
347− authMnemonic={authMnemonic}
271+ authMnemonic={authMnemonic}
348− setAuthMnemonic={this.setAuthMnemonic}
272+ setAuthMnemonic={this.setAuthMnemonic}
349− // point
273+ // point
350− setPointCursor={this.setPointCursor}
274+ setPointCursor={this.setPointCursor}
351− addToPointCache={this.addToPointCache}
275+ addToPointCache={this.addToPointCache}
352− pointCursor={pointCursor}
276+ pointCursor={pointCursor}
353− pointCache={pointCache}
277+ pointCache={pointCache}
354− networkSeedCache={networkSeedCache}
278+ networkSeedCache={networkSeedCache}
355− networkRevisionCache={networkRevisionCache}
279+ networkRevisionCache={networkRevisionCache}
356− setNetworkSeedCache={this.setNetworkSeedCache}
280+ setNetworkSeedCache={this.setNetworkSeedCache}
357− // txn
281+ // txn
358− onSent={this.setTxnHashCursor}
282+ onSent={this.setTxnHashCursor}
359− setTxnHashCursor={this.setTxnHashCursor}
283+ setTxnHashCursor={this.setTxnHashCursor}
360− txnHashCursor={txnHashCursor}
284+ txnHashCursor={txnHashCursor}
361− setTxnConfirmations={this.setTxnConfirmations}
362− txnConfirmations={txnConfirmations}
363− />
285+ />
364−
286+
365− <div className={'push'} />
287+ <div className={'push'} />
288+ </Row>
289+
290+ <Footer />
291+ </VariableWidthColumn>
366 </Row>
292 </Row>
367−
293+ </Container>
368− <Footer />
294+ </TxnConfirmationsProvider>
369− </Col>
295+ </HistoryProvider>
370− </Row>
371− </Container>
372 );
296 );
373 }
297 }
374}
298}
src/bridge/components/DropdownItem.js+1−3
@@ -10,9 +10,7 @@ const DropdownItem = props => {
10 <button
10 <button
11 disabled={props.disabled}
11 disabled={props.disabled}
12 style={props.style}
12 style={props.style}
13− className={`h-10 m-0 p-0 ph-2 bg-white flex align-center items-start bs-solid brw-2 blw-2 btw-0 bbw-0 sans ${_disabled} ${
13+ className={`h-10 m-0 p-0 ph-2 bg-white flex align-center items-start bs-solid brw-2 blw-2 btw-0 bbw-0 sans ${_disabled} ${props.className}`}
14− props.className
15− }`}
16 onClick={props.onClick}>
14 onClick={props.onClick}>
17 {props.children}
15 {props.children}
18 </button>
16 </button>
src/bridge/components/Header.js+46−43
@@ -1,58 +1,61 @@
1import React from 'react';
1import React from 'react';
2import { Button, Chevron } from '../components/Base';
2import { Button, Chevron } from '../components/Base';
3
3
4−import { renderRoute } from '../lib/router';
4+import { getRouteBreadcrumb } from '../lib/router';
5+import { ROUTE_NAMES } from '../lib/routeNames';
6+import { useHistory } from '../store/history';
5import { isLast } from '../lib/lib';
7import { isLast } from '../lib/lib';
6
8
7−const Crumbs = props => {
9+function Crumbs(props) {
8− const { routeCrumbs, skipRoute } = props;
10+ const history = useHistory();
11+
12+ return (
13+ <>
14+ {history.routes.map((route, idx) => {
15+ return (
16+ <div key={`history-${idx}`} className={'flex items-center'}>
17+ <Button
18+ prop-type={'link'}
19+ prop-size={'sm'}
20+ key={`history-button-${idx}`}
21+ onClick={() => history.pop(history.size - idx - 1)}>
22+ {getRouteBreadcrumb(props, route)}
23+ </Button>
24+
25+ {isLast(history.size, idx) ? (
26+ <div />
27+ ) : (
28+ <Chevron className={'h-4 mh-2'} />
29+ )}
30+ </div>
31+ );
32+ })}
33+ </>
34+ );
35+}
36+
37+function Header(props) {
9− const history = routeCrumbs.reverse();
38+ const history = useHistory();
39+
40+ const showCrumbs = !history.includes(ROUTE_NAMES.INVITE_TICKET);
10
41
11− // FIXME probably more straightforward to render them normally and just
42+ if (showCrumbs) {
12− // return the reversed array of renders
13− const rendered = history.map((route, idx) => {
14 return (
43 return (
15− <div className={'flex items-center'} key={`history-${idx}`}>
44+ <div className={'flex items-center h-10'}>
16− <Button
45+ <Crumbs
17− prop-type={'link'}
46+ networkType={props.networkType}
18− prop-size={'sm'}
47+ wallet={props.wallet}
19− key={`history-button-${idx}`}
48+ pointCursor={props.pointCursor}
20− onClick={() => skipRoute(history.size - idx - 1)}>
49+ />
21− {renderRoute(props, route)}
22− </Button>
23−
24− {isLast(history.size, idx) ? (
25− <div />
26− ) : (
27− <Chevron className={'h-4 mh-2'} />
28− )}
29 </div>
50 </div>
30 );
51 );
31− });
52+ }
32−
33− return rendered;
34−};
35−
36−const Header = props => {
37− const crumbs = (
38− <div className={'flex items-center h-10'}>
39− <Crumbs
40− routeCrumbs={props.routeCrumbs}
41− skipRoute={props.skipRoute}
42− networkType={props.networkType}
43− wallet={props.wallet}
44− pointCursor={props.pointCursor}
45− />
46− </div>
47− );
48
53
49− const noCrumbs = (
54+ return (
50− <h2 className="mt-9 clickable" onClick={() => props.skipRoute(1)}>
55+ <h2 className="mt-9 clickable" onClick={() => history.pop()}>
51 Bridge
56 Bridge
52 </h2>
57 </h2>
53 );
58 );
54−
55− return props.showCrumbs ? crumbs : noCrumbs;
56−};
59+}
57
60
58export default Header;
61export default Header;
src/bridge/components/HorizontalSelector.js+1−3
@@ -22,9 +22,7 @@ class HorizontalSelector extends React.Component {
22 let active = opt.value === this.state.option ? 'btn-primary active' : '';
22 let active = opt.value === this.state.option ? 'btn-primary active' : '';
23 return (
23 return (
24 <button
24 <button
25− className={`btn ${active} h-10 ph-4 flex sans ${
25+ className={`btn ${active} h-10 ph-4 flex sans ${this.props.className}`}
26− this.props.className
27− }`}
28 value={opt.value}
26 value={opt.value}
29 onClick={() => this.selectOption(opt.value)}>
27 onClick={() => this.selectOption(opt.value)}>
30 {opt.title}
28 {opt.title}
src/bridge/components/OldHeader.js+2−2
@@ -1,7 +1,7 @@
1import React from 'react';
1import React from 'react';
2import { Button, Chevron } from '../components/Base';
2import { Button, Chevron } from '../components/Base';
3
3
4−import { renderRoute } from '../lib/router';
4+import { getRouteBreadcrumb } from '../lib/router';
5import { isLast } from '../lib/lib';
5import { isLast } from '../lib/lib';
6
6
7const Crumbs = props => {
7const Crumbs = props => {
@@ -19,7 +19,7 @@ const Crumbs = props => {
19 color={'black'}
19 color={'black'}
20 key={`history-button-${idx}`}
20 key={`history-button-${idx}`}
21 onClick={() => skipRoute(history.size - idx - 1)}>
21 onClick={() => skipRoute(history.size - idx - 1)}>
22− {`${renderRoute(props, route)}`}
22+ {`${getRouteBreadcrumb(props, route)}`}
23 </Button>
23 </Button>
24
24
25 {isLast(history.size, idx) ? (
25 {isLast(history.size, idx) ? (
src/bridge/components/RenderedPoint.js+1−1
@@ -5,7 +5,7 @@ import { Button } from './Base';
5import { pour } from 'sigil-js';
5import { pour } from 'sigil-js';
6import * as ob from 'urbit-ob';
6import * as ob from 'urbit-ob';
7
7
8−import { ROUTE_NAMES } from '../lib/router';
8+import { ROUTE_NAMES } from '../lib/routeNames';
9import ReactSVGComponents from './ReactSVGComponents';
9import ReactSVGComponents from './ReactSVGComponents';
10
10
11const RenderedPoint = props => {
11const RenderedPoint = props => {
src/bridge/components/StatelessTransaction.js+6−4
@@ -9,7 +9,8 @@ import { CheckboxButton, Input, InnerLabel, InnerLabelDropdown } from './Base';
9import { Warning } from '../components/Base';
9import { Warning } from '../components/Base';
10
10
11import { BRIDGE_ERROR } from '../lib/error';
11import { BRIDGE_ERROR } from '../lib/error';
12−import { ROUTE_NAMES } from '../lib/router';
12+import { ROUTE_NAMES } from '../lib/routeNames';
13+import { withHistory } from '../store/history';
13import * as tank from '../lib/tank';
14import * as tank from '../lib/tank';
14
15
15import {
16import {
@@ -20,6 +21,7 @@ import {
20 renderSignedTx,
21 renderSignedTx,
21 signTransaction,
22 signTransaction,
22} from '../lib/txn';
23} from '../lib/txn';
24+import { withTxnConfirmations } from '../store/txnConfirmations';
23
25
24const SUBMISSION_STATES = {
26const SUBMISSION_STATES = {
25 PROMPT: 'Send transaction',
27 PROMPT: 'Send transaction',
@@ -234,14 +236,14 @@ class StatelessTransaction extends React.Component {
234 )
236 )
235 .then(txHash => {
237 .then(txHash => {
236 props.onSent(Just(Ok(txHash)), state.stx.value);
238 props.onSent(Just(Ok(txHash)), state.stx.value);
237− props.popRoute();
238
239
239 let routeData = {};
240 let routeData = {};
240 if (props.networkSeed) {
241 if (props.networkSeed) {
241 props.setNetworkSeedCache(props.networkSeed);
242 props.setNetworkSeedCache(props.networkSeed);
242 routeData.promptKeyfile = true;
243 routeData.promptKeyfile = true;
243 }
244 }
245+
244− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION, routeData);
246+ props.history.popAndPush(ROUTE_NAMES.SENT_TRANSACTION, routeData);
245 })
247 })
246 .catch(err => {
248 .catch(err => {
247 this.setState({
249 this.setState({
@@ -577,4 +579,4 @@ class StatelessTransaction extends React.Component {
577 }
579 }
578}
580}
579
581
580−export default StatelessTransaction;
582+export default withTxnConfirmations(withHistory(StatelessTransaction));
src/bridge/components/icons/Chevron.js+1−3
@@ -4,9 +4,7 @@ import PropTypes from 'prop-types';
4const Chevron = props => {
4const Chevron = props => {
5 return (
5 return (
6 <img
6 <img
7− src={`data:image/svg+xml;utf8,<svg width="11" height="24" viewBox="0 0 11 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 12L10.387 12.3166L10.646 12L10.387 11.6833L10 12ZM0.613022 1.31662L9.61302 12.3166L10.387 11.6833L1.38698 0.68338L0.613022 1.31662ZM9.61302 11.6833L0.613021 22.6834L1.38698 23.3166L10.387 12.3166L9.61302 11.6833Z" stroke="${
7+ src={`data:image/svg+xml;utf8,<svg width="11" height="24" viewBox="0 0 11 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 12L10.387 12.3166L10.646 12L10.387 11.6833L10 12ZM0.613022 1.31662L9.61302 12.3166L10.387 11.6833L1.38698 0.68338L0.613022 1.31662ZM9.61302 11.6833L0.613021 22.6834L1.38698 23.3166L10.387 12.3166L9.61302 11.6833Z" stroke="${props.color}" stroke-width="${props.strokeWidth}" fill="${props.color}"/></svg>`}
8− props.color
9− }" stroke-width="${props.strokeWidth}" fill="${props.color}"/></svg>`}
10 alt=""
8 alt=""
11 style={props.style}
9 style={props.style}
12 className={props.className}
10 className={props.className}
src/bridge/lib/flags.jsnew file+1
@@ -0,0 +1 @@
1+export const isLocal = process.env.NODE_ENV === 'development';
src/bridge/lib/invite.js+1−1
@@ -2,7 +2,7 @@ import { Just, Nothing } from 'folktale/maybe';
2import Tx from 'ethereumjs-tx';
2import Tx from 'ethereumjs-tx';
3
3
4import * as azimuth from 'azimuth-js';
4import * as azimuth from 'azimuth-js';
5−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
5+import * as kg from 'urbit-key-generation/dist/index';
6import * as wg from '../../walletgen/lib/lib.js';
6import * as wg from '../../walletgen/lib/lib.js';
7import * as tank from './tank';
7import * as tank from './tank';
8
8
src/bridge/lib/keys.js+3−3
@@ -4,7 +4,7 @@ import * as need from '../lib/need';
4
4
5import * as noun from '../nockjs/noun';
5import * as noun from '../nockjs/noun';
6import * as serial from '../nockjs/serial';
6import * as serial from '../nockjs/serial';
7−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
7+import * as kg from 'urbit-key-generation/dist/index';
8
8
9import { BRIDGE_ERROR } from './error';
9import { BRIDGE_ERROR } from './error';
10import { WALLET_NAMES, eqAddr } from './wallet';
10import { WALLET_NAMES, eqAddr } from './wallet';
@@ -21,7 +21,7 @@ const b64 = buf => {
21
21
22 // prettier-ignore
22 // prettier-ignore
23 const trans = j =>
23 const trans = j =>
24− 10 > j
24+ 10 > j
25 ? j + 48
25 ? j + 48
26 : 36 > j
26 : 36 > j
27 ? j + 87
27 ? j + 87
@@ -29,7 +29,7 @@ const b64 = buf => {
29 ? j + 29
29 ? j + 29
30 : 62 === j
30 : 62 === j
31 ? 45
31 ? 45
32− : 126
32+ : 126;
33
33
34 return (
34 return (
35 '0w' +
35 '0w' +
src/bridge/lib/routeNames.jsnew file+33
@@ -0,0 +1,33 @@
1+export const ROUTE_NAMES = {
2+ DEFAULT: Symbol('DEFAULT'),
3+ //
4+ INVITE_TICKET: Symbol('INVITE_TICKET'),
5+ INVITE_TRANSACTIONS: Symbol('INVITE_TRANSACTIONS'),
6+ INVITES_SEND: Symbol('INVITES_SEND'),
7+ INVITES_MANAGE: Symbol('INVITES_MANAGE'),
8+ //
9+ ACCEPT_TRANSFER: Symbol('ACCEPT_TRANSFER'),
10+ CANCEL_TRANSFER: Symbol('CANCEL_TRANSFER'),
11+ LANDING: Symbol('LANDING'),
12+ NETWORK: Symbol('NETWORK'),
13+ WALLET: Symbol('WALLET'),
14+ MNEMONIC: Symbol('MNEMONIC'),
15+ TICKET: Symbol('TICKET'),
16+ SHARDS: Symbol('SHARDS'),
17+ LEDGER: Symbol('LEDGER'),
18+ TREZOR: Symbol('TREZOR'),
19+ PRIVATE_KEY: Symbol('PRIVATE_KEY'),
20+ KEYSTORE: Symbol('KEYSTORE'),
21+ VIEW_SHIP: Symbol('VIEW_SHIP'),
22+ SHIPS: Symbol('SHIPS'),
23+ SHIP: Symbol('SHIP'),
24+ SET_MANAGEMENT_PROXY: Symbol('SET_MANAGEMENT_PROXY'),
25+ SET_SPAWN_PROXY: Symbol('SET_SPAWN_PROXY'),
26+ SET_TRANSFER_PROXY: Symbol('SET_TRANSFER_PROXY'),
27+ CREATE_GALAXY: Symbol('CREATE_GALAXY'),
28+ ISSUE_CHILD: Symbol('ISSUE_CHILD'),
29+ SET_KEYS: Symbol('SET_KEYS'),
30+ TRANSFER: Symbol('TRANSFER'),
31+ SENT_TRANSACTION: Symbol('SENT_TRANSACTION'),
32+ GEN_KEYFILE: Symbol('GEN_KEYFILE'),
33+};
src/bridge/lib/router.js+92−134
@@ -1,15 +1,11 @@
1+import React from 'react';
1import * as ob from 'urbit-ob';
2import * as ob from 'urbit-ob';
2import * as need from '../lib/need';
3import * as need from '../lib/need';
3
4
4−import React from 'react';
5−
6import Landing from '../views/Landing';
5import Landing from '../views/Landing';
7−
8import InviteTicket from '../views/InviteTicket';
6import InviteTicket from '../views/InviteTicket';
9−
10import InvitesSend from '../views/InvitesSend.js';
7import InvitesSend from '../views/InvitesSend.js';
11import InvitesManage from '../views/InvitesManage.js';
8import InvitesManage from '../views/InvitesManage.js';
12−
13import AcceptTransfer from '../views/AcceptTransfer';
9import AcceptTransfer from '../views/AcceptTransfer';
14import CancelTransfer from '../views/CancelTransfer';
10import CancelTransfer from '../views/CancelTransfer';
15import CreateGalaxy from '../views/CreateGalaxy';
11import CreateGalaxy from '../views/CreateGalaxy';
@@ -38,94 +34,55 @@ import Wallet from '../views/Wallet';
38
34
39import { EthereumWallet } from './wallet';
35import { EthereumWallet } from './wallet';
40import { renderNetworkType } from './network';
36import { renderNetworkType } from './network';
37+import { ROUTE_NAMES } from './routeNames';
41
38
42−const ROUTE_NAMES = {
39+const ROUTES = {
43− DEFAULT: Symbol('DEFAULT'),
40+ [ROUTE_NAMES.DEFAULT]: Landing,
44− //
41+ [ROUTE_NAMES.LANDING]: Landing,
45− INVITE_TICKET: Symbol('INVITE_TICKET'),
42+ [ROUTE_NAMES.INVITE_TICKET]: InviteTicket,
46− INVITE_TRANSACTIONS: Symbol('INVITE_TRANSACTIONS'),
43+ [ROUTE_NAMES.INVITES_SEND]: InvitesSend,
47− INVITES_SEND: Symbol('INVITES_SEND'),
44+ [ROUTE_NAMES.INVITES_MANAGE]: InvitesManage,
48− INVITES_MANAGE: Symbol('INVITES_MANAGE'),
45+ [ROUTE_NAMES.ACCEPT_TRANSFER]: AcceptTransfer,
49− //
46+ [ROUTE_NAMES.CANCEL_TRANSFER]: CancelTransfer,
50− ACCEPT_TRANSFER: Symbol('ACCEPT_TRANSFER'),
47+ [ROUTE_NAMES.NETWORK]: Network,
51− CANCEL_TRANSFER: Symbol('CANCEL_TRANSFER'),
48+ [ROUTE_NAMES.WALLET]: Wallet,
52− LANDING: Symbol('LANDING'),
49+ [ROUTE_NAMES.VIEW_SHIP]: ViewPoint,
53− NETWORK: Symbol('NETWORK'),
50+ [ROUTE_NAMES.MNEMONIC]: Mnemonic,
54− WALLET: Symbol('WALLET'),
51+ [ROUTE_NAMES.TICKET]: Ticket,
55− MNEMONIC: Symbol('MNEMONIC'),
52+ [ROUTE_NAMES.SHARDS]: Shards,
56− TICKET: Symbol('TICKET'),
53+ [ROUTE_NAMES.LEDGER]: Ledger,
57− SHARDS: Symbol('SHARDS'),
54+ [ROUTE_NAMES.TREZOR]: Trezor,
58− LEDGER: Symbol('LEDGER'),
55+ [ROUTE_NAMES.PRIVATE_KEY]: PrivateKey,
59− TREZOR: Symbol('TREZOR'),
56+ [ROUTE_NAMES.KEYSTORE]: Keystore,
60− PRIVATE_KEY: Symbol('PRIVATE_KEY'),
57+ [ROUTE_NAMES.SHIPS]: Points,
61− KEYSTORE: Symbol('KEYSTORE'),
58+ [ROUTE_NAMES.SHIP]: Point,
62− VIEW_SHIP: Symbol('VIEW_SHIP'),
63− SHIPS: Symbol('SHIPS'),
64− SHIP: Symbol('SHIP'),
65− SET_MANAGEMENT_PROXY: Symbol('SET_MANAGEMENT_PROXY'),
59+ [ROUTE_NAMES.SET_MANAGEMENT_PROXY]: SetManagementProxy,
66− SET_SPAWN_PROXY: Symbol('SET_SPAWN_PROXY'),
60+ [ROUTE_NAMES.SET_SPAWN_PROXY]: SetSpawnProxy,
67− SET_TRANSFER_PROXY: Symbol('SET_TRANSFER_PROXY'),
61+ [ROUTE_NAMES.SET_TRANSFER_PROXY]: SetTransferProxy,
68− CREATE_GALAXY: Symbol('CREATE_GALAXY'),
62+ [ROUTE_NAMES.CREATE_GALAXY]: CreateGalaxy,
69− ISSUE_CHILD: Symbol('ISSUE_CHILD'),
63+ [ROUTE_NAMES.ISSUE_CHILD]: IssueChild,
70− SET_KEYS: Symbol('SET_KEYS'),
64+ [ROUTE_NAMES.SET_KEYS]: SetKeys,
71− TRANSFER: Symbol('TRANSFER'),
65+ [ROUTE_NAMES.TRANSFER]: Transfer,
72− SENT_TRANSACTION: Symbol('SENT_TRANSACTION'),
66+ [ROUTE_NAMES.SENT_TRANSACTION]: SentTransaction,
73− GEN_KEYFILE: Symbol('GEN_KEYFILE'),
67+ [ROUTE_NAMES.GEN_KEYFILE]: GenKeyfile,
74};
68};
75
69
76−const createRoutes = () => {
70+export const getRouteBreadcrumb = (props, route) => {
77− const routes = {};
78− routes[ROUTE_NAMES.DEFAULT] = Landing;
79− //
80− routes[ROUTE_NAMES.INVITE_TICKET] = InviteTicket;
81− routes[ROUTE_NAMES.INVITES_SEND] = InvitesSend;
82− routes[ROUTE_NAMES.INVITES_MANAGE] = InvitesManage;
83− //
84− routes[ROUTE_NAMES.ACCEPT_TRANSFER] = AcceptTransfer;
85− routes[ROUTE_NAMES.CANCEL_TRANSFER] = CancelTransfer;
86− routes[ROUTE_NAMES.LANDING] = Landing;
87− routes[ROUTE_NAMES.NETWORK] = Network;
88− routes[ROUTE_NAMES.WALLET] = Wallet;
89− routes[ROUTE_NAMES.VIEW_SHIP] = ViewPoint;
90− routes[ROUTE_NAMES.MNEMONIC] = Mnemonic;
91− routes[ROUTE_NAMES.TICKET] = Ticket;
92− routes[ROUTE_NAMES.SHARDS] = Shards;
93− routes[ROUTE_NAMES.LEDGER] = Ledger;
94− routes[ROUTE_NAMES.TREZOR] = Trezor;
95− routes[ROUTE_NAMES.PRIVATE_KEY] = PrivateKey;
96− routes[ROUTE_NAMES.KEYSTORE] = Keystore;
97− routes[ROUTE_NAMES.SHIPS] = Points;
98− routes[ROUTE_NAMES.SHIP] = Point;
99− routes[ROUTE_NAMES.SET_MANAGEMENT_PROXY] = SetManagementProxy;
100− routes[ROUTE_NAMES.SET_SPAWN_PROXY] = SetSpawnProxy;
101− routes[ROUTE_NAMES.SET_TRANSFER_PROXY] = SetTransferProxy;
102− routes[ROUTE_NAMES.CREATE_GALAXY] = CreateGalaxy;
103− routes[ROUTE_NAMES.ISSUE_CHILD] = IssueChild;
104− routes[ROUTE_NAMES.SET_KEYS] = SetKeys;
105− routes[ROUTE_NAMES.TRANSFER] = Transfer;
106− routes[ROUTE_NAMES.SENT_TRANSACTION] = SentTransaction;
107− routes[ROUTE_NAMES.GEN_KEYFILE] = GenKeyfile;
108− return routes;
109−};
110−
111−const ROUTES = createRoutes();
112−
113−const renderRoute = (props, route) => {
114 const { wallet, networkType } = props;
71 const { wallet, networkType } = props;
115− return route === ROUTE_NAMES.LANDING
72+
116− ? 'Bridge'
73+ switch (route.name) {
117− : route === ROUTE_NAMES.INVITE_TICKET
74+ case ROUTE_NAMES.INVITE_TICKET:
118− ? 'Invite code'
75+ return 'Invite code';
119− : route === ROUTE_NAMES.INVITE_TRANSACTIONS
76+ case ROUTE_NAMES.INVITE_TRANSACTIONS:
120− ? 'Setting up new wallet'
77+ return 'Setting up new wallet';
121− : route === ROUTE_NAMES.INVITES_SEND
78+ case ROUTE_NAMES.INVITES_SEND:
122− ? 'Send invites'
79+ return 'Send invites';
123− : route === ROUTE_NAMES.INVITES_MANAGE
80+ case ROUTE_NAMES.INVITES_MANAGE:
124− ? 'Manage invites'
81+ return 'Manage invites';
125− : route === ROUTE_NAMES.NETWORK
82+ case ROUTE_NAMES.NETWORK:
126− ? `${renderNetworkType(networkType)}`
83+ return `${renderNetworkType(networkType)}`;
127− : route === ROUTE_NAMES.WALLET
84+ case ROUTE_NAMES.WALLET:
128− ? wallet.matchWith({
85+ return wallet.matchWith({
129 Nothing: () => 'Wallet',
86 Nothing: () => 'Wallet',
130 Just: wal =>
87 Just: wal =>
131 wal.value instanceof EthereumWallet ? (
88 wal.value instanceof EthereumWallet ? (
@@ -133,50 +90,51 @@ const renderRoute = (props, route) => {
133 ) : (
90 ) : (
134 <span className="text-mono">{wal.value.address}</span>
91 <span className="text-mono">{wal.value.address}</span>
135 ),
92 ),
136− })
93+ });
137− : route === ROUTE_NAMES.MNEMONIC
94+ case ROUTE_NAMES.MNEMONIC:
138− ? 'Mnemonic'
95+ return 'Mnemonic';
139− : route === ROUTE_NAMES.TICKET
96+ case ROUTE_NAMES.TICKET:
140− ? 'Urbit Ticket'
97+ return 'Urbit Ticket';
141− : route === ROUTE_NAMES.SHARDS
98+ case ROUTE_NAMES.SHARDS:
142− ? 'Urbit Ticket'
99+ return 'Urbit Ticket';
143− : route === ROUTE_NAMES.LEDGER
100+ case ROUTE_NAMES.LEDGER:
144− ? 'Ledger'
101+ return 'Ledger';
145− : route === ROUTE_NAMES.TREZOR
102+ case ROUTE_NAMES.TREZOR:
146− ? 'Trezor'
103+ return 'Trezor';
147− : route === ROUTE_NAMES.PRIVATE_KEY
104+ case ROUTE_NAMES.PRIVATE_KEY:
148− ? 'Private Key'
105+ return 'Private Key';
149− : route === ROUTE_NAMES.KEYSTORE
106+ case ROUTE_NAMES.KEYSTORE:
150− ? 'Keystore File'
107+ return 'Keystore File';
151− : route === ROUTE_NAMES.SHIPS
108+ case ROUTE_NAMES.SHIPS:
152− ? 'Points'
109+ return 'Points';
153− : route === ROUTE_NAMES.VIEW_SHIP
110+ case ROUTE_NAMES.VIEW_SHIP:
154− ? 'View'
111+ return 'View';
155− : route === ROUTE_NAMES.SHIP
112+ case ROUTE_NAMES.SHIP:
156− ? ob.patp(need.pointCursor(props))
113+ return ob.patp(need.pointCursor(props));
157− : route === ROUTE_NAMES.SET_TRANSFER_PROXY ||
114+ case ROUTE_NAMES.SET_TRANSFER_PROXY:
158− route === ROUTE_NAMES.SET_MANAGEMENT_PROXY ||
115+ case ROUTE_NAMES.SET_MANAGEMENT_PROXY:
159− route === ROUTE_NAMES.SET_SPAWN_PROXY
116+ case ROUTE_NAMES.SET_SPAWN_PROXY:
160− ? 'Set Proxy'
117+ return 'Set Proxy';
161− : route === ROUTE_NAMES.CREATE_GALAXY
118+ case ROUTE_NAMES.CREATE_GALAXY:
162− ? 'Create Galaxy'
119+ return 'Create Galaxy';
163− : route === ROUTE_NAMES.ISSUE_CHILD
120+ case ROUTE_NAMES.ISSUE_CHILD:
164− ? 'Issue Child'
121+ return 'Issue Child';
165− : route === ROUTE_NAMES.TRANSFER
122+ case ROUTE_NAMES.TRANSFER:
166− ? 'Transfer'
123+ return 'Transfer';
167− : route === ROUTE_NAMES.ACCEPT_TRANSFER
124+ case ROUTE_NAMES.ACCEPT_TRANSFER:
168− ? 'Accept Transfer'
125+ return 'Accept Transfer';
169− : route === ROUTE_NAMES.CANCEL_TRANSFER
126+ case ROUTE_NAMES.CANCEL_TRANSFER:
170− ? 'Cancel Transfer'
127+ return 'Cancel Transfer';
171− : route === ROUTE_NAMES.GEN_KEYFILE
128+ case ROUTE_NAMES.GEN_KEYFILE:
172− ? 'Keyfile'
129+ return 'Keyfile';
173− : route === ROUTE_NAMES.SET_KEYS
130+ case ROUTE_NAMES.SET_KEYS:
174− ? 'Configure Keys'
131+ return 'Configure Keys';
175− : route === ROUTE_NAMES.SENT_TRANSACTION
132+ case ROUTE_NAMES.SENT_TRANSACTION:
176− ? 'Txn'
133+ return 'Txn';
134+ case ROUTE_NAMES.LANDING:
135+ default:
177− : 'Bridge';
136+ return 'Bridge';
137+ }
178};
138};
179
139
180−const router = route => ROUTES[route];
140+export const router = route => ROUTES[route.name];
181−
182−export { ROUTE_NAMES, router, renderRoute };
src/bridge/lib/wallet.js+1−1
@@ -5,7 +5,7 @@ import * as lodash from 'lodash';
5import Maybe from 'folktale/maybe';
5import Maybe from 'folktale/maybe';
6import * as secp256k1 from 'secp256k1';
6import * as secp256k1 from 'secp256k1';
7import * as ob from 'urbit-ob';
7import * as ob from 'urbit-ob';
8−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
8+import * as kg from 'urbit-key-generation/dist/index';
9import { isAddress } from 'web3-utils';
9import { isAddress } from 'web3-utils';
10
10
11const DEFAULT_HD_PATH = "m/44'/60'/0'/0/0";
11const DEFAULT_HD_PATH = "m/44'/60'/0'/0/0";
src/bridge/lib/web3.jsnew file+23
@@ -0,0 +1,23 @@
1+import * as azimuth from 'azimuth-js';
2+import Web3 from 'web3';
3+
4+import { CONTRACT_ADDRESSES } from './contracts';
5+import { NETWORK_NAMES } from './network';
6+
7+export const initWeb3 = networkType => {
8+ if (networkType === NETWORK_NAMES.MAINNET) {
9+ const endpoint = `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
10+
11+ const provider = new Web3.providers.HttpProvider(endpoint);
12+ const web3 = new Web3(provider);
13+ const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.MAINNET);
14+ return { web3: web3, contracts: contracts };
15+ } else if (networkType === NETWORK_NAMES.LOCAL) {
16+ const protocol = process.env.NODE_ENV === 'development' ? 'ws' : 'wss';
17+ const endpoint = `${protocol}://localhost:8545`;
18+ const provider = new Web3.providers.WebsocketProvider(endpoint);
19+ const web3 = new Web3(provider);
20+ const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.DEV);
21+ return { web3: web3, contracts: contracts };
22+ }
23+};
src/bridge/store/history.jsnew file+73
@@ -0,0 +1,73 @@
1+import React, { forwardRef, useContext, useState, useEffect } from 'react';
2+import { last, includes } from 'lodash';
3+
4+import { BRIDGE_ERROR } from '../lib/error';
5+import { ROUTE_NAMES } from '../lib/routeNames';
6+
7+export const HistoryContext = React.createContext(null);
8+
9+function _useHistory(initialRoutes = []) {
10+ const [history, setHistory] = useState(initialRoutes);
11+
12+ const value = {
13+ routes: history,
14+ push: (name, data) => {
15+ if (!includes(ROUTE_NAMES, name)) {
16+ throw BRIDGE_ERROR.INVALID_ROUTE;
17+ }
18+
19+ setHistory(history => [...history, { name, data }]);
20+ },
21+ popAndPush: (name, data = {}) =>
22+ setHistory(history => [
23+ ...history.slice(0, history.length - 1),
24+ { name, data },
25+ ]),
26+ pop: (count = 1) =>
27+ setHistory(history => [...history.slice(0, history.length - count)]),
28+ peek: () => last(history),
29+ size: history.length,
30+ includes: name => includes(history.map(r => r.name), name),
31+ data: last(history).data,
32+ };
33+
34+ // Scroll to top of page with each route transition.
35+ useEffect(() => window.scrollTo(0, 0), [history]);
36+
37+ // set up handlers
38+ useEffect(() => {
39+ window.history.pushState(null, null, null);
40+
41+ window.onpopstate = e => {
42+ window.history.pushState(null, null, null);
43+ value.pop();
44+ };
45+
46+ // TODO: disposer functon
47+ });
48+
49+ return value;
50+}
51+
52+export function HistoryProvider({ initialRoutes, children }) {
53+ const history = _useHistory(initialRoutes);
54+
55+ return (
56+ <HistoryContext.Provider value={history}>
57+ {children}
58+ </HistoryContext.Provider>
59+ );
60+}
61+
62+// Hook version
63+export function useHistory() {
64+ return useContext(HistoryContext);
65+}
66+
67+// HOC version
68+export const withHistory = Component =>
69+ forwardRef((props, ref) => (
70+ <HistoryContext.Consumer>
71+ {history => <Component ref={ref} history={history} {...props} />}
72+ </HistoryContext.Consumer>
73+ ));
src/bridge/store/txnConfirmations.jsnew file+39
@@ -0,0 +1,39 @@
1+import React, { forwardRef, useContext, useState } from 'react';
2+
3+export const TxnConfirmationsContext = React.createContext(null);
4+
5+export function TxnConfirmationsProvider({ children }) {
6+ const [confirmations, setConfirmations] = useState({});
7+
8+ const setTxnConfirmations = (txnHash, txnConfirmations) => {
9+ setConfirmations({
10+ ...confirmations,
11+ [txnHash]: txnConfirmations,
12+ });
13+ };
14+
15+ return (
16+ <TxnConfirmationsContext.Provider
17+ value={{
18+ txnConfirmations: confirmations,
19+ setTxnConfirmations,
20+ }}>
21+ {children}
22+ </TxnConfirmationsContext.Provider>
23+ );
24+}
25+
26+// HOC version
27+export const withTxnConfirmations = Component =>
28+ forwardRef((props, ref) => (
29+ <TxnConfirmationsContext.Consumer>
30+ {txnConfirmations => (
31+ <Component ref={ref} {...txnConfirmations} {...props} />
32+ )}
33+ </TxnConfirmationsContext.Consumer>
34+ ));
35+
36+// Hook version
37+export function useTxnConfirmations() {
38+ return useContext(TxnConfirmationsContext);
39+}
src/bridge/views/GenKeyfile.js+1−1
@@ -6,7 +6,7 @@ import { Button } from '../components/Base';
6import { Row, Col, H1, P } from '../components/Base';
6import { Row, Col, H1, P } from '../components/Base';
7
7
8import * as ob from 'urbit-ob';
8import * as ob from 'urbit-ob';
9−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
9+import * as kg from 'urbit-key-generation/dist/index';
10import saveAs from 'file-saver';
10import saveAs from 'file-saver';
11
11
12import { attemptSeedDerivation, genKey } from '../lib/keys';
12import { attemptSeedDerivation, genKey } from '../lib/keys';
src/bridge/views/InviteTicket.js+6−5
@@ -14,7 +14,8 @@ import * as azimuth from 'azimuth-js';
14import * as need from '../lib/need';
14import * as need from '../lib/need';
15
15
16import { randomPatq } from '../lib/lib';
16import { randomPatq } from '../lib/lib';
17−import { ROUTE_NAMES } from '../lib/router';
17+import { ROUTE_NAMES } from '../lib/routeNames';
18+import { withHistory } from '../store/history';
18import {
19import {
19 DEFAULT_HD_PATH,
20 DEFAULT_HD_PATH,
20 ownershipWalletFromTicket,
21 ownershipWalletFromTicket,
@@ -63,8 +64,8 @@ class InviteTicket extends React.Component {
63 }
64 }
64
65
65 navigateLogin() {
66 navigateLogin() {
66− this.props.popRoute();
67+ this.props.history.pop();
67− this.props.pushRoute(ROUTE_NAMES.NETWORK);
68+ this.props.history.push(ROUTE_NAMES.NETWORK);
68 }
69 }
69
70
70 handleInviteTicketInput(inviteTicket) {
71 handleInviteTicketInput(inviteTicket) {
@@ -310,7 +311,7 @@ class InviteTicket extends React.Component {
310 updateProgress: this.updateProgress,
311 updateProgress: this.updateProgress,
311 }).then(() => {
312 }).then(() => {
312 setTimeout(() => {
313 setTimeout(() => {
313− this.props.popRoute();
314+ this.props.history.pop();
314 }, 5000);
315 }, 5000);
315 });
316 });
316 }
317 }
@@ -421,4 +422,4 @@ class InviteTicket extends React.Component {
421 }
422 }
422}
423}
423
424
424−export default InviteTicket;
425+export default withHistory(InviteTicket);
src/bridge/views/Keystore.js+5−7
@@ -7,7 +7,8 @@ import { Input, InnerLabel, InputCaption } from '../components/Base';
7import { Row, Col, H1, H3, Warning } from '../components/Base';
7import { Row, Col, H1, H3, Warning } from '../components/Base';
8
8
9import { BRIDGE_ERROR } from '../lib/error';
9import { BRIDGE_ERROR } from '../lib/error';
10−import { ROUTE_NAMES } from '../lib/router';
10+import { ROUTE_NAMES } from '../lib/routeNames';
11+import { withHistory } from '../store/history';
11import { EthereumWallet } from '../lib/wallet';
12import { EthereumWallet } from '../lib/wallet';
12
13
13class Keystore extends React.Component {
14class Keystore extends React.Component {
@@ -80,7 +81,7 @@ class Keystore extends React.Component {
80 };
81 };
81
82
82 render() {
83 render() {
83− const { pushRoute, popRoute, wallet } = this.props;
84+ const { history, wallet } = this.props;
84 const { keystore, password, decryptionProblem } = this.state;
85 const { keystore, password, decryptionProblem } = this.state;
85
86
86 const uploadButtonClass = keystore.matchWith({
87 const uploadButtonClass = keystore.matchWith({
@@ -149,10 +150,7 @@ class Keystore extends React.Component {
149 className={'mt-10'}
150 className={'mt-10'}
150 prop-size={'wide lg'}
151 prop-size={'wide lg'}
151 disabled={Nothing.hasInstance(wallet)}
152 disabled={Nothing.hasInstance(wallet)}
152− onClick={() => {
153− popRoute();
154− pushRoute(ROUTE_NAMES.SHIPS);
153+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
155− }}>
156 {'Continue →'}
154 {'Continue →'}
157 </Button>
155 </Button>
158 </Col>
156 </Col>
@@ -161,4 +159,4 @@ class Keystore extends React.Component {
161 }
159 }
162}
160}
163
161
164−export default Keystore;
162+export default withHistory(Keystore);
src/bridge/views/Landing.js+50−57
@@ -3,70 +3,63 @@ import { Button } from '../components/Base';
3import { Row, Col } from '../components/Base';
3import { Row, Col } from '../components/Base';
4import { H1, P } from '../components/Base';
4import { H1, P } from '../components/Base';
5
5
6−import { ROUTE_NAMES } from '../lib/router';
6+import { ROUTE_NAMES } from '../lib/routeNames';
7+import { useHistory } from '../store/history';
7
8
8−const Landing = props => (
9+function Landing(props) {
9− <Row>
10+ const history = useHistory();
10− <Col>
11− <H1>{'Welcome'}</H1>
12
11
13− <P>
12+ return (
14− {'Bridge is a tool for managing and viewing assets on ' +
13+ <Row>
15− 'Azimuth, the Urbit address space.'}
14+ <Col>
16− </P>
15+ <H1>{'Welcome'}</H1>
17
16
18− <Button
17+ <P>
19− prop-type="link"
18+ {'Bridge is a tool for managing and viewing assets on ' +
20− prop-size="lg"
19+ 'Azimuth, the Urbit address space.'}
21− className={'mb-4 mt-8'}
20+ </P>
22− onClick={() => props.pushRoute(ROUTE_NAMES.INVITE_TICKET)}>
23− {'Claim an invite →'}
24− </Button>
25
21
26− <P>{'If you were sent an Azimuth invite code, start here.'}</P>
22+ <Button
23+ prop-type="link"
24+ prop-size="lg"
25+ className={'mb-4 mt-8'}
26+ onClick={() => history.push(ROUTE_NAMES.INVITE_TICKET)}>
27+ {'Claim an invite →'}
28+ </Button>
27
29
28− <Button
30+ <P>{'If you were sent an Azimuth invite code, start here.'}</P>
29− prop-type="link"
30− prop-size="lg"
31− className={'mb-4 mt-8'}
32− onClick={() => props.pushRoute(ROUTE_NAMES.NETWORK)}>
33− {'Unlock a Wallet →'}
34− </Button>
35
31
36− <P>
32+ <Button
37− {'If you own Azimuth assets and want to manage them in some ' +
33+ prop-type="link"
38− "way, start here. You'll need either your Urbit ticket or a " +
34+ prop-size="lg"
39− 'keypair.'}
35+ className={'mb-4 mt-8'}
40− </P>
36+ onClick={() => history.push(ROUTE_NAMES.NETWORK)}>
37+ {'Unlock a Wallet →'}
38+ </Button>
41
39
42− {
40+ <P>
43− <Row>
41+ {'If you own Azimuth assets and want to manage them in some ' +
44− <Col>
42+ "way, start here. You'll need either your Urbit ticket or a " +
45− <Button
43+ 'keypair.'}
46− prop-type={'link'}
44+ </P>
47− prop-size={'lg'}
48− className={'mb-4 mt-8'}
49− onClick={() => props.pushRoute(ROUTE_NAMES.VIEW_SHIP)}>
50− {'View a point →'}
51− </Button>
52− <P>{'View an Azimuth point without signing into a wallet.'}</P>
53− </Col>
54− </Row>
55− // FIXME add address view
56− // <LinkButton
57− // size={'l'}
58− // className={'mb-4 mt-10'}
59− // onClick={ () => props.pushRoute(ROUTE_NAMES.NETWORK) }
60− // >
61− // { 'View an Address →' }
62− // </LinkButton>
63
45
64− // <p>
46+ {
65− // { "Lorem" }
47+ <Row>
66− // </p>
48+ <Col>
67− }
49+ <Button
68− </Col>
50+ prop-type={'link'}
69− </Row>
51+ prop-size={'lg'}
52+ className={'mb-4 mt-8'}
53+ onClick={() => history.push(ROUTE_NAMES.VIEW_SHIP)}>
54+ {'View a point →'}
55+ </Button>
56+ <P>{'View an Azimuth point without signing into a wallet.'}</P>
57+ </Col>
58+ </Row>
59+ }
60+ </Col>
61+ </Row>
70−);
62+ );
63+}
71
64
72export default Landing;
65export default Landing;
src/bridge/views/Ledger.js+5−7
@@ -9,7 +9,8 @@ import Eth from '@ledgerhq/hw-app-eth';
9import * as secp256k1 from 'secp256k1';
9import * as secp256k1 from 'secp256k1';
10
10
11import { LEDGER_LIVE_PATH, LEDGER_LEGACY_PATH } from '../lib/ledger';
11import { LEDGER_LIVE_PATH, LEDGER_LEGACY_PATH } from '../lib/ledger';
12−import { ROUTE_NAMES } from '../lib/router';
12+import { ROUTE_NAMES } from '../lib/routeNames';
13+import { withHistory } from '../store/history';
13
14
14const chopHdPrefix = str => (str.slice(0, 2) === 'm/' ? str.slice(2) : str);
15const chopHdPrefix = str => (str.slice(0, 2) === 'm/' ? str.slice(2) : str);
15
16
@@ -76,7 +77,7 @@ class Ledger extends React.Component {
76 }
77 }
77
78
78 render() {
79 render() {
79− const { pushRoute, popRoute, wallet } = this.props;
80+ const { history, wallet } = this.props;
80 const { basePath, hdpath, account } = this.state;
81 const { basePath, hdpath, account } = this.state;
81 const { handlePathSelection, handleAccountSelection } = this;
82 const { handlePathSelection, handleAccountSelection } = this;
82
83
@@ -207,10 +208,7 @@ class Ledger extends React.Component {
207 className={'mt-8'}
208 className={'mt-8'}
208 prop-size={'wide lg'}
209 prop-size={'wide lg'}
209 disabled={Maybe.Nothing.hasInstance(wallet)}
210 disabled={Maybe.Nothing.hasInstance(wallet)}
210− onClick={() => {
211− popRoute();
212− pushRoute(ROUTE_NAMES.SHIPS);
211+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
213− }}>
214 {'Continue →'}
212 {'Continue →'}
215 </Button>
213 </Button>
216 </Col>
214 </Col>
@@ -219,4 +217,4 @@ class Ledger extends React.Component {
219 }
217 }
220}
218}
221
219
222−export default Ledger;
220+export default withHistory(Ledger);
src/bridge/views/Mnemonic.js+5−7
@@ -10,7 +10,8 @@ import {
10} from '../components/Base';
10} from '../components/Base';
11import { Row, Col, H1 } from '../components/Base';
11import { Row, Col, H1 } from '../components/Base';
12
12
13−import { ROUTE_NAMES } from '../lib/router';
13+import { ROUTE_NAMES } from '../lib/routeNames';
14+import { withHistory } from '../store/history';
14import { DEFAULT_HD_PATH, walletFromMnemonic } from '../lib/wallet';
15import { DEFAULT_HD_PATH, walletFromMnemonic } from '../lib/wallet';
15
16
16class Mnemonic extends React.Component {
17class Mnemonic extends React.Component {
@@ -91,7 +92,7 @@ class Mnemonic extends React.Component {
91 }
92 }
92
93
93 render() {
94 render() {
94− const { pushRoute, popRoute, wallet } = this.props;
95+ const { history, wallet } = this.props;
95 const { mnemonic, hdpath, exampleMnemonic, passphrase } = this.state;
96 const { mnemonic, hdpath, exampleMnemonic, passphrase } = this.state;
96
97
97 return (
98 return (
@@ -150,10 +151,7 @@ class Mnemonic extends React.Component {
150 <Button
151 <Button
151 className={'mt-10'}
152 className={'mt-10'}
152 disabled={Nothing.hasInstance(wallet)}
153 disabled={Nothing.hasInstance(wallet)}
153− onClick={() => {
154− popRoute();
155− pushRoute(ROUTE_NAMES.SHIPS);
154+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
156− }}>
157 {'Continue →'}
155 {'Continue →'}
158 </Button>
156 </Button>
159 </Col>
157 </Col>
@@ -162,4 +160,4 @@ class Mnemonic extends React.Component {
162 }
160 }
163}
161}
164
162
165−export default Mnemonic;
163+export default withHistory(Mnemonic);
src/bridge/views/Network.js+7−10
@@ -8,7 +8,8 @@ import Web3 from 'web3';
8
8
9import { CONTRACT_ADDRESSES } from '../lib/contracts';
9import { CONTRACT_ADDRESSES } from '../lib/contracts';
10import { NETWORK_NAMES, renderNetworkType } from '../lib/network';
10import { NETWORK_NAMES, renderNetworkType } from '../lib/network';
11−import { ROUTE_NAMES } from '../lib/router';
11+import { ROUTE_NAMES } from '../lib/routeNames';
12+import { withHistory } from '../store/history';
12
13
13class Network extends React.Component {
14class Network extends React.Component {
14 constructor(props) {
15 constructor(props) {
@@ -34,9 +35,7 @@ class Network extends React.Component {
34 if (network === NETWORK_NAMES.ROPSTEN) {
35 if (network === NETWORK_NAMES.ROPSTEN) {
35 setNetworkType(network);
36 setNetworkType(network);
36
37
37− const endpoint = `https://ropsten.infura.io/v3/${
38+ const endpoint = `https://ropsten.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
38− process.env.REACT_APP_INFURA_ENDPOINT
39− }`;
40
39
41 const provider = new Web3.providers.HttpProvider(endpoint);
40 const provider = new Web3.providers.HttpProvider(endpoint);
42 const web3 = new Web3(provider);
41 const web3 = new Web3(provider);
@@ -48,9 +47,7 @@ class Network extends React.Component {
48 if (network === NETWORK_NAMES.MAINNET) {
47 if (network === NETWORK_NAMES.MAINNET) {
49 setNetworkType(network);
48 setNetworkType(network);
50
49
51− const endpoint = `https://mainnet.infura.io/v3/${
50+ const endpoint = `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
52− process.env.REACT_APP_INFURA_ENDPOINT
53− }`;
54
51
55 const provider = new Web3.providers.HttpProvider(endpoint);
52 const provider = new Web3.providers.HttpProvider(endpoint);
56 const web3 = new Web3(provider);
53 const web3 = new Web3(provider);
@@ -112,7 +109,7 @@ class Network extends React.Component {
112 }
109 }
113
110
114 render() {
111 render() {
115− const { networkType, pushRoute } = this.props;
112+ const { networkType, history } = this.props;
116 const networkOptions = this.getNetworkOptions();
113 const networkOptions = this.getNetworkOptions();
117
114
118 return (
115 return (
@@ -136,7 +133,7 @@ class Network extends React.Component {
136
133
137 <Button
134 <Button
138 className={'mt-10'}
135 className={'mt-10'}
139− onClick={() => pushRoute(ROUTE_NAMES.WALLET)}>
136+ onClick={() => history.push(ROUTE_NAMES.WALLET)}>
140 {'Continue →'}
137 {'Continue →'}
141 </Button>
138 </Button>
142 </Col>
139 </Col>
@@ -145,4 +142,4 @@ class Network extends React.Component {
145 }
142 }
146}
143}
147
144
148−export default Network;
145+export default withHistory(Network);
src/bridge/views/Point.js+4−16
@@ -10,6 +10,7 @@ import ReactSVGComponents from '../components/ReactSVGComponents';
10import KeysAndMetadata from './Point/KeysAndMetadata';
10import KeysAndMetadata from './Point/KeysAndMetadata';
11import Actions from './Point/Actions';
11import Actions from './Point/Actions';
12import { Row, Col, H1, H3 } from '../components/Base';
12import { Row, Col, H1, H3 } from '../components/Base';
13+import { withHistory } from '../store/history';
13
14
14class Point extends React.Component {
15class Point extends React.Component {
15 constructor(props) {
16 constructor(props) {
@@ -73,14 +74,7 @@ class Point extends React.Component {
73 };
74 };
74
75
75 render() {
76 render() {
76− const {
77− web3,
78− popRoute,
79− pushRoute,
80− wallet,
81− setPointCursor,
77+ const { web3, history, wallet, setPointCursor, pointCache } = this.props;
82− pointCache,
83− } = this.props;
84
78
85 const { spawned } = this.state;
79 const { spawned } = this.state;
86
80
@@ -101,11 +95,6 @@ class Point extends React.Component {
101
95
102 const authenticated = Just.hasInstance(wallet);
96 const authenticated = Just.hasInstance(wallet);
103
97
104− const routeHandler = route => {
105− popRoute();
106− pushRoute(route);
107− };
108−
109 const issuedPointList =
98 const issuedPointList =
110 spawned.length === 0 ? (
99 spawned.length === 0 ? (
111 <div />
100 <div />
@@ -115,7 +104,7 @@ class Point extends React.Component {
115
104
116 <PointList
105 <PointList
117 setPointCursor={setPointCursor}
106 setPointCursor={setPointCursor}
118− routeHandler={routeHandler}
107+ routeHandler={history.popAndPush}
119 points={spawned}
108 points={spawned}
120 />
109 />
121 </div>
110 </div>
@@ -130,7 +119,6 @@ class Point extends React.Component {
130 </H1>
119 </H1>
131 {authenticated ? (
120 {authenticated ? (
132 <Actions
121 <Actions
133− pushRoute={pushRoute}
134 online={online}
122 online={online}
135 wallet={wallet}
123 wallet={wallet}
136 point={point}
124 point={point}
@@ -147,4 +135,4 @@ class Point extends React.Component {
147 }
135 }
148}
136}
149
137
150−export default Point;
138+export default withHistory(Point);
src/bridge/views/Point/Actions.js+18−17
@@ -1,17 +1,20 @@
1import React from 'react';
1import React from 'react';
2+import { azimuth } from 'azimuth-js';
2import * as need from '../../lib/need';
3import * as need from '../../lib/need';
4+
3import { ETH_ZERO_ADDR, CURVE_ZERO_ADDR, eqAddr } from '../../lib/wallet';
5import { ETH_ZERO_ADDR, CURVE_ZERO_ADDR, eqAddr } from '../../lib/wallet';
4import { Row, Col, H2, P } from '../../components/Base';
6import { Row, Col, H2, P } from '../../components/Base';
5import { Button } from '../../components/Base';
7import { Button } from '../../components/Base';
6−import { ROUTE_NAMES } from '../../lib/router';
8+import { ROUTE_NAMES } from '../../lib/routeNames';
7−import { azimuth } from 'azimuth-js';
9+import { useHistory } from '../../store/history';
8
10
9const isPlanet = point =>
11const isPlanet = point =>
10 azimuth.getPointSize(point) === azimuth.PointSize.Planet;
12 azimuth.getPointSize(point) === azimuth.PointSize.Planet;
11const isStar = point => azimuth.getPointSize(point) === azimuth.PointSize.Star;
13const isStar = point => azimuth.getPointSize(point) === azimuth.PointSize.Star;
12
14
13−const Actions = props => {
15+function Actions(props) {
16+ const history = useHistory();
14− const { pushRoute, online, point, pointDetails, invites } = props;
17+ const { online, point, pointDetails, invites } = props;
15
18
16 const addr = need.address(props);
19 const addr = need.address(props);
17
20
@@ -105,9 +108,7 @@ const Actions = props => {
105 disabled={!isActiveOwner || !online || !hasInvites}
108 disabled={!isActiveOwner || !online || !hasInvites}
106 prop-size={'sm'}
109 prop-size={'sm'}
107 prop-type={'link'}
110 prop-type={'link'}
108− onClick={() => {
109− pushRoute(ROUTE_NAMES.INVITES_SEND);
111+ onClick={() => history.push(ROUTE_NAMES.INVITES_SEND)}>
110− }}>
111 {'Send invites ('}
112 {'Send invites ('}
112 {invites.matchWith({
113 {invites.matchWith({
113 Nothing: () => '?',
114 Nothing: () => '?',
@@ -124,7 +125,7 @@ const Actions = props => {
124 prop-size={'sm'}
125 prop-size={'sm'}
125 prop-type={'link'}
126 prop-type={'link'}
126 onClick={() => {
127 onClick={() => {
127− pushRoute(ROUTE_NAMES.INVITES_MANAGE);
128+ history.push(ROUTE_NAMES.INVITES_MANAGE);
128 }}>
129 }}>
129 {'Manage invites'}
130 {'Manage invites'}
130 </Button>
131 </Button>
@@ -147,7 +148,7 @@ const Actions = props => {
147 prop-type={'link'}
148 prop-type={'link'}
148 disabled={(online || planet) && !canIssueChild}
149 disabled={(online || planet) && !canIssueChild}
149 onClick={() => {
150 onClick={() => {
150− pushRoute(ROUTE_NAMES.ISSUE_CHILD);
151+ history.push(ROUTE_NAMES.ISSUE_CHILD);
151 }}>
152 }}>
152 {'Issue child'}
153 {'Issue child'}
153 </Button>
154 </Button>
@@ -157,7 +158,7 @@ const Actions = props => {
157 prop-type={'link'}
158 prop-type={'link'}
158 disabled={online && !canAcceptTransfer}
159 disabled={online && !canAcceptTransfer}
159 onClick={() => {
160 onClick={() => {
160− pushRoute(ROUTE_NAMES.ACCEPT_TRANSFER);
161+ history.push(ROUTE_NAMES.ACCEPT_TRANSFER);
161 }}>
162 }}>
162 {'Accept incoming transfer'}
163 {'Accept incoming transfer'}
163 </Button>
164 </Button>
@@ -167,7 +168,7 @@ const Actions = props => {
167 prop-type={'link'}
168 prop-type={'link'}
168 disabled={online && !canCancelTransfer}
169 disabled={online && !canCancelTransfer}
169 onClick={() => {
170 onClick={() => {
170− pushRoute(ROUTE_NAMES.CANCEL_TRANSFER);
171+ history.push(ROUTE_NAMES.CANCEL_TRANSFER);
171 }}>
172 }}>
172 {'Cancel outgoing transfer'}
173 {'Cancel outgoing transfer'}
173 </Button>
174 </Button>
@@ -177,7 +178,7 @@ const Actions = props => {
177 prop-type={'link'}
178 prop-type={'link'}
178 disabled={online && !canGenKeyfile}
179 disabled={online && !canGenKeyfile}
179 onClick={() => {
180 onClick={() => {
180− pushRoute(ROUTE_NAMES.GEN_KEYFILE);
181+ history.push(ROUTE_NAMES.GEN_KEYFILE);
181 }}>
182 }}>
182 {'Generate Arvo keyfile'}
183 {'Generate Arvo keyfile'}
183 </Button>
184 </Button>
@@ -188,7 +189,7 @@ const Actions = props => {
188 prop-size={'sm'}
189 prop-size={'sm'}
189 prop-type={'link'}
190 prop-type={'link'}
190 onClick={() => {
191 onClick={() => {
191− pushRoute(ROUTE_NAMES.SET_SPAWN_PROXY);
192+ history.push(ROUTE_NAMES.SET_SPAWN_PROXY);
192 }}>
193 }}>
193 {'Change spawn proxy'}
194 {'Change spawn proxy'}
194 </Button>
195 </Button>
@@ -198,7 +199,7 @@ const Actions = props => {
198 prop-size={'sm'}
199 prop-size={'sm'}
199 prop-type={'link'}
200 prop-type={'link'}
200 onClick={() => {
201 onClick={() => {
201− pushRoute(ROUTE_NAMES.SET_MANAGEMENT_PROXY);
202+ history.push(ROUTE_NAMES.SET_MANAGEMENT_PROXY);
202 }}>
203 }}>
203 {'Change management proxy'}
204 {'Change management proxy'}
204 </Button>
205 </Button>
@@ -208,7 +209,7 @@ const Actions = props => {
208 prop-size={'sm'}
209 prop-size={'sm'}
209 prop-type={'link'}
210 prop-type={'link'}
210 onClick={() => {
211 onClick={() => {
211− pushRoute(ROUTE_NAMES.SET_KEYS);
212+ history.push(ROUTE_NAMES.SET_KEYS);
212 }}>
213 }}>
213 {'Set network keys'}
214 {'Set network keys'}
214 </Button>
215 </Button>
@@ -218,7 +219,7 @@ const Actions = props => {
218 prop-size={'sm'}
219 prop-size={'sm'}
219 prop-type={'link'}
220 prop-type={'link'}
220 onClick={() => {
221 onClick={() => {
221− pushRoute(ROUTE_NAMES.TRANSFER);
222+ history.push(ROUTE_NAMES.TRANSFER);
222 }}>
223 }}>
223 {'Transfer'}
224 {'Transfer'}
224 </Button>
225 </Button>
@@ -229,6 +230,6 @@ const Actions = props => {
229 </Row>
230 </Row>
230 </div>
231 </div>
231 );
232 );
232−};
233+}
233
234
234export default Actions;
235export default Actions;
src/bridge/views/Points.js+12−11
@@ -5,7 +5,8 @@ import * as azimuth from 'azimuth-js';
5
5
6import PointList from '../components/PointList';
6import PointList from '../components/PointList';
7import { NETWORK_NAMES } from '../lib/network';
7import { NETWORK_NAMES } from '../lib/network';
8−import { ROUTE_NAMES } from '../lib/router';
8+import { ROUTE_NAMES } from '../lib/routeNames';
9+import { withHistory } from '../store/history';
9import { ETH_ZERO_ADDR, eqAddr } from '../lib/wallet';
10import { ETH_ZERO_ADDR, eqAddr } from '../lib/wallet';
10
11
11const hasTransferProxy = (cache, point) =>
12const hasTransferProxy = (cache, point) =>
@@ -79,7 +80,7 @@ class Points extends React.Component {
79 }
80 }
80
81
81 render() {
82 render() {
82− const { setPointCursor, pushRoute } = this.props;
83+ const { setPointCursor, history } = this.props;
83 const { pointCache } = this.props;
84 const { pointCache } = this.props;
84
85
85 const {
86 const {
@@ -98,7 +99,7 @@ class Points extends React.Component {
98 <Button
99 <Button
99 prop-type={'link'}
100 prop-type={'link'}
100 prop-size={'md'}
101 prop-size={'md'}
101− onClick={() => pushRoute(ROUTE_NAMES.VIEW_SHIP)}>
102+ onClick={() => history.push(ROUTE_NAMES.VIEW_SHIP)}>
102 {'View a point →'}
103 {'View a point →'}
103 </Button>
104 </Button>
104 <P>{'View a point on Azimuth.'}</P>
105 <P>{'View a point on Azimuth.'}</P>
@@ -115,7 +116,7 @@ class Points extends React.Component {
115 <Button
116 <Button
116 prop-type={'link'}
117 prop-type={'link'}
117 prop-size={'md'}
118 prop-size={'md'}
118− onClick={() => pushRoute(ROUTE_NAMES.CREATE_GALAXY)}>
119+ onClick={() => history.push(ROUTE_NAMES.CREATE_GALAXY)}>
119 {'Create a galaxy →'}
120 {'Create a galaxy →'}
120 </Button>
121 </Button>
121 <P>
122 <P>
@@ -141,7 +142,7 @@ class Points extends React.Component {
141 </P>
142 </P>
142 <PointList
143 <PointList
143 setPointCursor={setPointCursor}
144 setPointCursor={setPointCursor}
144− routeHandler={pushRoute}
145+ routeHandler={history.push}
145 points={outgoing}
146 points={outgoing}
146 />
147 />
147 </React.Fragment>
148 </React.Fragment>
@@ -159,7 +160,7 @@ class Points extends React.Component {
159 </P>
160 </P>
160 <PointList
161 <PointList
161 setPointCursor={setPointCursor}
162 setPointCursor={setPointCursor}
162− routeHandler={pushRoute}
163+ routeHandler={history.push}
163 points={incoming}
164 points={incoming}
164 />
165 />
165 </React.Fragment>
166 </React.Fragment>
@@ -177,7 +178,7 @@ class Points extends React.Component {
177 </P>
178 </P>
178 <PointList
179 <PointList
179 setPointCursor={setPointCursor}
180 setPointCursor={setPointCursor}
180− routeHandler={pushRoute}
181+ routeHandler={history.push}
181 points={managing}
182 points={managing}
182 />
183 />
183 </React.Fragment>
184 </React.Fragment>
@@ -195,7 +196,7 @@ class Points extends React.Component {
195 </P>
196 </P>
196 <PointList
197 <PointList
197 setPointCursor={setPointCursor}
198 setPointCursor={setPointCursor}
198− routeHandler={pushRoute}
199+ routeHandler={history.push}
199 points={voting}
200 points={voting}
200 />
201 />
201 </React.Fragment>
202 </React.Fragment>
@@ -210,7 +211,7 @@ class Points extends React.Component {
210 <P>{`You can create new child ships under these points.`}</P>
211 <P>{`You can create new child ships under these points.`}</P>
211 <PointList
212 <PointList
212 setPointCursor={setPointCursor}
213 setPointCursor={setPointCursor}
213− routeHandler={pushRoute}
214+ routeHandler={history.push}
214 points={spawning}
215 points={spawning}
215 />
216 />
216 </React.Fragment>
217 </React.Fragment>
@@ -238,7 +239,7 @@ class Points extends React.Component {
238
239
239 <PointList
240 <PointList
240 setPointCursor={setPointCursor}
241 setPointCursor={setPointCursor}
241− routeHandler={pushRoute}
242+ routeHandler={history.push}
242 points={points}
243 points={points}
243 loading={loading}
244 loading={loading}
244 />
245 />
@@ -254,4 +255,4 @@ class Points extends React.Component {
254 }
255 }
255}
256}
256
257
257−export default Points;
258+export default withHistory(Points);
src/bridge/views/PrivateKey.js+5−7
@@ -4,7 +4,8 @@ import { Button } from '../components/Base';
4import { RequiredInput, InnerLabel, InputCaption } from '../components/Base';
4import { RequiredInput, InnerLabel, InputCaption } from '../components/Base';
5import { Row, Col, H1 } from '../components/Base';
5import { Row, Col, H1 } from '../components/Base';
6
6
7−import { ROUTE_NAMES } from '../lib/router';
7+import { ROUTE_NAMES } from '../lib/routeNames';
8+import { withHistory } from '../store/history';
8import { EthereumWallet } from '../lib/wallet';
9import { EthereumWallet } from '../lib/wallet';
9
10
10class PrivateKey extends React.Component {
11class PrivateKey extends React.Component {
@@ -35,7 +36,7 @@ class PrivateKey extends React.Component {
35 }
36 }
36
37
37 render() {
38 render() {
38− const { pushRoute, popRoute, wallet } = this.props;
39+ const { history, wallet } = this.props;
39 const { privateKey } = this.state;
40 const { privateKey } = this.state;
40
41
41 return (
42 return (
@@ -63,10 +64,7 @@ class PrivateKey extends React.Component {
63 className={'mt-10'}
64 className={'mt-10'}
64 prop-size={'wide lg'}
65 prop-size={'wide lg'}
65 disabled={Maybe.Nothing.hasInstance(wallet)}
66 disabled={Maybe.Nothing.hasInstance(wallet)}
66− onClick={() => {
67− popRoute();
68− pushRoute(ROUTE_NAMES.SHIPS);
67+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
69− }}>
70 {'Continue →'}
68 {'Continue →'}
71 </Button>
69 </Button>
72 </Col>
70 </Col>
@@ -75,4 +73,4 @@ class PrivateKey extends React.Component {
75 }
73 }
76}
74}
77
75
78−export default PrivateKey;
76+export default withHistory(PrivateKey);
src/bridge/views/SentTransaction.js+9−15
@@ -4,9 +4,11 @@ import * as need from '../lib/need';
4import { Row, Col, H1, H3, P, Warning, Anchor } from '../components/Base';
4import { Row, Col, H1, H3, P, Warning, Anchor } from '../components/Base';
5import { Button } from '../components/Base';
5import { Button } from '../components/Base';
6
6
7−import { ROUTE_NAMES } from '../lib/router';
7+import { ROUTE_NAMES } from '../lib/routeNames';
8+import { useHistory } from '../store/history';
8import { BRIDGE_ERROR, renderTxnError } from '../lib/error';
9import { BRIDGE_ERROR, renderTxnError } from '../lib/error';
9import { NETWORK_NAMES } from '../lib/network';
10import { NETWORK_NAMES } from '../lib/network';
11+import { withTxnConfirmations } from '../store/txnConfirmations';
10
12
11class Success extends React.Component {
13class Success extends React.Component {
12 constructor(props) {
14 constructor(props) {
@@ -108,16 +110,11 @@ const Failure = props => (
108);
110);
109
111
110const SentTransaction = props => {
112const SentTransaction = props => {
111− const {
113+ const history = useHistory();
112− txnHashCursor,
113− networkType,
114− popRoute,
115− pushRoute,
116− txnConfirmations,
114+ const { txnHashCursor, networkType, txnConfirmations } = props;
117− } = props;
118 const { setPointCursor, pointCursor } = props;
115 const { setPointCursor, pointCursor } = props;
119
116
120− const promptKeyfile = props.routeData && props.routeData.promptKeyfile;
117+ const promptKeyfile = history.data && history.data.promptKeyfile;
121
118
122 const w3 = need.web3(props);
119 const w3 = need.web3(props);
123
120
@@ -146,7 +143,7 @@ const SentTransaction = props => {
146 prop-type={'link'}
143 prop-type={'link'}
147 onClick={() => {
144 onClick={() => {
148 setPointCursor(pointCursor);
145 setPointCursor(pointCursor);
149− popRoute();
146+ history.pop();
150 }}>
147 }}>
151 {'Ok →'}
148 {'Ok →'}
152 </Button>
149 </Button>
@@ -162,10 +159,7 @@ const SentTransaction = props => {
162 <Col>
159 <Col>
163 <Button
160 <Button
164 prop-type={'link'}
161 prop-type={'link'}
165− onClick={() => {
166− popRoute();
167− pushRoute(ROUTE_NAMES.GEN_KEYFILE);
162+ onClick={() => history.popAndPush(ROUTE_NAMES.GEN_KEYFILE)}>
168− }}>
169 {'Download Keyfile →'}
163 {'Download Keyfile →'}
170 </Button>
164 </Button>
171 </Col>
165 </Col>
@@ -182,4 +176,4 @@ const SentTransaction = props => {
182 );
176 );
183};
177};
184
178
185−export default SentTransaction;
179+export default withTxnConfirmations(SentTransaction);
src/bridge/views/SetKeys.js+1−1
@@ -8,7 +8,7 @@ import { Row, Col, H1, P, Warning, CheckboxButton } from '../components/Base';
8import StatelessTransaction from '../components/StatelessTransaction';
8import StatelessTransaction from '../components/StatelessTransaction';
9import { attemptSeedDerivation } from '../lib/keys';
9import { attemptSeedDerivation } from '../lib/keys';
10
10
11−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
11+import * as kg from 'urbit-key-generation/dist/index';
12
12
13import { addHexPrefix } from '../lib/wallet';
13import { addHexPrefix } from '../lib/wallet';
14
14
src/bridge/views/Shards.js+6−8
@@ -10,10 +10,11 @@ import {
10 Input,
10 Input,
11} from '../components/Base';
11} from '../components/Base';
12import { Row, Col, H1, P } from '../components/Base';
12import { Row, Col, H1, P } from '../components/Base';
13−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
13+import * as kg from 'urbit-key-generation/dist/index';
14import * as ob from 'urbit-ob';
14import * as ob from 'urbit-ob';
15
15
16−import { ROUTE_NAMES } from '../lib/router';
16+import { ROUTE_NAMES } from '../lib/routeNames';
17+import { withHistory } from '../store/history';
17import { urbitWalletFromTicket } from '../lib/wallet';
18import { urbitWalletFromTicket } from '../lib/wallet';
18
19
19const placeholder = len => {
20const placeholder = len => {
@@ -90,7 +91,7 @@ class Shards extends React.Component {
90 }
91 }
91
92
92 render() {
93 render() {
93− const { popRoute, pushRoute, wallet } = this.props;
94+ const { history, wallet } = this.props;
94 const { shard1, shard2, shard3, pointName, passphrase } = this.state;
95 const { shard1, shard2, shard3, pointName, passphrase } = this.state;
95
96
96 const phPoint = this.pointPlaceholder;
97 const phPoint = this.pointPlaceholder;
@@ -201,10 +202,7 @@ class Shards extends React.Component {
201 className={'mt-4'}
202 className={'mt-4'}
202 prop-size={'xl wide'}
203 prop-size={'xl wide'}
203 disabled={Nothing.hasInstance(wallet)}
204 disabled={Nothing.hasInstance(wallet)}
204− onClick={() => {
205− popRoute();
206− pushRoute(ROUTE_NAMES.SHIPS);
205+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
207− }}>
208 {'Continue →'}
206 {'Continue →'}
209 </Button>
207 </Button>
210 </Col>
208 </Col>
@@ -213,4 +211,4 @@ class Shards extends React.Component {
213 }
211 }
214}
212}
215
213
216−export default Shards;
214+export default withHistory(Shards);
src/bridge/views/Ticket.js+5−7
@@ -12,7 +12,8 @@ import {
12import { Row, Col, H1, P } from '../components/Base';
12import { Row, Col, H1, P } from '../components/Base';
13
13
14import { randomPatq } from '../lib/lib';
14import { randomPatq } from '../lib/lib';
15−import { ROUTE_NAMES } from '../lib/router';
15+import { ROUTE_NAMES } from '../lib/routeNames';
16+import { withHistory } from '../store/history';
16import { urbitWalletFromTicket } from '../lib/wallet';
17import { urbitWalletFromTicket } from '../lib/wallet';
17
18
18class Ticket extends React.Component {
19class Ticket extends React.Component {
@@ -62,7 +63,7 @@ class Ticket extends React.Component {
62 }
63 }
63
64
64 render() {
65 render() {
65− const { popRoute, pushRoute, wallet } = this.props;
66+ const { history, wallet } = this.props;
66 const { ticket, pointName, passphrase } = this.state;
67 const { ticket, pointName, passphrase } = this.state;
67
68
68 const phPoint = this.pointPlaceholder;
69 const phPoint = this.pointPlaceholder;
@@ -140,10 +141,7 @@ class Ticket extends React.Component {
140 className={'mt-4'}
141 className={'mt-4'}
141 prop-size={'xl wide'}
142 prop-size={'xl wide'}
142 disabled={Nothing.hasInstance(wallet)}
143 disabled={Nothing.hasInstance(wallet)}
143− onClick={() => {
144− popRoute();
145− pushRoute(ROUTE_NAMES.SHIPS);
144+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
146− }}>
147 {'Continue →'}
145 {'Continue →'}
148 </Button>
146 </Button>
149 </Col>
147 </Col>
@@ -152,4 +150,4 @@ class Ticket extends React.Component {
152 }
150 }
153}
151}
154
152
155−export default Ticket;
153+export default withHistory(Ticket);
src/bridge/views/Trezor.js+5−7
@@ -8,7 +8,8 @@ import TrezorConnect from 'trezor-connect';
8import * as secp256k1 from 'secp256k1';
8import * as secp256k1 from 'secp256k1';
9
9
10import { TREZOR_PATH } from '../lib/trezor';
10import { TREZOR_PATH } from '../lib/trezor';
11−import { ROUTE_NAMES } from '../lib/router';
11+import { ROUTE_NAMES } from '../lib/routeNames';
12+import { withHistory } from '../store/history';
12
13
13class Trezor extends React.Component {
14class Trezor extends React.Component {
14 constructor(props) {
15 constructor(props) {
@@ -60,7 +61,7 @@ class Trezor extends React.Component {
60 }
61 }
61
62
62 render() {
63 render() {
63− const { pushRoute, popRoute, wallet } = this.props;
64+ const { history, wallet } = this.props;
64 const { hdpath, account } = this.state;
65 const { hdpath, account } = this.state;
65 const { handleAccountSelection } = this;
66 const { handleAccountSelection } = this;
66
67
@@ -129,10 +130,7 @@ class Trezor extends React.Component {
129 className={'mt-8'}
130 className={'mt-8'}
130 prop-size={'wide lg'}
131 prop-size={'wide lg'}
131 disabled={Maybe.Nothing.hasInstance(wallet)}
132 disabled={Maybe.Nothing.hasInstance(wallet)}
132− onClick={() => {
133− popRoute();
134− pushRoute(ROUTE_NAMES.SHIPS);
133+ onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
135− }}>
136 {'Continue →'}
134 {'Continue →'}
137 </Button>
135 </Button>
138 </Col>
136 </Col>
@@ -141,4 +139,4 @@ class Trezor extends React.Component {
141 }
139 }
142}
140}
143
141
144−export default Trezor;
142+export default withHistory(Trezor);
src/bridge/views/ViewPoint.js+5−5
@@ -6,7 +6,8 @@ import { Button } from '../components/Base';
6import { Row, Col, H1, P } from '../components/Base';
6import { Row, Col, H1, P } from '../components/Base';
7import { InnerLabel, PointInput, ValidatedSigil } from '../components/Base';
7import { InnerLabel, PointInput, ValidatedSigil } from '../components/Base';
8
8
9−import { ROUTE_NAMES } from '../lib/router';
9+import { ROUTE_NAMES } from '../lib/routeNames';
10+import { withHistory } from '../store/history';
10
11
11class ViewPoint extends React.Component {
12class ViewPoint extends React.Component {
12 constructor(props) {
13 constructor(props) {
@@ -27,7 +28,7 @@ class ViewPoint extends React.Component {
27
28
28 render() {
29 render() {
29 const { pointName } = this.state;
30 const { pointName } = this.state;
30− const { popRoute, pushRoute, setPointCursor } = this.props;
31+ const { history, setPointCursor } = this.props;
31
32
32 // NB (jtobin):
33 // NB (jtobin):
33 //
34 //
@@ -69,8 +70,7 @@ class ViewPoint extends React.Component {
69 disabled={valid === false}
70 disabled={valid === false}
70 onClick={() => {
71 onClick={() => {
71 setPointCursor(Maybe.Just(ob.patp2dec(pointName)));
72 setPointCursor(Maybe.Just(ob.patp2dec(pointName)));
72− popRoute();
73− pushRoute(ROUTE_NAMES.SHIP);
73+ history.popAndPush(ROUTE_NAMES.SHIP);
74 }}>
74 }}>
75 {'Continue →'}
75 {'Continue →'}
76 </Button>
76 </Button>
@@ -80,4 +80,4 @@ class ViewPoint extends React.Component {
80 }
80 }
81}
81}
82
82
83−export default ViewPoint;
83+export default withHistory(ViewPoint);
src/bridge/views/Wallet.js+4−3
@@ -4,7 +4,8 @@ import { Button, H1, P } from '../components/Base';
4import { InnerLabelDropdown } from '../components/Base';
4import { InnerLabelDropdown } from '../components/Base';
5import { Row, Col } from '../components/Base';
5import { Row, Col } from '../components/Base';
6
6
7−import { ROUTE_NAMES } from '../lib/router';
7+import { ROUTE_NAMES } from '../lib/routeNames';
8+import { withHistory } from '../store/history';
8import { WALLET_NAMES, renderWalletType } from '../lib/wallet';
9import { WALLET_NAMES, renderWalletType } from '../lib/wallet';
9
10
10class Wallet extends React.Component {
11class Wallet extends React.Component {
@@ -77,7 +78,7 @@ class Wallet extends React.Component {
77 <Button
78 <Button
78 className={'mt-10'}
79 className={'mt-10'}
79 onClick={() =>
80 onClick={() =>
80− props.pushRoute(
81+ props.history.push(
81 props.walletType === WALLET_NAMES.MNEMONIC
82 props.walletType === WALLET_NAMES.MNEMONIC
82 ? ROUTE_NAMES.MNEMONIC
83 ? ROUTE_NAMES.MNEMONIC
83 : props.walletType === WALLET_NAMES.TICKET
84 : props.walletType === WALLET_NAMES.TICKET
@@ -103,4 +104,4 @@ class Wallet extends React.Component {
103 }
104 }
104}
105}
105
106
106−export default Wallet;
107+export default withHistory(Wallet);
src/walletgen/lib/lib.js+1−1
@@ -1,5 +1,5 @@
1import * as ob from 'urbit-ob';
1import * as ob from 'urbit-ob';
2−import * as kg from '../../../node_modules/urbit-key-generation/dist/index';
2+import * as kg from 'urbit-key-generation/dist/index';
3import * as more from 'more-entropy';
3import * as more from 'more-entropy';
4import lodash from 'lodash';
4import lodash from 'lodash';
5import {
5import {