on master help sign in
feat: add cancel transfer admin view
75e1000Matt Condon (shrugs)
src/lib/constants.js+1
@@ -30,6 +30,7 @@ const CRYPTO_SUITE_VERSION = 1;
30const GAS_LIMITS = {
30const GAS_LIMITS = {
31 SPAWN: 250000,
31 SPAWN: 250000,
32 TRANSFER: 550000,
32 TRANSFER: 550000,
33+ CANCEL_TRANSFER: 550000, //NOTE: no samples
33 CONFIGURE_KEYS: 100000,
34 CONFIGURE_KEYS: 100000,
34 SET_PROXY: 120000,
35 SET_PROXY: 120000,
35 //
36 //
src/lib/usePermissionsForPoint.js+26−2
@@ -2,12 +2,23 @@ import { azimuth } from 'azimuth-js';
2
2
3import { usePointCache } from 'store/pointCache';
3import { usePointCache } from 'store/pointCache';
4
4
5−import { eqAddr } from './wallet';
5+import { eqAddr, ETH_ZERO_ADDR } from './wallet';
6
6
7const NULL_PERMISSIONS = {
7const NULL_PERMISSIONS = {
8+ isPlanet: false,
9+ isStar: false,
10+ isGalaxy: false,
11+ //
8 isOwner: false,
12 isOwner: false,
13+ isActiveOwner: false,
9 isTransferProxy: false,
14 isTransferProxy: false,
10 isManagementProxy: false,
15 isManagementProxy: false,
16+ //
17+ isManagementProxySet: false,
18+ isSpawnProxySet: false,
19+ isVotingProxySet: false,
20+ isTransferProxySet: false,
21+ //
11 canManage: false,
22 canManage: false,
12 canTransfer: false,
23 canTransfer: false,
13 canSpawn: false,
24 canSpawn: false,
@@ -31,10 +42,18 @@ export default function usePermissionsForPoint(address, point) {
31
42
32 const isOwner = eqAddr(address, details.owner);
43 const isOwner = eqAddr(address, details.owner);
33 const isActiveOwner = isOwner && details.active;
44 const isActiveOwner = isOwner && details.active;
34− const isTransferProxy = eqAddr(address, details.transferProxy);
35 const isManagementProxy = eqAddr(address, details.managementProxy);
45 const isManagementProxy = eqAddr(address, details.managementProxy);
36 const isSpawnProxy = eqAddr(address, details.spawnProxy);
46 const isSpawnProxy = eqAddr(address, details.spawnProxy);
37 const isVotingProxy = eqAddr(address, details.votingProxy);
47 const isVotingProxy = eqAddr(address, details.votingProxy);
48+ const isTransferProxy = eqAddr(address, details.transferProxy);
49+
50+ const isManagementProxySet = !eqAddr(
51+ ETH_ZERO_ADDR,
52+ details.managementProxy
53+ );
54+ const isSpawnProxySet = !eqAddr(ETH_ZERO_ADDR, details.spawnProxy);
55+ const isVotingProxySet = !eqAddr(ETH_ZERO_ADDR, details.votingProxy);
56+ const isTransferProxySet = !eqAddr(ETH_ZERO_ADDR, details.transferProxy);
38
57
39 const canManage = isOwner || isManagementProxy;
58 const canManage = isOwner || isManagementProxy;
40 const canTransfer = isOwner || isTransferProxy;
59 const canTransfer = isOwner || isTransferProxy;
@@ -51,6 +70,11 @@ export default function usePermissionsForPoint(address, point) {
51 isTransferProxy,
70 isTransferProxy,
52 isManagementProxy,
71 isManagementProxy,
53 //
72 //
73+ isManagementProxySet,
74+ isSpawnProxySet,
75+ isVotingProxySet,
76+ isTransferProxySet,
77+ //
54 canManage,
78 canManage,
55 canTransfer,
79 canTransfer,
56 canSpawn,
80 canSpawn,
src/views/Admin.js+3
@@ -16,6 +16,7 @@ import AdminRedownload from './Admin/AdminRedownload';
16import AdminReticket from './Admin/AdminReticket';
16import AdminReticket from './Admin/AdminReticket';
17import AdminSetProxy from './Admin/AdminSetProxy';
17import AdminSetProxy from './Admin/AdminSetProxy';
18import AdminTransfer from './Admin/AdminTransfer';
18import AdminTransfer from './Admin/AdminTransfer';
19+import AdminCancelTransfer from './Admin/AdminCancelTransfer';
19import AdminNetworkingKeys from './Admin/AdminNetworkingKeys';
20import AdminNetworkingKeys from './Admin/AdminNetworkingKeys';
20
21
21const NAMES = {
22const NAMES = {
@@ -25,6 +26,7 @@ const NAMES = {
25 RETICKET: 'RETICKET',
26 RETICKET: 'RETICKET',
26 SET_PROXY: 'SET_PROXY',
27 SET_PROXY: 'SET_PROXY',
27 TRANSFER: 'TRANSFER',
28 TRANSFER: 'TRANSFER',
29+ CANCEL_TRANSFER: 'CANCEL_TRANSFER',
28 NETWORKING_KEYS: 'NETWORKING_KEYS',
30 NETWORKING_KEYS: 'NETWORKING_KEYS',
29};
31};
30
32
@@ -35,6 +37,7 @@ const VIEWS = {
35 [NAMES.RETICKET]: AdminReticket,
37 [NAMES.RETICKET]: AdminReticket,
36 [NAMES.SET_PROXY]: AdminSetProxy,
38 [NAMES.SET_PROXY]: AdminSetProxy,
37 [NAMES.TRANSFER]: AdminTransfer,
39 [NAMES.TRANSFER]: AdminTransfer,
40+ [NAMES.CANCEL_TRANSFER]: AdminCancelTransfer,
38 [NAMES.NETWORKING_KEYS]: AdminNetworkingKeys,
41 [NAMES.NETWORKING_KEYS]: AdminNetworkingKeys,
39};
42};
40
43
src/views/Admin/AdminCancelTransfer.jsnew file+91
@@ -0,0 +1,91 @@
1+import React, { useEffect } from 'react';
2+import cn from 'classnames';
3+import { Grid, Text } from 'indigo-react';
4+import * as azimuth from 'azimuth-js';
5+
6+import { useNetwork } from 'store/network';
7+import { usePointCursor } from 'store/pointCursor';
8+import { usePointCache } from 'store/pointCache';
9+
10+import * as need from 'lib/need';
11+import { useLocalRouter } from 'lib/LocalRouter';
12+import useCurrentPointName from 'lib/useCurrentPointName';
13+import useEthereumTransaction from 'lib/useEthereumTransaction';
14+import { GAS_LIMITS } from 'lib/constants';
15+import { ETH_ZERO_ADDR } from 'lib/wallet';
16+import useLifecycle from 'lib/useLifecycle';
17+
18+import ViewHeader from 'components/ViewHeader';
19+import MiniBackButton from 'components/MiniBackButton';
20+import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
21+
22+function useCancelTransfer() {
23+ const { contracts } = useNetwork();
24+ const { pointCursor } = usePointCursor();
25+ const { syncOwnedPoint } = usePointCache();
26+
27+ const _contracts = need.contracts(contracts);
28+ const _point = need.point(pointCursor);
29+
30+ const { construct, confirmed, bind } = useEthereumTransaction(
31+ GAS_LIMITS.CANCEL_TRANSFER
32+ );
33+
34+ useLifecycle(() => {
35+ construct(
36+ azimuth.ecliptic.setTransferProxy(_contracts, _point, ETH_ZERO_ADDR)
37+ );
38+ });
39+
40+ // sync point details after success
41+ useEffect(() => {
42+ if (confirmed) {
43+ syncOwnedPoint(_point);
44+ }
45+ }, [_point, confirmed, syncOwnedPoint]);
46+
47+ return {
48+ confirmed,
49+ bind,
50+ };
51+}
52+
53+export default function AdminCancelTransfer() {
54+ const { pop } = useLocalRouter();
55+ const { getDetails } = usePointCache();
56+ const { pointCursor } = usePointCursor();
57+ const _point = need.point(pointCursor);
58+
59+ const name = useCurrentPointName();
60+ const _details = need.details(getDetails(_point));
61+
62+ const { confirmed, bind } = useCancelTransfer();
63+
64+ return (
65+ <Grid>
66+ <Grid.Item full as={MiniBackButton} onClick={() => pop()} />
67+
68+ <Grid.Item full as={ViewHeader}>
69+ Cancel Outgoing Transfer
70+ </Grid.Item>
71+
72+ <Grid.Item
73+ full
74+ as={Text}
75+ className={cn('f5', {
76+ green3: confirmed,
77+ })}>
78+ {confirmed
79+ ? `The outgoing transfer of ${name} has been cancelled.`
80+ : `Cancel the outgoing transfer of ${name} to ${_details.transferProxy}.`}
81+ </Grid.Item>
82+
83+ <Grid.Item
84+ full
85+ as={InlineEthereumTransaction}
86+ {...bind}
87+ onReturn={() => pop()}
88+ />
89+ </Grid>
90+ );
91+}
src/views/Admin/AdminHome.js+27−9
@@ -22,7 +22,10 @@ export default function AdminHome() {
22
22
23 const point = need.point(pointCursor);
23 const point = need.point(pointCursor);
24 const address = need.addressFromWallet(wallet);
24 const address = need.addressFromWallet(wallet);
25− const { isOwner, canTransfer } = usePermissionsForPoint(address, point);
25+ const { isOwner, canTransfer, isTransferProxySet } = usePermissionsForPoint(
26+ address,
27+ point
28+ );
26
29
27 const goRedownload = useCallback(() => push(names.REDOWNLOAD), [push, names]);
30 const goRedownload = useCallback(() => push(names.REDOWNLOAD), [push, names]);
28 const goReticket = useCallback(() => push(names.RETICKET), [push, names]);
31 const goReticket = useCallback(() => push(names.RETICKET), [push, names]);
@@ -30,6 +33,10 @@ export default function AdminHome() {
30 push,
33 push,
31 names,
34 names,
32 ]);
35 ]);
36+ const goCancelTransfer = useCallback(() => push(names.CANCEL_TRANSFER), [
37+ names,
38+ push,
39+ ]);
33 const goTransfer = useCallback(() => push(names.TRANSFER), [names, push]);
40 const goTransfer = useCallback(() => push(names.TRANSFER), [names, push]);
34
41
35 const canDownloadPassport = Just.hasInstance(urbitWallet);
42 const canDownloadPassport = Just.hasInstance(urbitWallet);
@@ -79,14 +86,25 @@ export default function AdminHome() {
79 Edit Permissions
86 Edit Permissions
80 </Grid.Item>
87 </Grid.Item>
81 <Grid.Divider />
88 <Grid.Divider />
89+ {isTransferProxySet ? (
82− <Grid.Item
90+ <Grid.Item
91+ full
92+ as={ForwardButton}
93+ onClick={goCancelTransfer}
94+ detail="Cancel outgoing transfer"
95+ disabled={!canTransfer}>
96+ Cancel Outgoing Transfer
97+ </Grid.Item>
98+ ) : (
99+ <Grid.Item
83− full
100+ full
84− as={ForwardButton}
101+ as={ForwardButton}
85− onClick={goTransfer}
102+ onClick={goTransfer}
86− detail="Transfer ownership of this point"
103+ detail="Transfer ownership of this point"
87− disabled={!canTransfer}>
104+ disabled={!canTransfer}>
88− Transfer
105+ Transfer
89− </Grid.Item>
106+ </Grid.Item>
107+ )}
90 <Grid.Divider />
108 <Grid.Divider />
91 </Grid>
109 </Grid>
92 </>
110 </>
src/views/Admin/AdminTransfer.js+9
@@ -5,6 +5,7 @@ import * as azimuth from 'azimuth-js';
5
5
6import { useNetwork } from 'store/network';
6import { useNetwork } from 'store/network';
7import { usePointCursor } from 'store/pointCursor';
7import { usePointCursor } from 'store/pointCursor';
8+import { usePointCache } from 'store/pointCache';
8
9
9import * as need from 'lib/need';
10import * as need from 'lib/need';
10import { useLocalRouter } from 'lib/LocalRouter';
11import { useLocalRouter } from 'lib/LocalRouter';
@@ -20,6 +21,7 @@ import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
20function useTransfer() {
21function useTransfer() {
21 const { contracts } = useNetwork();
22 const { contracts } = useNetwork();
22 const { pointCursor } = usePointCursor();
23 const { pointCursor } = usePointCursor();
24+ const { syncOwnedPoint } = usePointCache();
23
25
24 const _contracts = need.contracts(contracts);
26 const _contracts = need.contracts(contracts);
25 const _point = need.point(pointCursor);
27 const _point = need.point(pointCursor);
@@ -39,6 +41,13 @@ function useTransfer() {
39 [_construct, _contracts, _point]
41 [_construct, _contracts, _point]
40 );
42 );
41
43
44+ // sync point details after success
45+ useEffect(() => {
46+ if (confirmed) {
47+ syncOwnedPoint(_point);
48+ }
49+ }, [_point, confirmed, syncOwnedPoint]);
50+
42 return {
51 return {
43 construct,
52 construct,
44 confirmed,
53 confirmed,