on df0c310 help sign in
bridge/src/views/Senate/Upgrades.jsx
199 lines 5.8 kB history raw
1import React, { useCallback, useMemo, useEffect, useState } from 'react';
2import { Grid, Text, P, LinkButton } from 'indigo-react';
3import * as azimuth from 'azimuth-js';
5import { useNetwork } from 'store/network';
6import { usePointCursor } from 'store/pointCursor';
8import * as need from 'lib/need';
9import useEthereumTransaction from 'lib/useEthereumTransaction';
10import { GAS_LIMITS } from 'lib/constants';
11import { useLocalRouter } from 'lib/LocalRouter';
13import ViewHeader from 'components/ViewHeader';
14import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
15import View from 'components/View';
16import BridgeForm from 'form/BridgeForm';
17import { convertToInt } from 'lib/convertToInt';
19function useCastUpgradeVote() {
20 const { contracts } = useNetwork();
21 const { pointCursor } = usePointCursor();
23 const _contracts = need.contracts(contracts);
24 const _point = need.point(pointCursor);
26 return useEthereumTransaction(
27 useCallback(
28 (address, accept) => {
29 return azimuth.ecliptic.castUpgradeVote(
30 _contracts,
31 _point,
32 address,
33 accept
34 );
35 },
36 [_contracts, _point]
37 ),
38 useCallback(() => null, []), //TODO update polls[address].hasVoted ?
39 GAS_LIMITS.DEFAULT //TODO update once we have a decent sample size
40 );
43export default function Upgrades() {
44 const { pop } = useLocalRouter();
45 const { contracts } = useNetwork();
46 const { pointCursor } = usePointCursor();
48 const _contracts = need.contracts(contracts);
49 const _point = convertToInt(need.point(pointCursor), 10);
51 const { construct, reset, unconstruct, bind } = useCastUpgradeVote();
53 const [proposals, setProposals] = useState([]);
54 const [polls, setPolls] = useState({});
55 const [loading, setLoading] = useState(true);
56 const [votingOn, setVotingOn] = useState({});
58 //TODO update every second?
59 const now = Math.round(new Date().getTime() / 1000);
61 useEffect(() => {
62 (async () => {
63 let proposals = await azimuth.polls.getUpgradeProposals(_contracts);
64 let polls = {};
65 for (let address of proposals) {
66 let poll = await azimuth.polls.getUpgradePoll(_contracts, address);
67 poll.endTime = convertToInt(poll.start) + convertToInt(poll.duration);
68 poll.hasVoted = await azimuth.polls.hasVotedOnUpgradePoll(
69 _contracts,
70 _point,
71 address
72 );
73 polls[address] = poll;
74 }
75 setProposals(proposals);
76 setPolls(polls);
77 setLoading(false);
78 })();
79 }, [_contracts, _point]);
81 // eslint-disable-next-line
82 const [open, closed] = useMemo(() => {
83 let open = [];
84 let closed = [];
85 if (loading) return [open, closed];
86 for (let address of proposals) {
87 if (now > polls[address].endTime) {
88 closed.push(address);
89 } else {
90 open.push(address);
91 }
92 }
93 return [open, closed];
94 }, [loading, proposals, polls, now]);
96 const doVote = useCallback(
97 (address, accept) => {
98 construct(address, accept);
99 setVotingOn({ address, accept });
100 },
101 [construct]
102 );
104 const didVote = useCallback(() => {
105 reset();
106 unconstruct();
107 setPolls(polls => {
108 polls[votingOn.address].hasVoted = true;
109 return polls;
110 });
111 setVotingOn({});
112 }, [votingOn, reset, unconstruct]);
114 const openList = useMemo(() => {
115 return open.map(address => {
116 const hasVoted = polls[address].hasVoted;
117 return (
118 <>
119 <Grid.Item full className="mv2" as={Text}>
120 <a
121 target="_blank"
122 rel="noopener noreferrer"
123 href={`https://etherscan.io/address/${address}#code`}
124 class="mb4 mono wrap pre">
125 {address}↗
126 </a>
127 <P className="mt0">
128 {hasVoted ? (
129 'Your vote has been cast.'
130 ) : (
131 <>
132 <LinkButton onClick={() => doVote(address, true)}>
133 {votingOn.address === address && votingOn.accept ? (
134 <b>support</b>
135 ) : (
136 <>support</>
137 )}
138 </LinkButton>
139 {' / '}
140 <LinkButton onClick={() => doVote(address, false)}>
141 {votingOn.address === address && !votingOn.accept ? (
142 <b>reject</b>
143 ) : (
144 <>reject</>
145 )}
146 </LinkButton>
147 </>
148 )}
149 </P>
150 </Grid.Item>
151 <Grid.Divider />
152 </>
153 );
154 });
155 }, [open, polls, votingOn, doVote]);
157 return (
158 <View pop={pop} inset>
159 <Grid>
160 <Grid.Item full as={ViewHeader}>
161 Senate: Upgrade Proposals
162 </Grid.Item>
164 <Grid.Item full as={Grid}>
165 <Grid.Item full as={P}>
166 Current Ecliptic:
167 </Grid.Item>
168 <Grid.Item full className="mv2 mb4 mono wrap pre" as={P}>
169 {_contracts.ecliptic.address}
170 </Grid.Item>
171 </Grid.Item>
173 {openList.length > 0 && (
174 <>
175 <Grid.Divider className="mv4" />
177 <Grid.Item full as={Grid}>
178 <Grid.Item full as={P}>
179 Open upgrade polls:
180 </Grid.Item>
181 {openList}
182 </Grid.Item>
184 <BridgeForm>
185 {({ onSubmit, values }) => (
186 <Grid.Item
187 full
188 as={InlineEthereumTransaction}
189 {...bind}
190 onReturn={didVote}
191 />
192 )}
193 </BridgeForm>
194 </>
195 )}
196 </Grid>
197 </View>
198 );