@@ -0,0 +1,167 @@
1+import React, { useState, useCallback } from 'react';
2+import { Just, Nothing } from 'folktale/maybe';
3+import * as need from 'lib/need';
4+import { azimuth } from 'azimuth-js';
5+import { Grid } from 'indigo-react';
6+
7+import { P } from 'indigo-react';
8+import View from 'components/View';
9+import { ForwardButton } from 'components/Buttons';
10+import FooterButton from 'components/FooterButton';
11+import Blinky, {
12+ LOADING_CHARACTER,
13+ INTERSTITIAL_CHARACTER,
14+} from 'components/Blinky';
15+
16+import { ROUTE_NAMES } from 'lib/routeNames';
17+import { eqAddr } from 'lib/wallet';
18+
19+import useLifecycle from 'lib/useLifecycle';
20+import { useNetwork } from 'store/network';
21+import { useHistory } from 'store/history';
22+import { useWallet } from 'store/wallet';
23+import { usePointCursor } from 'store/pointCursor';
24+import { usePointCache } from 'store/pointCache';
25+
26+//TODO consolidate with azimuth-js' getActivationBlock
27+const getRekeyDate = async (web3, contracts, point) => {
28+ const logs = await contracts.azimuth.getPastEvents('ChangedKeys', {
29+ fromBlock: 0,
30+ toBlock: 'latest',
31+ filter: { point: [point] },
32+ });
33+ if (logs.length === 0) {
34+ return null;
35+ } else {
36+ // last log is most recent
37+ const block = await web3.eth.getBlock(logs[logs.length - 1].blockNumber);
38+ return new Date(block.timestamp * 1000);
39+ }
40+};
41+
42+export default function Permissions() {
43+ const history = useHistory();
44+ const { web3, contracts } = useNetwork();
45+ const { wallet } = useWallet();
46+ const { pointCursor } = usePointCursor();
47+ const { pointCache } = usePointCache();
48+
49+ const [rekeyDate, setRekeyDate] = useState(Nothing());
50+
51+ const point = need.point(pointCursor);
52+ const pointSize = azimuth.getPointSize(point);
53+ const userAddress = need.wallet(wallet).address;
54+
55+ useLifecycle(() => {
56+ getRekeyDate(need.web3(web3), need.contracts(contracts), point).then(
57+ res => {
58+ if (res === null) setRekeyDate(Just('unknown'));
59+ else setRekeyDate(Just(res.toString()));
60+ }
61+ );
62+ });
63+
64+ const goSetManagement = useCallback(
65+ () => history.push(ROUTE_NAMES.SET_MANAGEMENT_PROXY),
66+ [history]
67+ );
68+
69+ const goSetSpawn = useCallback(
70+ () => history.push(ROUTE_NAMES.SET_SPAWN_PROXY),
71+ [history]
72+ );
73+
74+ const goSetVoting = useCallback(
75+ () => history.push(ROUTE_NAMES.SET_VOTING_PROXY),
76+ [history]
77+ );
78+
79+ const goSetKeys = useCallback(() => history.push(ROUTE_NAMES.SET_KEYS), [
80+ history,
81+ ]);
82+
83+ const pointDetails = need.fromPointCache(pointCache, point);
84+
85+ const isOwner = eqAddr(userAddress, pointDetails.owner);
86+ const canManage =
87+ isOwner || eqAddr(userAddress, pointDetails.managementProxy);
88+
89+ const proxyAction = (name, address, onClick) => {
90+ if (address === '0x0000000000000000000000000000000000000000')
91+ address = 'Unset';
92+ return (
93+ <Grid.Item full>
94+ <ForwardButton disabled={!isOwner} onClick={onClick} detail={address}>
95+ {`${name} proxy address`}
96+ </ForwardButton>
97+ </Grid.Item>
98+ );
99+ };
100+
101+ let items = 3;
102+
103+ let spawnProxyAction = null;
104+ if (pointSize !== azimuth.PointSize.Planet) {
105+ items++;
106+ spawnProxyAction = proxyAction(
107+ 'Spawn',
108+ pointDetails.spawnProxy,
109+ goSetSpawn
110+ );
111+ }
112+
113+ let votingProxyAction = null;
114+ if (pointSize === azimuth.PointSize.Galaxy) {
115+ items++;
116+ votingProxyAction = proxyAction(
117+ 'Voting',
118+ pointDetails.votingProxy,
119+ goSetVoting
120+ );
121+ }
122+
123+ const netKeysText =
124+ pointDetails.keyRevisionNumber === 0 ? (
125+ 'Not yet configured'
126+ ) : (
127+ <>
128+ {`Revision #${pointDetails.keyRevisionNumber}, since `}
129+ {Just.hasInstance(rekeyDate) ? (
130+ rekeyDate.value
131+ ) : (
132+ <Blinky a={LOADING_CHARACTER} b={INTERSTITIAL_CHARACTER} delayed />
133+ )}
134+ </>
135+ );
136+
137+ return (
138+ <View>
139+ <Grid className={`pt${items}`}>
140+ <Grid.Item full>
141+ <ForwardButton disabled="true" detail={pointDetails.owner}>
142+ Ownership address
143+ </ForwardButton>
144+ </Grid.Item>
145+ {proxyAction(
146+ 'Management',
147+ pointDetails.managementProxy,
148+ goSetManagement
149+ )}
150+ {spawnProxyAction}
151+ {votingProxyAction}
152+ <Grid.Item full>
153+ <ForwardButton
154+ disabled={!canManage}
155+ onClick={goSetKeys}
156+ detail={netKeysText}>
157+ Network keys
158+ </ForwardButton>
159+ </Grid.Item>
160+ </Grid>
161+
162+ <FooterButton detail="Transfer this identity to a new owner" disabled>
163+ Transfer
164+ </FooterButton>
165+ </View>
166+ );
167+}