on master help sign in
checkpoint: squash me
commite27d1c60b5cb74c9b72ab22100cd32f8265bac89 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateTue 11 Jun 2019, 13:31 (7 years ago) parent77325bb
6 files changed+261−234
src/bridge/Bridge.js+57−73 src/bridge/lib/flags.js+2−1 src/bridge/lib/web3.js−23 src/bridge/store/network.js+98 src/bridge/store/online.js+46 src/bridge/views/Network.js+58−137
src/bridge/Bridge.js+57−73
@@ -7,7 +7,6 @@ import Header from './components/Header';
77import { Container, Row, Col } from './components/Base';
88
99import { router } from './lib/router';
10−import { initWeb3 } from './lib/web3';
1110import { ROUTE_NAMES } from './lib/routeNames';
1211import { HistoryProvider, withHistory, useHistory } from './store/history';
1312import { TxnConfirmationsProvider } from './store/txnConfirmations';
@@ -19,13 +18,15 @@ import {
1918 addressFromSecp256k1Public,
2019} from './lib/wallet';
2120import { BRIDGE_ERROR } from './lib/error';
22−import { isLocal } from './lib/flags';
21+import { isDevelopment } from './lib/flags';
22+import { OnlineProvider } from './store/online';
23+import { NetworkProvider } from './store/network';
2324
2425// NB(shrugs): toggle this variable to use the default local state.
2526// don't commit changes to this line, but there shouldn't be a problem
2627// if you do because we'll never stub on a production build.
2728const shouldStubLocal = false;
28−const isStubbed = isLocal && shouldStubLocal;
29+const isStubbed = isDevelopment && shouldStubLocal;
2930const kInitialRoutes = isStubbed
3031 ? [
3132 { name: ROUTE_NAMES.SHIPS },
@@ -66,12 +67,6 @@ class Bridge extends React.Component {
6667 constructor(props) {
6768 super(props);
6869
69− const networkType = isLocal ? NETWORK_NAMES.LOCAL : NETWORK_NAMES.MAINNET;
70−
71− // Sidestepping full network selection to allow for point viewing,
72− // but still respecting the networkType
73− const { web3, contracts } = initWeb3(networkType);
74−
7570 // NB (jtobin):
7671 //
7772 // Note that the 'wallet' prop has type depending on the 'walletType' prop.
@@ -86,10 +81,6 @@ class Bridge extends React.Component {
8681 // 'EthereumWallet'.
8782
8883 this.state = {
89− // network
90− networkType: networkType,
91− web3: Just(web3),
92− contracts: Just(contracts),
9384 // wallet
9485 walletType: WALLET_NAMES.MNEMONIC,
9586 wallet: Nothing(),
@@ -106,8 +97,6 @@ class Bridge extends React.Component {
10697 txnConfirmations: {},
10798 };
10899
109− this.setNetworkType = this.setNetworkType.bind(this);
110− this.setNetwork = this.setNetwork.bind(this);
111100 this.setWalletType = this.setWalletType.bind(this);
112101 this.setWallet = this.setWallet.bind(this);
113102 this.setWalletHdPath = this.setWalletHdPath.bind(this);
@@ -155,13 +144,6 @@ class Bridge extends React.Component {
155144 });
156145 }
157146
158− setNetwork(web3, contracts) {
159− this.setState({
160− web3: web3,
161− contracts: contracts,
162− });
163− }
164−
165147 setWalletType(symbol) {
166148 if (includes(WALLET_NAMES, symbol)) {
167149 this.setState({
@@ -222,7 +204,6 @@ class Bridge extends React.Component {
222204
223205 render() {
224206 const {
225− networkType,
226207 walletType,
227208 walletHdPath,
228209 wallet,
@@ -233,64 +214,67 @@ class Bridge extends React.Component {
233214 pointCursor,
234215 pointCache,
235216 txnHashCursor,
236− web3,
237− contracts,
238217 } = this.state;
239218
219+ const initialNetworkType = isDevelopment
220+ ? NETWORK_NAMES.LOCAL
221+ : NETWORK_NAMES.MAINNET;
222+
240223 return (
241224 <HistoryProvider initialRoutes={kInitialRoutes}>
242225 <TxnConfirmationsProvider>
243− <Container>
244− <Row>
245− <VariableWidthColumn>
246− <Header
247− skipRoute={this.skipRoute}
248− networkType={networkType}
249− wallet={wallet}
250− pointCursor={pointCursor}
251− />
226+ <OnlineProvider>
227+ <NetworkProvider initialNetworkType={initialNetworkType}>
228+ <Container>
229+ <Row>
230+ <VariableWidthColumn>
231+ <Header
232+ skipRoute={this.skipRoute}
233+ wallet={wallet}
234+ pointCursor={pointCursor}
235+ />
252236
253− <Row className={'row wrapper'}>
254− <Router
255− // network
256− setNetworkType={this.setNetworkType}
257− setNetwork={this.setNetwork}
258− networkType={networkType}
259− web3={web3}
260− contracts={contracts}
261− // wallet
262− setWalletType={this.setWalletType}
263− setWalletHdPath={this.setWalletHdPath}
264− setWallet={this.setWallet}
265− walletType={walletType}
266− walletHdPath={walletHdPath}
267− wallet={wallet}
268− // urbit wallet
269− urbitWallet={urbitWallet}
270− setUrbitWallet={this.setUrbitWallet}
271− authMnemonic={authMnemonic}
272− setAuthMnemonic={this.setAuthMnemonic}
273− // point
274− setPointCursor={this.setPointCursor}
275− addToPointCache={this.addToPointCache}
276− pointCursor={pointCursor}
277− pointCache={pointCache}
278− networkSeedCache={networkSeedCache}
279− networkRevisionCache={networkRevisionCache}
280− setNetworkSeedCache={this.setNetworkSeedCache}
281− // txn
282− onSent={this.setTxnHashCursor}
283− setTxnHashCursor={this.setTxnHashCursor}
284− txnHashCursor={txnHashCursor}
285− />
237+ <Row className={'row wrapper'}>
238+ <Router
239+ setWalletType={
240+ this.setWalletType // wallet
241+ }
242+ setWalletHdPath={this.setWalletHdPath}
243+ setWallet={this.setWallet}
244+ walletType={walletType}
245+ walletHdPath={walletHdPath}
246+ wallet={wallet}
247+ urbitWallet={
248+ urbitWallet // urbit wallet
249+ }
250+ setUrbitWallet={this.setUrbitWallet}
251+ authMnemonic={authMnemonic}
252+ setAuthMnemonic={this.setAuthMnemonic}
253+ setPointCursor={
254+ this.setPointCursor // point
255+ }
256+ addToPointCache={this.addToPointCache}
257+ pointCursor={pointCursor}
258+ pointCache={pointCache}
259+ networkSeedCache={networkSeedCache}
260+ networkRevisionCache={networkRevisionCache}
261+ setNetworkSeedCache={this.setNetworkSeedCache}
262+ onSent={
263+ this.setTxnHashCursor // txn
264+ }
265+ setTxnHashCursor={this.setTxnHashCursor}
266+ txnHashCursor={txnHashCursor}
267+ />
286268
287− <div className={'push'} />
288− </Row>
269+ <div className={'push'} />
270+ </Row>
289271
290− <Footer />
291− </VariableWidthColumn>
292− </Row>
293− </Container>
272+ <Footer />
273+ </VariableWidthColumn>
274+ </Row>
275+ </Container>
276+ </NetworkProvider>
277+ </OnlineProvider>
294278 </TxnConfirmationsProvider>
295279 </HistoryProvider>
296280 );
src/bridge/lib/flags.js+2−1
@@ -1 +1,2 @@
1−export const isLocal = process.env.NODE_ENV === 'development';
1+// are we running bridge in a development build
2+export const isDevelopment = process.env.NODE_ENV === 'development';
src/bridge/lib/web3.jsdeleted−23
@@ -1,23 +0,0 @@
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/network.jsnew file+98
@@ -0,0 +1,98 @@
1+import React, { useContext, useMemo, useState } from 'react';
2+import * as azimuth from 'azimuth-js';
3+import Web3 from 'web3';
4+import Maybe from 'folktale/maybe';
5+
6+import { CONTRACT_ADDRESSES } from '../lib/contracts';
7+
8+import { NETWORK_NAMES } from '../lib/network';
9+import { isDevelopment } from '../lib/flags';
10+
11+function _useNetwork(initialNetworkType = null) {
12+ const [networkType, setNetworkType] = useState(initialNetworkType);
13+
14+ const { web3, contracts } = useMemo(() => {
15+ if (networkType === NETWORK_NAMES.LOCAL) {
16+ const protocol = isDevelopment ? '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+
22+ return { web3: Maybe.Just(web3), contracts: Maybe.Just(contracts) };
23+ }
24+
25+ if (networkType === NETWORK_NAMES.ROPSTEN) {
26+ const endpoint = `https://ropsten.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
27+
28+ const provider = new Web3.providers.HttpProvider(endpoint);
29+ const web3 = new Web3(provider);
30+ const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.ROPSTEN);
31+
32+ return { web3: Maybe.Just(web3), contracts: Maybe.Just(contracts) };
33+ }
34+
35+ if (networkType === NETWORK_NAMES.MAINNET) {
36+ const endpoint = `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
37+
38+ const provider = new Web3.providers.HttpProvider(endpoint);
39+ const web3 = new Web3(provider);
40+ const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.MAINNET);
41+
42+ return { web3: Maybe.Just(web3), contracts: Maybe.Just(contracts) };
43+ }
44+
45+ if (networkType === NETWORK_NAMES.OFFLINE) {
46+ // NB (jtobin):
47+ //
48+ // The 'offline' network type targets the mainnet contracts, but does not
49+ // actually use a provider to connect. We use a web3 instance to
50+ // initalise the contracts, but the network itself is set to Nothing.
51+ //
52+ // We may want to offer the ability to select a target network for
53+ // transactions when offline.
54+
55+ // Note: example.com:3456 doesn't actually point to anything, we just need
56+ // a provider to initialize the Web3 object
57+ const provider = new Web3.providers.HttpProvider(
58+ 'http://example.com:3456'
59+ );
60+ const web3 = new Web3(provider);
61+
62+ const target = isDevelopment
63+ ? CONTRACT_ADDRESSES.DEV
64+ : CONTRACT_ADDRESSES.MAINNET;
65+
66+ const contracts = azimuth.initContracts(web3, target);
67+
68+ return { web3: Maybe.Nothing(), contracts: Maybe.Just(contracts) };
69+ }
70+ }, [networkType]);
71+
72+ return { networkType, setNetworkType, web3, contracts };
73+}
74+
75+const NetworkContext = React.createContext(null);
76+
77+// provider
78+export function NetworkProvider({ initialNetworkType, children }) {
79+ const value = _useNetwork(initialNetworkType);
80+ return (
81+ <NetworkContext.Provider value={value}>{children}</NetworkContext.Provider>
82+ );
83+}
84+
85+// hook consumer
86+export function useNetwork() {
87+ return useContext(NetworkContext);
88+}
89+
90+// hoc consumer
91+export const withNetwork = Component =>
92+ React.forwardRef((props, ref) => {
93+ return (
94+ <NetworkContext.Consumer>
95+ {value => <Component ref={ref} {...value} {...props} />}
96+ </NetworkContext.Consumer>
97+ );
98+ });
src/bridge/store/online.jsnew file+46
@@ -0,0 +1,46 @@
1+import React, { useContext, useEffect, useState } from 'react';
2+
3+function _useOnline() {
4+ const [online, setOnline] = useState(window.navigator.onLine);
5+
6+ useEffect(() => {
7+ function handleOnlineStatus(event) {
8+ setOnline(window.navigator.onLine);
9+ }
10+
11+ window.addEventListener('online', handleOnlineStatus);
12+ window.addEventListener('offline', handleOnlineStatus);
13+
14+ return () => {
15+ window.removeEventListener('online', handleOnlineStatus);
16+ window.removeEventListener('offline', handleOnlineStatus);
17+ };
18+ }, []);
19+
20+ return online;
21+}
22+
23+const OnlineContext = React.createContext(null);
24+
25+// provider
26+export function OnlineProvider({ children }) {
27+ const online = _useOnline();
28+ return (
29+ <OnlineContext.Provider value={online}>{children}</OnlineContext.Provider>
30+ );
31+}
32+
33+// hook consumer
34+export function useOnline() {
35+ return useContext(OnlineContext);
36+}
37+
38+// hoc consumer
39+export const withOnline = Component =>
40+ React.forwardRef((props, ref) => {
41+ return (
42+ <OnlineContext.Consumer>
43+ {online => <Component ref={ref} online={online} {...props} />}
44+ </OnlineContext.Consumer>
45+ );
46+ });
src/bridge/views/Network.js+58−137
@@ -1,145 +1,66 @@
1−import Maybe from 'folktale/maybe';
21import React from 'react';
2+
33import { Button } from '../components/Base';
44import { InnerLabelDropdown } from '../components/Base';
55import { Row, Col, H1, P } from '../components/Base';
6−import * as azimuth from 'azimuth-js';
7−import Web3 from 'web3';
8−
9−import { CONTRACT_ADDRESSES } from '../lib/contracts';
106import { NETWORK_NAMES, renderNetworkType } from '../lib/network';
117import { ROUTE_NAMES } from '../lib/routeNames';
12−import { withHistory } from '../store/history';
13−
14−class Network extends React.Component {
15− constructor(props) {
16− super(props);
17−
18− this.handleNetworkChange = this.handleNetworkChange.bind(this);
19− }
20−
21− handleNetworkChange(network) {
22− const { setNetworkType, setNetwork } = this.props;
23−
24− if (network === NETWORK_NAMES.LOCAL) {
25− setNetworkType(network);
26−
27− const endpoint = 'ws://localhost:8545';
28− const provider = new Web3.providers.WebsocketProvider(endpoint);
29− const web3 = new Web3(provider);
30− const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.DEV);
31−
32− setNetwork(Maybe.Just(web3), Maybe.Just(contracts));
33− }
34−
35− if (network === NETWORK_NAMES.ROPSTEN) {
36− setNetworkType(network);
37−
38− const endpoint = `https://ropsten.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
39−
40− const provider = new Web3.providers.HttpProvider(endpoint);
41− const web3 = new Web3(provider);
42− const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.ROPSTEN);
43−
44− setNetwork(Maybe.Just(web3), Maybe.Just(contracts));
45− }
46−
47− if (network === NETWORK_NAMES.MAINNET) {
48− setNetworkType(network);
49−
50− const endpoint = `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_ENDPOINT}`;
51−
52− const provider = new Web3.providers.HttpProvider(endpoint);
53− const web3 = new Web3(provider);
54− const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.MAINNET);
55−
56− setNetwork(Maybe.Just(web3), Maybe.Just(contracts));
57− }
58−
59− if (network === NETWORK_NAMES.OFFLINE) {
60− setNetworkType(network);
61−
62− // NB (jtobin):
63− //
64− // The 'offline' network type targets the mainnet contracts, but does not
65− // actually use a provider to connect. We use a web3 instance to
66− // initalise the contracts, but the network itself is set to Nothing.
67− //
68− // We may want to offer the ability to select a target network for
69− // transactions when offline.
70−
71− // Note: localhost:3456 doesn't actually point to anything, we just need
72− // a provider to initialize the Web3 object
73− const provider = new Web3.providers.HttpProvider('http://localhost:3456');
74− const web3 = new Web3(provider);
75−
76− const target =
77− process.env.NODE_ENV === 'development'
78− ? CONTRACT_ADDRESSES.DEV
79− : CONTRACT_ADDRESSES.MAINNET;
80−
81− const contracts = azimuth.initContracts(web3, target);
82−
83− setNetwork(Maybe.Nothing(), Maybe.Just(contracts));
84− }
85− }
86−
87− getNetworkOptions() {
88− return [
89− {
90− title: 'Main Network (default)',
91− value: NETWORK_NAMES.MAINNET,
92− },
93− {
94− title: 'Local Node',
95− value: NETWORK_NAMES.LOCAL,
96− },
97− {
98− title: 'Ropsten',
99− value: NETWORK_NAMES.ROPSTEN,
100− },
101− {
102− type: 'divider',
103− },
104− {
105− title: 'Offline',
106− value: NETWORK_NAMES.OFFLINE,
107− },
108− ];
109− }
110−
111− render() {
112− const { networkType, history } = this.props;
113− const networkOptions = this.getNetworkOptions();
114−
115− return (
116− <Row>
117− <Col>
118− <H1>{'Select Network'}</H1>
119−
120− <P>
121− {"Please select the Ethereum node you'd like to send " +
122− 'transactions to. For highly valuable keys, please select ' +
123− 'offline mode.'}
124− </P>
125−
126− <InnerLabelDropdown
127− className={'mt-6'}
128− title={'Node:'}
129− handleUpdate={this.handleNetworkChange}
130− options={networkOptions}
131− currentSelectionTitle={renderNetworkType(networkType)}
132− />
133−
134− <Button
135− className={'mt-10'}
136− onClick={() => history.push(ROUTE_NAMES.WALLET)}>
137− {'Continue →'}
138− </Button>
139− </Col>
140− </Row>
141− );
142− }
8+import { useHistory } from '../store/history';
9+import { useNetwork } from '../store/network';
10+
11+const kNetworkOptions = [
12+ {
13+ title: 'Main Network (default)',
14+ value: NETWORK_NAMES.MAINNET,
15+ },
16+ {
17+ title: 'Local Node',
18+ value: NETWORK_NAMES.LOCAL,
19+ },
20+ {
21+ title: 'Ropsten',
22+ value: NETWORK_NAMES.ROPSTEN,
23+ },
24+ {
25+ type: 'divider',
26+ },
27+ {
28+ title: 'Offline',
29+ value: NETWORK_NAMES.OFFLINE,
30+ },
31+];
32+
33+function Network() {
34+ const { networkType } = useNetwork();
35+ const history = useHistory();
36+
37+ return (
38+ <Row>
39+ <Col>
40+ <H1>{'Select Network'}</H1>
41+
42+ <P>
43+ {"Please select the Ethereum node you'd like to send " +
44+ 'transactions to. For highly valuable keys, please select ' +
45+ 'offline mode.'}
46+ </P>
47+
48+ <InnerLabelDropdown
49+ className={'mt-6'}
50+ title={'Node:'}
51+ handleUpdate={this.network.setNetworkType}
52+ options={kNetworkOptions}
53+ currentSelectionTitle={renderNetworkType(networkType)}
54+ />
55+
56+ <Button
57+ className={'mt-10'}
58+ onClick={() => history.push(ROUTE_NAMES.WALLET)}>
59+ {'Continue →'}
60+ </Button>
61+ </Col>
62+ </Row>
63+ );
14364}
14465
145−export default withHistory(Network);
66+export default Network;