Skip to content
This repository was archived by the owner on Oct 11, 2024. It is now read-only.

Commit 45dd031

Browse files
authored
Merge pull request #412 from 0xProject/governance-updates
Merging in recent governance updates into development
2 parents f4c8105 + da0019c commit 45dd031

32 files changed

+2965
-123
lines changed

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"eslint": "eslint 'ts/**/*.{ts,tsx}'",
1818
"lint": "tslint --format stylish --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
1919
"fix": "yarn lint --fix",
20-
"pre_push": "yarn typecheck && yarn lint:prettier && yarn lint && yarn test",
20+
"pre_push": "yarn lint:prettier && yarn lint && yarn test",
2121
"update:tools": "aws s3 sync --delete s3://docs-markdown/ mdx/tools/ --profile $(npm config get awscli_profile)",
2222
"dev": "npm run update:tools && node --max-old-space-size=16384 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --content-base public --https",
2323
"deploy_dogfood": "npm run update:tools && yarn index_docs --environment dogfood && npm run build:prod && aws s3 sync ./public/. s3://dogfood.0xproject.com --profile $(npm config get awscli_profile) --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers && ./cdn-cache-clear.sh dogfood",
@@ -77,8 +77,8 @@
7777
"find-versions": "^2.0.0",
7878
"flickity": "^2.2.2",
7979
"fuse.js": "^3.4.6",
80-
"graphql": "^15.5.0",
81-
"graphql-request": "^3.4.0",
80+
"graphql": "^15.5.1",
81+
"graphql-request": "^3.5.0",
8282
"is-mobile": "^0.2.2",
8383
"less": "^2.7.2",
8484
"lodash": "^4.17.11",
@@ -89,6 +89,7 @@
8989
"moment": "2.21.0",
9090
"moment-precise-range-plugin": "^1.3.0",
9191
"moment-timezone": "^0.5.33",
92+
"nice-color-palettes": "^3.0.0",
9293
"numeral": "^2.0.6",
9394
"polished": "^1.9.2",
9495
"query-string": "^6.0.0",
@@ -104,6 +105,7 @@
104105
"react-highlight": "0xproject/react-highlight#react-peer-deps",
105106
"react-instantsearch-dom": "^5.7.0",
106107
"react-markdown": "^4.0.6",
108+
"react-minimal-pie-chart": "^8.2.0",
107109
"react-popper": "^1.0.0-beta.6",
108110
"react-query": "^3.7.1",
109111
"react-redux": "^7.1.3",
@@ -127,6 +129,7 @@
127129
"styled-components": "^5.0.0",
128130
"thenby": "^1.2.3",
129131
"truffle-contract": "2.0.1",
132+
"urql": "^2.0.4",
130133
"valid-url": "^1.0.9",
131134
"web3-provider-engine": "14.0.6",
132135
"xml-js": "^1.6.4"

public/images/mail.png

603 Bytes
Loading
3.27 KB
Loading
4.2 KB
Loading

ts/components/dialogs/connect_wallet_dialog.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ export const ConnectWalletDialog = () => {
232232
const handleAccount = async (currentConnector: AbstractConnector, option: Option) => {
233233
let address: string = '';
234234

235+
(window as any).heap.track('Wallet connected', { wallet: option.type });
236+
// console.log(currentConnector, option)
235237
try {
236238
await activate(currentConnector, undefined, true);
237239
setActivatingConnector(currentConnector);

ts/components/governance/hero.tsx

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
import { Web3Wrapper } from '@0x/web3-wrapper';
2+
import * as React from 'react';
3+
import styled from 'styled-components';
4+
import { GOVERNOR_CONTRACT_ADDRESS } from 'ts/utils/configs';
5+
import { formatNumber } from 'ts/utils/format_number';
6+
7+
import { ERC20TokenContract } from '@0x/contract-wrappers';
8+
9+
import { BigNumber } from '@0x/utils';
10+
import { useSelector } from 'react-redux';
11+
12+
import { State } from 'ts/redux/reducer';
13+
import { backendClient } from 'ts/utils/backend_client';
14+
15+
import { ZeroExProvider } from '@0x/asset-buyer';
16+
import { colors } from 'ts/style/colors';
17+
18+
interface GovernanceHeroProps {
19+
title: string | React.ReactNode;
20+
numProposals?: number | null;
21+
titleMobile: string | React.ReactNode;
22+
description: string | React.ReactNode;
23+
figure: React.ReactNode;
24+
actions: React.ReactNode;
25+
provider?: ZeroExProvider;
26+
videoId?: string;
27+
videoChannel?: string;
28+
videoRatio?: string;
29+
youtubeOptions?: any;
30+
averageVotingPower?: number | undefined;
31+
metrics?: {
32+
zrxStaked: number;
33+
currentEpochRewards: BigNumber;
34+
nextEpochStartDate: Date;
35+
};
36+
}
37+
38+
interface WrapperProps {}
39+
40+
interface InnerProps {}
41+
42+
interface RowProps {}
43+
44+
const Wrapper = styled.div<WrapperProps>`
45+
width: 100%;
46+
text-align: center;
47+
max-width: 1450px;
48+
margin: 0 auto;
49+
@media (min-width: 768px) {
50+
padding: 30px;
51+
text-align: left;
52+
}
53+
`;
54+
55+
const Inner = styled.div<InnerProps>`
56+
background-color: #f3f6f4;
57+
background-image: url(/images/stakingGraphic.svg);
58+
background-repeat: no-repeat;
59+
background-position-x: right;
60+
background-position-y: center;
61+
@media (min-width: 768px) {
62+
padding: 30px;
63+
}
64+
`;
65+
66+
const Row = styled.div<RowProps>`
67+
max-width: 1152px;
68+
margin: 0 auto;
69+
display: flex;
70+
justify-content: space-between;
71+
align-items: center;
72+
flex-direction: column;
73+
@media (min-width: 768px) {
74+
flex-direction: row;
75+
& > * {
76+
}
77+
}
78+
`;
79+
80+
const Column = styled.div`
81+
padding: 30px;
82+
@media (min-width: 768px) {
83+
padding: 60px 28px;
84+
&:first-child {
85+
padding-left: 0;
86+
}
87+
&:last-child {
88+
padding-right: 0;
89+
}
90+
}
91+
`;
92+
93+
const Title = styled.h1`
94+
font-size: 46px;
95+
line-height: 1.2;
96+
font-weight: 300;
97+
margin-bottom: 20px;
98+
display: none;
99+
@media (min-width: 768px) {
100+
font-size: 50px;
101+
display: block;
102+
}
103+
`;
104+
105+
const TitleMobile = styled(Title)`
106+
display: block;
107+
@media (min-width: 768px) {
108+
display: none;
109+
}
110+
`;
111+
112+
const Description = styled.h2`
113+
font-size: 18px;
114+
line-height: 1.45;
115+
font-weight: 300;
116+
margin-bottom: 30px;
117+
color: ${colors.textDarkSecondary};
118+
`;
119+
120+
const Actions = styled.div`
121+
display: flex;
122+
flex-direction: column;
123+
& > * {
124+
margin-right: 13px;
125+
margin-bottom: 10px;
126+
}
127+
@media (min-width: 768px) {
128+
flex-direction: row;
129+
}
130+
`;
131+
132+
const MetricsWrapper = styled.div`
133+
display: flex;
134+
flex-direction: column;
135+
`;
136+
137+
const FiguresList = styled.ol`
138+
display: flex;
139+
flex-direction: column;
140+
flex-wrap: wrap;
141+
padding-top: 15px;
142+
`;
143+
144+
const Figure = styled.li`
145+
display: flex;
146+
flex-direction: column;
147+
justify-content: space-between;
148+
text-align: left;
149+
padding: 10px;
150+
margin-bottom: 15px;
151+
max-width: 50%;
152+
@media (min-width: 480px) {
153+
padding: 20px;
154+
}
155+
`;
156+
157+
const FigurePair = styled.div`
158+
display: flex;
159+
justify-content: space-between;
160+
`;
161+
const FigureHeader = styled.header`
162+
display: flex;
163+
justify-content: space-between;
164+
align-items: baseline;
165+
`;
166+
167+
const FigureTitle = styled.span`
168+
display: block;
169+
font-size: 16px;
170+
line-height: 1.35;
171+
margin-bottom: 5px;
172+
`;
173+
174+
const FigureNumber = styled.span`
175+
display: block;
176+
font-feature-settings: 'tnum' on, 'lnum' on;
177+
font-size: 20px;
178+
line-height: 1.35;
179+
@media (min-width: 768px) {
180+
font-size: 34px;
181+
}
182+
@media (min-width: 991px) {
183+
font-size: 44px;
184+
}
185+
`;
186+
187+
export const GovernanceHero: React.FC<GovernanceHeroProps> = (props) => {
188+
const { title, titleMobile, description, actions, numProposals, averageVotingPower } = props;
189+
const providerState = useSelector((state: State) => state.providerState);
190+
191+
const [totalTreasuryAmountUSD, setTotalTreasuryAmountUSD] = React.useState('-');
192+
const [totalTreasuryDistributedUSD, setTotalTreasuryDistributedUSD] = React.useState('-');
193+
194+
const parseTotalDistributed = (transferData: any) => {
195+
let totalDistributed = 0;
196+
if (transferData) {
197+
transferData.forEach((tf: any) => {
198+
if (tf.data.items) {
199+
tf.data.items.forEach((item: any) => {
200+
item.transfers.forEach((transfer: any) => {
201+
if (transfer.transfer_type === 'OUT') {
202+
const delta_quote =
203+
parseInt(transfer.delta, 10) *
204+
Math.pow(10, -transfer.contract_decimals) *
205+
transfer.quote_rate;
206+
207+
totalDistributed += delta_quote;
208+
}
209+
});
210+
});
211+
}
212+
});
213+
}
214+
215+
return totalDistributed;
216+
};
217+
218+
React.useEffect(() => {
219+
const zrxTokenContract = new ERC20TokenContract(
220+
'0xe41d2489571d322189246dafa5ebde1f4699f498',
221+
providerState.provider,
222+
);
223+
const maticTokenContract = new ERC20TokenContract(
224+
'0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0',
225+
providerState.provider,
226+
);
227+
228+
// tslint:disable-next-line:no-floating-promises
229+
(async () => {
230+
const [zrxBalance, maticBalance] = await Promise.all([
231+
zrxTokenContract.balanceOf(GOVERNOR_CONTRACT_ADDRESS.ZRX).callAsync(),
232+
maticTokenContract.balanceOf(GOVERNOR_CONTRACT_ADDRESS.ZRX).callAsync(),
233+
]);
234+
const res = await backendClient.getTreasuryTokenPricesAsync();
235+
const zrxAmount = Web3Wrapper.toUnitAmount(zrxBalance, 18);
236+
const maticAmount = Web3Wrapper.toUnitAmount(maticBalance, 18);
237+
const zrxUSD = zrxAmount.multipliedBy(res['0x'].usd);
238+
const maticUSD = maticAmount.multipliedBy(res['matic-network'].usd);
239+
240+
const treasuryTokenTransferData = await backendClient.getTreasuryTokenTransfersAsync();
241+
const totalDistributed = parseTotalDistributed(treasuryTokenTransferData);
242+
setTotalTreasuryDistributedUSD(
243+
`$${
244+
formatNumber(totalDistributed, {
245+
decimals: 6,
246+
decimalsRounded: 6,
247+
bigUnitPostfix: true,
248+
}).formatted
249+
}`,
250+
);
251+
setTotalTreasuryAmountUSD(
252+
`$${
253+
formatNumber(zrxUSD.plus(maticUSD).toString(), {
254+
decimals: 6,
255+
decimalsRounded: 6,
256+
bigUnitPostfix: true,
257+
}).formatted
258+
}`,
259+
);
260+
})();
261+
}, [providerState]);
262+
263+
const averageVotingPowerFormatted = averageVotingPower
264+
? formatNumber(averageVotingPower, {
265+
decimals: 6,
266+
decimalsRounded: 6,
267+
bigUnitPostfix: true,
268+
}).formatted
269+
: '-';
270+
return (
271+
<Wrapper>
272+
<Inner>
273+
<Row>
274+
<Column>
275+
<Title>{title}</Title>
276+
<TitleMobile>{titleMobile}</TitleMobile>
277+
<Description>{description}</Description>
278+
<Actions>{actions}</Actions>
279+
</Column>
280+
<Column>
281+
<MetricsWrapper>
282+
{/* <FiguresListHeader>Treasury Stats</FiguresListHeader> */}
283+
<FiguresList>
284+
<FigurePair>
285+
<Figure key={1}>
286+
<FigureHeader>
287+
<FigureTitle>Available Treasury</FigureTitle>
288+
</FigureHeader>
289+
<FigureNumber>{totalTreasuryAmountUSD}</FigureNumber>
290+
</Figure>
291+
<Figure key={2}>
292+
<FigureHeader>
293+
<FigureTitle>Total Distributed</FigureTitle>
294+
</FigureHeader>
295+
<FigureNumber>{totalTreasuryDistributedUSD}</FigureNumber>
296+
</Figure>
297+
</FigurePair>
298+
299+
<FigurePair>
300+
<Figure key={3}>
301+
<FigureHeader>
302+
<FigureTitle>Votes Passed</FigureTitle>
303+
</FigureHeader>
304+
<FigureNumber>{numProposals || 0}</FigureNumber>
305+
</Figure>
306+
<Figure key={4} style={{}}>
307+
<FigureHeader>
308+
<FigureTitle>Avg. ZRX Voted Per Proposal</FigureTitle>
309+
</FigureHeader>
310+
<FigureNumber>{averageVotingPowerFormatted}</FigureNumber>
311+
</Figure>
312+
</FigurePair>
313+
{/* <ProgressbarText>Treasury Details</ProgressbarText> */}
314+
</FiguresList>
315+
</MetricsWrapper>
316+
</Column>
317+
</Row>
318+
</Inner>
319+
</Wrapper>
320+
);
321+
};
322+
323+
GovernanceHero.defaultProps = {
324+
videoChannel: 'youtube',
325+
videoRatio: '21:9',
326+
};

0 commit comments

Comments
 (0)