on master help sign in
Add view a point button to landing page
7468ecapkova
src/Bridge.js+27−2
@@ -1,8 +1,11 @@
1import Maybe from 'folktale/maybe'
1import Maybe from 'folktale/maybe'
2import * as lodash from 'lodash'
2import * as lodash from 'lodash'
3+import * as azimuth from 'azimuth-js'
3import { Stack } from 'immutable'
4import { Stack } from 'immutable'
5+import { CONTRACT_ADDRESSES } from './lib/contracts'
4import React from 'react'
6import React from 'react'
5
7
8+import Web3 from 'web3'
6import Footer from './components/Footer'
9import Footer from './components/Footer'
7import Header from './components/Header'
10import Header from './components/Header'
8import { Container, Row, Col } from './components/Base'
11import { Container, Row, Col } from './components/Base'
@@ -14,6 +17,24 @@ import { BRIDGE_ERROR } from './lib/error'
14
17
15import './style/index.css'
18import './style/index.css'
16
19
20+const initWeb3 = (networkType) => {
21+ if (networkType === NETWORK_NAMES.MAINNET) {
22+ const endpoint =
23+ `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_KEY}`
24+
25+ const provider = new Web3.providers.HttpProvider(endpoint)
26+ const web3 = new Web3(provider)
27+ const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.MAINNET)
28+ return {web3: web3, contracts: contracts}
29+ } else if (networkType === NETWORK_NAMES.LOCAL) {
30+ const endpoint = 'wss://localhost:8545'
31+ const provider = new Web3.providers.WebsocketProvider(endpoint)
32+ const web3 = new Web3(provider)
33+ const contracts = azimuth.initContracts(web3, CONTRACT_ADDRESSES.DEV)
34+ return {web3: web3, contracts: contracts}
35+ }
36+}
37+
17class Bridge extends React.Component {
38class Bridge extends React.Component {
18
39
19 constructor(props) {
40 constructor(props) {
@@ -24,6 +45,10 @@ class Bridge extends React.Component {
24 ? NETWORK_NAMES.LOCAL
45 ? NETWORK_NAMES.LOCAL
25 : NETWORK_NAMES.MAINNET
46 : NETWORK_NAMES.MAINNET
26
47
48+ // Sidestepping full network selection to allow for point viewing,
49+ // but still respecting the networkType
50+ const { web3, contracts } = initWeb3(networkType)
51+
27 // NB (jtobin):
52 // NB (jtobin):
28 //
53 //
29 // Note that the 'wallet' prop has type depending on the 'walletType' prop.
54 // Note that the 'wallet' prop has type depending on the 'walletType' prop.
@@ -42,8 +67,8 @@ class Bridge extends React.Component {
42 routeCrumbs: Stack([ ROUTE_NAMES.LANDING ]),
67 routeCrumbs: Stack([ ROUTE_NAMES.LANDING ]),
43 // network
68 // network
44 networkType: networkType,
69 networkType: networkType,
45− web3: Maybe.Nothing(),
70+ web3: Maybe.Just(web3),
46− contracts: Maybe.Nothing(),
71+ contracts: Maybe.Just(contracts),
47 // wallet
72 // wallet
48 walletType: WALLET_NAMES.MNEMONIC,
73 walletType: WALLET_NAMES.MNEMONIC,
49 wallet: Maybe.Nothing(),
74 wallet: Maybe.Nothing(),
src/views/Landing.js+14
@@ -34,6 +34,20 @@ const Landing = (props) =>
34 </P>
34 </P>
35
35
36 {
36 {
37+ <Row>
38+ <Col>
39+ <Button
40+ prop-type={'link'}
41+ prop-size={'md'}
42+ onClick={ () => props.pushRoute(ROUTE_NAMES.VIEW_SHIP) }
43+ >
44+ { 'View a point →' }
45+ </Button>
46+ <P>
47+ { "View a point on Azimuth." }
48+ </P>
49+ </Col>
50+ </Row>
37 // FIXME add address view
51 // FIXME add address view
38 // <LinkButton
52 // <LinkButton
39 // size={'l'}
53 // size={'l'}
src/views/Network.js−5
@@ -34,11 +34,6 @@ class Network extends React.Component {
34 }))
34 }))
35 }
35 }
36
36
37− componentDidMount() {
38− const { networkType } = this.props
39− this.handleNetworkChange(networkType)
40− }
41−
42 handleNetworkChange(network) {
37 handleNetworkChange(network) {
43 const { setNetworkType, setNetwork } = this.props
38 const { setNetworkType, setNetwork } = this.props
44
39
src/views/Point.js+10−222
@@ -7,19 +7,10 @@ import * as azimuth from 'azimuth-js'
7import PointList from '../components/PointList'
7import PointList from '../components/PointList'
8import ReactSVGComponents from '../components/ReactSVGComponents'
8import ReactSVGComponents from '../components/ReactSVGComponents'
9import KeysAndMetadata from './Point/KeysAndMetadata'
9import KeysAndMetadata from './Point/KeysAndMetadata'
10+import Actions from './Point/Actions'
10import { BRIDGE_ERROR } from '../lib/error'
11import { BRIDGE_ERROR } from '../lib/error'
11−import { ROUTE_NAMES } from '../lib/router'
12−import { Row, Col, H1, H2, H3, P } from '../components/Base'
13−import { Button } from '../components/Base'
12+import { Row, Col, H1, H3 } from '../components/Base'
14−import {
15− ETH_ZERO_ADDR,
16− CURVE_ZERO_ADDR,
17− addressFromSecp256k1Public,
18− eqAddr
19− } from '../lib/wallet'
20
13
21−const isPlanet = point =>
22− parseInt(point, 10) > 65535
23
14
24class Point extends React.Component {
15class Point extends React.Component {
25
16
@@ -84,12 +75,6 @@ class Point extends React.Component {
84
75
85 const { spawned } = this.state
76 const { spawned } = this.state
86
77
87− const addr = wallet.matchWith({
88− Just: (wal) => addressFromSecp256k1Public(wal.value.publicKey),
89− Nothing: () => {
90− throw BRIDGE_ERROR.MISSING_WALLET
91− }
92− })
93
78
94 const point = pointCursor.matchWith({
79 const point = pointCursor.matchWith({
95 Just: (cursor) => cursor.value,
80 Just: (cursor) => cursor.value,
@@ -113,93 +98,11 @@ class Point extends React.Component {
113
98
114 const online = Maybe.Just.hasInstance(web3)
99 const online = Maybe.Just.hasInstance(web3)
115
100
116− const canSetTransferProxy = pointDetails.matchWith({
101+ const authenticated = wallet.matchWith({
117− // also should check is addr is operator
102+ Just: _ => true,
118− Nothing: _ => false,
103+ Nothing: _ => false
119− Just: details => eqAddr(details.value.owner, addr)
120 })
104 })
121
105
122− const canSetSpawnProxy = pointDetails.matchWith({
123− Nothing: _ => false,
124− Just: details =>
125− eqAddr(details.value.owner, addr) && details.value.active
126− })
127−
128−
129− const canSetManagementProxy = pointDetails.matchWith({
130− Nothing: _ => false,
131− Just: details =>
132− eqAddr(details.value.owner, addr) && details.value.active
133− })
134−
135− const canConfigureKeys = pointDetails.matchWith({
136− Nothing: _ => false,
137− Just: details => {
138− const canManage =
139− eqAddr(details.value.owner, addr)
140− || eqAddr(details.value.managementProxy, addr)
141−
142− return canManage && details.value.active
143− }
144− })
145−
146− const canIssueChild =
147− pointDetails.matchWith({
148− Nothing: () => false,
149− Just: (details) => {
150− const hasPermission =
151− eqAddr(details.value.owner, addr)
152− || eqAddr(details.value.spawnProxy, addr)
153−
154− const isBooted =
155− details.value.keyRevisionNumber > 0
156−
157− const isNotPlanet = !isPlanet(point)
158−
159− return hasPermission && isBooted && isNotPlanet
160− }
161− })
162−
163− const planet = isPlanet(point)
164−
165− const canTransfer =
166− pointDetails.matchWith({
167− Nothing: () => false,
168− Just: (deets) =>
169− eqAddr(deets.value.transferProxy, addr) ||
170− eqAddr(deets.value.owner, addr)
171− })
172−
173− const canGenKeyfile =
174− pointDetails.matchWith({
175− Nothing: () => false,
176− Just: (deets) => {
177− const hasPermission =
178− eqAddr(deets.value.owner, addr)
179− || eqAddr(deets.value.managementProxy, addr)
180−
181− const isBooted =
182− deets.value.keyRevisionNumber > 0
183−
184− return hasPermission && isBooted
185− }
186− })
187−
188− const canAcceptTransfer =
189− pointDetails.matchWith({
190− Nothing: () => false,
191− Just: (deets) =>
192− eqAddr(deets.value.transferProxy, addr)
193− })
194−
195− const canCancelTransfer =
196− pointDetails.matchWith({
197− Nothing: () => false,
198− Just: (deets) =>
199− eqAddr(deets.value.owner, addr) &&
200− !eqAddr(deets.value.transferProxy, ETH_ZERO_ADDR)
201− })
202−
203 const routeHandler = route => {
106 const routeHandler = route => {
204 popRoute()
107 popRoute()
205 pushRoute(route)
108 pushRoute(route)
@@ -219,141 +122,26 @@ class Point extends React.Component {
219 </div>
122 </div>
220
123
221
124
222− const displayReminder = pointDetails.matchWith({
223− Nothing: () => false,
224− Just: (deets) => {
225− return deets.value.encryptionKey === CURVE_ZERO_ADDR
226− && deets.value.authenticationKey === CURVE_ZERO_ADDR
227− }
228− })
229
125
230 return (
126 return (
231 <Row>
127 <Row>
232 <Col>
128 <Col>
233−
234 <div className={'mt-12 pt-6'}>
129 <div className={'mt-12 pt-6'}>
235 { sigil }
130 { sigil }
236 </div>
131 </div>
237−
238 <H1><code>{ name }</code></H1>
132 <H1><code>{ name }</code></H1>
239−
240− <H2>{ 'Actions' }</H2>
241−
242 {
133 {
243− displayReminder
134+ authenticated
244− ? <P>{`Before you can issue child points or generate your Arvo
135+ ? <Actions pushRoute={ pushRoute } online={ online } point={ point } pointDetails={ pointDetails } wallet={ wallet }/>
245− keyfile, you need to set your public keys.`}</P>
136+ : null
246− : ''
247 }
137 }
248
138
249− <Row>
250− <Col className={'flex flex-column items-start col-md-4'}>
251− <Button
252− prop-size={'sm'}
253− prop-type={'link'}
254− disabled={ (online || planet) && !canIssueChild }
255− onClick={ () => {
256− pushRoute(ROUTE_NAMES.ISSUE_CHILD)
257− }}
258− >
259− { 'Issue child' }
260− </Button>
261−
262− <Button
263− prop-size={'sm'}
264− prop-type={'link'}
265− disabled={ !canAcceptTransfer }
266− onClick={ () => {
267− pushRoute(ROUTE_NAMES.ACCEPT_TRANSFER)
268− }}
269− >
270− { 'Accept incoming transfer' }
271− </Button>
272−
273− <Button
274− prop-size={'sm'}
275− prop-type={'link'}
276− disabled={ online && !canCancelTransfer }
277− onClick={ () => {
278− pushRoute(ROUTE_NAMES.CANCEL_TRANSFER)
279− }}
280− >
281− { 'Cancel outgoing transfer' }
282− </Button>
283−
284− <Button
285− prop-size={'sm'}
286− prop-type={'link'}
287− disabled={ !canGenKeyfile }
288− onClick={ () => {
289− pushRoute(ROUTE_NAMES.GEN_KEYFILE)
290− }}
291− >
292− { 'Generate Arvo keyfile' }
293− </Button>
294−
295− </Col>
296− <Col className={'flex flex-column items-start col-md-4'}>
297−
298− <Button
299− disabled={ online && !canSetSpawnProxy }
300− prop-size={'sm'}
301− prop-type={'link'}
302− onClick={ () => {
303− pushRoute(ROUTE_NAMES.SET_SPAWN_PROXY)
304− }}
305− >
306− { 'Set spawn proxy' }
307− </Button>
308−
309− <Button
310− disabled={ online && !canSetManagementProxy }
311− prop-size={'sm'}
312− prop-type={'link'}
313− onClick={ () => {
314− pushRoute(ROUTE_NAMES.SET_MANAGEMENT_PROXY)
315− }}
316− >
317− { 'Set management proxy' }
318− </Button>
319−
320− <Button
321− disabled={ online && !canConfigureKeys }
322− prop-size={'sm'}
323− prop-type={'link'}
324− onClick={ () => {
325− pushRoute(ROUTE_NAMES.SET_KEYS)
326− }}
327− >
328− { 'Set public keys' }
329− </Button>
330−
331− <Button
332− disabled={ online && !canTransfer }
333− prop-size={'sm'}
334− prop-type={'link'}
335− onClick={ () => {
336− pushRoute(ROUTE_NAMES.TRANSFER)
337− }}
338− >
339− { 'Transfer' }
340− </Button>
341−
342− </Col>
343− </Row>
344−
345−
346−
347− {
139+ {
348 online
140 online
349 ? <KeysAndMetadata pointDetails={ pointDetails } />
141 ? <KeysAndMetadata pointDetails={ pointDetails } />
350 : <div />
142 : <div />
351− }
143+ }
352−
353−
354−
355 { issuedPointList }
144 { issuedPointList }
356−
357 </Col>
145 </Col>
358 </Row>
146 </Row>
359 )
147 )
src/views/Point/Actions.jsnew file+230
@@ -0,0 +1,230 @@
1+import React from 'react'
2+import {
3+ ETH_ZERO_ADDR,
4+ CURVE_ZERO_ADDR,
5+ addressFromSecp256k1Public,
6+ eqAddr
7+} from '../../lib/wallet'
8+import { BRIDGE_ERROR } from '../../lib/error'
9+import { Row, Col, H2, P } from '../../components/Base'
10+import { Button } from '../../components/Base'
11+import { ROUTE_NAMES } from '../../lib/router'
12+
13+
14+const isPlanet = point =>
15+ parseInt(point, 10) > 65535
16+
17+const Actions = (props) => {
18+ const { pushRoute, online, point, pointDetails, wallet } = props
19+
20+ const addr = wallet.matchWith({
21+ Just: (wal) => addressFromSecp256k1Public(wal.value.publicKey),
22+ Nothing: () => {
23+ throw BRIDGE_ERROR.MISSING_WALLET
24+ }
25+ })
26+
27+ const canSetTransferProxy = pointDetails.matchWith({
28+ // also should check is addr is operator
29+ Nothing: _ => false,
30+ Just: details => eqAddr(details.value.owner, addr)
31+ })
32+
33+ const canSetSpawnProxy = pointDetails.matchWith({
34+ Nothing: _ => false,
35+ Just: details =>
36+ eqAddr(details.value.owner, addr) && details.value.active
37+ })
38+
39+
40+ const canSetManagementProxy = pointDetails.matchWith({
41+ Nothing: _ => false,
42+ Just: details =>
43+ eqAddr(details.value.owner, addr) && details.value.active
44+ })
45+
46+ const canConfigureKeys = pointDetails.matchWith({
47+ Nothing: _ => false,
48+ Just: details => {
49+ const canManage =
50+ eqAddr(details.value.owner, addr)
51+ || eqAddr(details.value.managementProxy, addr)
52+
53+ return canManage && details.value.active
54+ }
55+ })
56+
57+ const canIssueChild =
58+ pointDetails.matchWith({
59+ Nothing: () => false,
60+ Just: (details) => {
61+ const hasPermission =
62+ eqAddr(details.value.owner, addr)
63+ || eqAddr(details.value.spawnProxy, addr)
64+
65+ const isBooted =
66+ details.value.keyRevisionNumber > 0
67+
68+ const isNotPlanet = !isPlanet(point)
69+
70+ return hasPermission && isBooted && isNotPlanet
71+ }
72+ })
73+
74+ const planet = isPlanet(point)
75+
76+ const canTransfer =
77+ pointDetails.matchWith({
78+ Nothing: () => false,
79+ Just: (deets) =>
80+ eqAddr(deets.value.transferProxy, addr) ||
81+ eqAddr(deets.value.owner, addr)
82+ })
83+
84+ const canGenKeyfile =
85+ pointDetails.matchWith({
86+ Nothing: () => false,
87+ Just: (deets) => {
88+ const hasPermission =
89+ eqAddr(deets.value.owner, addr)
90+ || eqAddr(deets.value.managementProxy, addr)
91+
92+ const isBooted =
93+ deets.value.keyRevisionNumber > 0
94+
95+ return hasPermission && isBooted
96+ }
97+ })
98+
99+ const canAcceptTransfer =
100+ pointDetails.matchWith({
101+ Nothing: () => false,
102+ Just: (deets) =>
103+ eqAddr(deets.value.transferProxy, addr)
104+ })
105+
106+ const canCancelTransfer =
107+ pointDetails.matchWith({
108+ Nothing: () => false,
109+ Just: (deets) =>
110+ eqAddr(deets.value.owner, addr) &&
111+ !eqAddr(deets.value.transferProxy, ETH_ZERO_ADDR)
112+ })
113+
114+ const displayReminder = pointDetails.matchWith({
115+ Nothing: () => false,
116+ Just: (deets) => {
117+ return deets.value.encryptionKey === CURVE_ZERO_ADDR
118+ && deets.value.authenticationKey === CURVE_ZERO_ADDR
119+ }
120+ })
121+
122+ return (
123+ <div>
124+ <H2>{ 'Actions' }</H2>
125+ {
126+ displayReminder
127+ ? <P>{`Before you can issue child points or generate your Arvo
128+ keyfile, you need to set your public keys.`}</P>
129+ : ''
130+ }
131+ <Row>
132+ <Col className={'flex flex-column items-start col-md-4'}>
133+ <Button
134+ prop-size={'sm'}
135+ prop-type={'link'}
136+ disabled={ (online || planet) && !canIssueChild }
137+ onClick={ () => {
138+ pushRoute(ROUTE_NAMES.ISSUE_CHILD)
139+ }}
140+ >
141+ { 'Issue child' }
142+ </Button>
143+
144+ <Button
145+ prop-size={'sm'}
146+ prop-type={'link'}
147+ disabled={ !canAcceptTransfer }
148+ onClick={ () => {
149+ pushRoute(ROUTE_NAMES.ACCEPT_TRANSFER)
150+ }}
151+ >
152+ { 'Accept incoming transfer' }
153+ </Button>
154+
155+ <Button
156+ prop-size={'sm'}
157+ prop-type={'link'}
158+ disabled={ online && !canCancelTransfer }
159+ onClick={ () => {
160+ pushRoute(ROUTE_NAMES.CANCEL_TRANSFER)
161+ }}
162+ >
163+ { 'Cancel outgoing transfer' }
164+ </Button>
165+
166+ <Button
167+ prop-size={'sm'}
168+ prop-type={'link'}
169+ disabled={ !canGenKeyfile }
170+ onClick={ () => {
171+ pushRoute(ROUTE_NAMES.GEN_KEYFILE)
172+ }}
173+ >
174+ { 'Generate Arvo keyfile' }
175+ </Button>
176+
177+ </Col>
178+ <Col className={'flex flex-column items-start col-md-4'}>
179+
180+ <Button
181+ disabled={ online && !canSetSpawnProxy }
182+ prop-size={'sm'}
183+ prop-type={'link'}
184+ onClick={ () => {
185+ pushRoute(ROUTE_NAMES.SET_SPAWN_PROXY)
186+ }}
187+ >
188+ { 'Set spawn proxy' }
189+ </Button>
190+
191+ <Button
192+ disabled={ online && !canSetManagementProxy }
193+ prop-size={'sm'}
194+ prop-type={'link'}
195+ onClick={ () => {
196+ pushRoute(ROUTE_NAMES.SET_MANAGEMENT_PROXY)
197+ }}
198+ >
199+ { 'Set management proxy' }
200+ </Button>
201+
202+ <Button
203+ disabled={ online && !canConfigureKeys }
204+ prop-size={'sm'}
205+ prop-type={'link'}
206+ onClick={ () => {
207+ pushRoute(ROUTE_NAMES.SET_KEYS)
208+ }}
209+ >
210+ { 'Set public keys' }
211+ </Button>
212+
213+ <Button
214+ disabled={ online && !canTransfer }
215+ prop-size={'sm'}
216+ prop-type={'link'}
217+ onClick={ () => {
218+ pushRoute(ROUTE_NAMES.TRANSFER)
219+ }}
220+ >
221+ { 'Transfer' }
222+ </Button>
223+
224+ </Col>
225+ </Row>
226+ </div>
227+ )
228+}
229+
230+export default Actions