aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHsuan Lee <boczeratul@gmail.com>2019-04-08 22:18:34 +0800
committerHsuan Lee <boczeratul@gmail.com>2019-04-08 22:18:34 +0800
commitb9c0c169ce805124cb6b3fb84c7db8df9a76151e (patch)
tree88d4b5a09267a9cc9e4d56ccadeebe588dc36284
parent336162ac78ad3d5c787c5ecfe735b98d423c4053 (diff)
downloaddexon-lottery-b9c0c169ce805124cb6b3fb84c7db8df9a76151e.tar.gz
dexon-lottery-b9c0c169ce805124cb6b3fb84c7db8df9a76151e.tar.zst
dexon-lottery-b9c0c169ce805124cb6b3fb84c7db8df9a76151e.zip
Complete webapp
-rw-r--r--app/app.js12
-rw-r--r--app/components/Button/index.js43
-rw-r--r--app/components/Input/__tests__/__snapshots__/index.test.js.snap10
-rw-r--r--app/components/Input/__tests__/index.test.js11
-rw-r--r--app/components/Input/index.js195
-rw-r--r--app/components/Mux/index.js21
-rw-r--r--app/constants/colors.js2
-rw-r--r--app/containers/App/Console.js65
-rw-r--r--app/containers/App/LotteryItem.js52
-rw-r--r--app/containers/App/Timer.js44
-rw-r--r--app/containers/App/__tests__/index.test.js24
-rw-r--r--app/containers/App/index.js14
-rw-r--r--app/containers/MainHome/Loadable.js11
-rw-r--r--app/containers/MainHome/components/MainHome.js309
-rw-r--r--app/containers/MainHome/index.js3
-rw-r--r--app/fonts.css17
-rw-r--r--app/global-styles.js10
-rw-r--r--app/index.html2
-rw-r--r--app/services/Lottery/constants.js2
-rw-r--r--app/services/Lottery/index.js8
-rw-r--r--internals/webpack/webpack.dev.babel.js1
-rw-r--r--package.json3
-rw-r--r--runTimer.js5
-rw-r--r--yarn.lock17
24 files changed, 220 insertions, 661 deletions
diff --git a/app/app.js b/app/app.js
index 6f33417..1dc7602 100644
--- a/app/app.js
+++ b/app/app.js
@@ -26,7 +26,7 @@ import './global-styles';
// Observe loading of Overpass (to remove Overpass, remove the <link> tag in
// the index.html file and this observer)
-const overpassObserver = new FontFaceObserver('Overpass', {});
+const overpassObserver = new FontFaceObserver('Overpass Mono', {});
// When Overpass is loaded, add a font-family using Overpass to the body
overpassObserver.load().then(() => {
@@ -43,14 +43,4 @@ const render = () => {
);
};
-if (module.hot) {
- // Hot reloadable React components and translation json files
- // modules.hot.accept does not accept dynamic dependencies,
- // have to be constants at compile-time
- module.hot.accept(['containers/App'], () => {
- ReactDOM.unmountComponentAtNode(MOUNT_NODE);
- render();
- });
-}
-
render();
diff --git a/app/components/Button/index.js b/app/components/Button/index.js
deleted file mode 100644
index 79083e4..0000000
--- a/app/components/Button/index.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- *
- * Button.js
- *
- * A common button, if you pass it a prop "route" it'll render a link to a react-router route
- * otherwise it'll render a link with an onclick
- */
-
-import React from 'react';
-import styled from 'styled-components';
-import { clickableStyle } from '@/utils/styles';
-
-const StyledButton = styled.button`
- position: relative;
- padding: 10px 20px;
- border-radius: 3px;
- user-select: none;
- font-size: 12px;
- outline: 0;
- border: 1px solid #5E6C75;
- color: #122028;
-
- ${clickableStyle}
-`;
-
-type ButtonProps = {
- className: String,
- onClick: Function,
- children: any,
- isDisabled: Boolean,
-};
-
-const Button = ({ className, onClick, children, isDisabled }: ButtonProps) => (
- <StyledButton
- isDisabled={isDisabled}
- className={className}
- onClick={onClick}
- >
- {children}
- </StyledButton>
-);
-
-export default Button;
diff --git a/app/components/Input/__tests__/__snapshots__/index.test.js.snap b/app/components/Input/__tests__/__snapshots__/index.test.js.snap
deleted file mode 100644
index bb1c9d9..0000000
--- a/app/components/Input/__tests__/__snapshots__/index.test.js.snap
+++ /dev/null
@@ -1,10 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`<Input /> should match snapshot 1`] = `
-<styled.div>
- <Styled(SVG)
- src="IMAGE_MOCK"
- />
- <styled.input />
-</styled.div>
-`;
diff --git a/app/components/Input/__tests__/index.test.js b/app/components/Input/__tests__/index.test.js
deleted file mode 100644
index 933a024..0000000
--- a/app/components/Input/__tests__/index.test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-
-import Input from '../index';
-
-describe('<Input />', () => {
- it('should match snapshot', () => {
- const renderedComponent = shallow(<Input />);
- expect(renderedComponent).toMatchSnapshot();
- });
-});
diff --git a/app/components/Input/index.js b/app/components/Input/index.js
deleted file mode 100644
index de16416..0000000
--- a/app/components/Input/index.js
+++ /dev/null
@@ -1,195 +0,0 @@
-import React, { PureComponent } from 'react';
-import styled from 'styled-components';
-import { timingFunctions } from 'polished';
-import noop from 'lodash/noop';
-
-const getBorderColor = (props) => {
- if (props.hasError) {
- return '#FF435A!important';
- }
-
- if (props.hasWarning) {
- return '#F69355!important';
- }
-
- if (props.hasFocus) {
- return '#37454E!important';
- }
-
- return '#AAB9C2';
-};
-
-const Wrapper = styled.div`
- position: relative;
- width: 100%;
- border: 1px solid ${getBorderColor};
- border-radius: 3px;
- transition: .2s border-color;
-`;
-
-const InputComponent = styled.input`
- font-family: 'Overpass', 'Helvetica Neue', Helvetica, Arial, sans-serif;
- font-size: 20px;
- text-overflow: ellipsis;
- color: #122028;
- background: ${props => (props.readOnly ? '#F8F8F8' : 'transparent')};
- padding: 10px 12px;
- padding-right: ${props => (props.hasUnit ? 112 : 12)}px;
- width: 100%;
- height: 100%;
- border-radius: 3px;
- display: block;
-
- &:focus {
- outline: none;
- }
-
- &::placeholder {
- color: #122028;
- }
-`;
-
-const TextArea = InputComponent.withComponent('textarea').extend`
- min-height: ${props => props.height || 82}px;
- height: ${props => props.height || 82}px;
- white-space: ${props => props.whiteSpace || 'initial'};
-`;
-
-const TooltipBox = styled.ul`
- position: absolute;
- top: calc(100% + 5px);
- left: 3px;
- z-index: 1;
- background-color: #FFFFFF;
- border-radius: 4px;
- padding: ${props => (props.hasContent ? '4px 10px' : 0)};
- box-shadow: 0 1px 3px 0px rgba(0, 0, 0, 0.5);
- pointer-events: none;
- opacity: ${props => (props.isActive && props.hasContent ? 1 : 0)};
- transform: ${props => (props.isActive && props.hasContent ? 'none' : 'translateY(10px)')};
- transition:
- .2s opacity ${timingFunctions('easeInOutQuad')},
- .2s transform ${timingFunctions('easeInOutQuad')}
- ;
-`;
-
-const Error = styled.li`
- color: #FF435A;
-`;
-
-const Warning = styled.li`
- color: #F69355;
-`;
-
-class Input extends PureComponent {
- props: {
- className: String,
- unit: String,
- isOptional: Boolean,
- isMultiline: Boolean,
- disabled: Boolean,
- validators: Array<Function>,
- onChange: Function,
- onError: Function,
- value: String,
- };
-
- static defaultProps = {
- validators: [],
- onChange: noop,
- onError: noop,
- };
-
- state = {
- hasFocus: false,
- errors: [],
- warnings: [],
- };
-
- componentDidUpdate(prevProps) {
- if (prevProps.value !== this.props.value) {
- this.handleValidation(this.props);
- }
- }
-
- handleFocus = () => this.setState({ hasFocus: true });
- handleBlur = () => this.setState({ hasFocus: false });
-
- handleChange = (event) => {
- const { onChange } = this.props;
- const { target: { name, value } } = event;
-
- onChange(event);
- this.handleValidation({ name, value });
- }
-
- handleValidation = ({ name, value }) => {
- const { onError, validators } = this.props;
-
- const errors = [];
- const warnings = [];
-
- if (value) {
- validators.forEach(({ test, message, isWarning }) => {
- if (!test(value)) {
- if (isWarning) {
- warnings.push(message);
- } else {
- errors.push(message);
- }
- }
- });
- }
- this.setState({ errors, warnings }, () => {
- onError({
- name,
- hasError: Boolean(this.state.errors.length),
- });
- });
- }
-
- render() {
- const { className, unit, onChange, isOptional, isMultiline, ...props } = this.props;
- const { hasFocus, errors, warnings } = this.state;
- const hasError = errors.length;
- const hasWarning = warnings.length;
- const Component = isMultiline ? TextArea : InputComponent;
-
- return (
- <Wrapper
- className={className}
- hasFocus={hasFocus}
- hasError={hasError}
- hasWarning={hasWarning}
- isOptional={isOptional}
- >
- <Component
- {...props}
- hasUnit={Boolean(unit)}
- onChange={this.handleChange}
- onFocus={this.handleFocus}
- onBlur={this.handleBlur}
- />
-
- <TooltipBox
- isActive={hasFocus}
- hasContent={hasError || hasWarning}
- >
- {errors.map((error, index) => (
- <Error key={index}>
- {error}
- </Error>
- ))}
-
- {warnings.map((warning, index) => (
- <Warning key={index}>
- {warning}
- </Warning>
- ))}
- </TooltipBox>
- </Wrapper>
- );
- }
-}
-
-export default Input;
diff --git a/app/components/Mux/index.js b/app/components/Mux/index.js
new file mode 100644
index 0000000..708a09c
--- /dev/null
+++ b/app/components/Mux/index.js
@@ -0,0 +1,21 @@
+import styled from 'styled-components';
+
+export const Container = styled.div`
+ margin: 5px 15px;
+ margin-top: 20px;
+ padding: 15px 20px;
+ border: 1px solid #4d4d4d;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+`;
+
+export const Header = styled.div`
+ position: absolute;
+ top: -12px;
+ left: 10px;
+ color: #8d8d8d;
+ background: black;
+ padding: 0 10px;
+ font-weight: 700;
+`;
diff --git a/app/constants/colors.js b/app/constants/colors.js
index 80e48dc..b2df732 100644
--- a/app/constants/colors.js
+++ b/app/constants/colors.js
@@ -1,5 +1,5 @@
export const COLOR_WHITE = '#FFFFFF';
-export const COLOR_BLACK = '#122028';
+export const COLOR_BLACK = '#000000';
export const COLOR_LIGHT_BLACK = '#0E1519';
export const COLOR_LIGHTER_BLACK = '#26343C';
export const COLOR_GRAY = '#AAB9C2';
diff --git a/app/containers/App/Console.js b/app/containers/App/Console.js
new file mode 100644
index 0000000..ba8f6fc
--- /dev/null
+++ b/app/containers/App/Console.js
@@ -0,0 +1,65 @@
+import React, { PureComponent } from 'react';
+import styled from 'styled-components';
+import { Container, Header } from '@/components/Mux';
+import LotteryContract from '@/services/Lottery';
+import LotteryItem from './LotteryItem';
+
+const StretchedContainer = styled(Container)`
+ flex: 1 1 auto;
+`;
+
+const Body = styled.div`
+ overflow: auto;
+ position: absolute;
+ height: calc(100% - 30px);
+ width: calc(100% - 40px);
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+`;
+
+// eslint-disable-next-line react/prefer-stateless-function
+class Console extends PureComponent {
+ state = {
+ list: [],
+ };
+
+ componentDidMount() {
+ this.updateList();
+ setInterval(this.updateList, 10000);
+ }
+
+ updateList = () => {
+ LotteryContract.getPastEvents('NumberRevealed', {
+ fromBlock: 0,
+ toBlock: 'latest',
+ })
+ .then(events => this.setState({ list: events }));
+ }
+
+ render() {
+ const { list } = this.state;
+
+ return (
+ <StretchedContainer>
+ <Header>
+ Lottery History
+ </Header>
+
+ <Body>
+ {list.map(event => (
+ <LotteryItem
+ key={event.transactionHash}
+ hash={event.transactionHash}
+ timestamp={event.returnValues[0]}
+ number={`00${event.returnValues[1]}`.slice(-3)}
+ rawValue={event.returnValues[2]}
+ />
+ ))}
+ </Body>
+ </StretchedContainer>
+ );
+ }
+}
+
+export default Console;
diff --git a/app/containers/App/LotteryItem.js b/app/containers/App/LotteryItem.js
new file mode 100644
index 0000000..619b842
--- /dev/null
+++ b/app/containers/App/LotteryItem.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import styled, { keyframes } from 'styled-components';
+import moment from 'moment';
+
+const blink = keyframes`
+ from, to {
+ color: transparent;
+ }
+
+ 50% {
+ color: white;
+ }
+`;
+
+const Marker = styled.span`
+ animation: ${blink} 1s step-end infinite;
+ display: none;
+`;
+
+const Item = styled.a`
+ margin-top: 20px;
+ display: flex;
+ align-items: flex-end;
+ white-space: pre;
+ cursor: pointer;
+
+ &:last-child ${Marker} {
+ display: block;
+ }
+
+ &:hover {
+ background: #222222;
+ }
+`;
+
+const Gray = styled.span`
+ color: #8d8d8d;
+ display: contents;
+`;
+
+const LotteryItem = ({ timestamp, hash, number }: { timestamp: String, hash: String, number: String }) => (
+ <Item
+ target="_blank"
+ href={`https://testnet.dexscan.app/transaction/${hash}`}
+ >
+ <Gray>{'Time: '}</Gray>{moment(timestamp * 1000).format('MMM Do, LTS ZZ')}<br />
+ <Gray>{'Number: '}</Gray>{number}<br />
+ <Gray>{'TxHash: '}</Gray>{hash}<Marker>_</Marker>
+ </Item>
+);
+
+export default LotteryItem;
diff --git a/app/containers/App/Timer.js b/app/containers/App/Timer.js
new file mode 100644
index 0000000..a164cd1
--- /dev/null
+++ b/app/containers/App/Timer.js
@@ -0,0 +1,44 @@
+
+import React, { PureComponent } from 'react';
+import styled from 'styled-components';
+import moment from 'moment';
+
+import { Container, Header } from '@/components/Mux';
+
+const LAUNCH_TIME = 1556164800000;
+const Time = styled.div`
+ font-size: 72px;
+`;
+const pad = number => `0${number}`.slice(-2);
+
+class Timer extends PureComponent {
+ state = {
+ duration: LAUNCH_TIME - Date.now(),
+ };
+
+ componentDidMount() {
+ setInterval(this.updateTime, 1000);
+ }
+
+ updateTime = () => {
+ this.setState({ duration: LAUNCH_TIME - Date.now() });
+ }
+
+ render() {
+ const duration = moment.duration(this.state.duration);
+
+ return (
+ <Container>
+ <Header>
+ Time Until DEXON Mainnet Launch
+ </Header>
+
+ <Time>
+ {(duration.days() * 24) + duration.hours()}:{pad(duration.minutes())}:{pad(duration.seconds())}
+ </Time>
+ </Container>
+ );
+ }
+}
+
+export default Timer;
diff --git a/app/containers/App/__tests__/index.test.js b/app/containers/App/__tests__/index.test.js
deleted file mode 100644
index 33a48c9..0000000
--- a/app/containers/App/__tests__/index.test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-import { Route } from 'react-router-dom';
-
-import Header from 'components/Header';
-import Footer from 'components/Footer';
-import App from '../index';
-
-describe('<App />', () => {
- it('should render the header', () => {
- const renderedComponent = shallow(<App />);
- expect(renderedComponent.find(Header).length).toBe(1);
- });
-
- it('should render some routes', () => {
- const renderedComponent = shallow(<App />);
- expect(renderedComponent.find(Route).length).not.toBe(0);
- });
-
- it('should render the footer', () => {
- const renderedComponent = shallow(<App />);
- expect(renderedComponent.find(Footer).length).toBe(1);
- });
-});
diff --git a/app/containers/App/index.js b/app/containers/App/index.js
index 0e4f3b1..3922807 100644
--- a/app/containers/App/index.js
+++ b/app/containers/App/index.js
@@ -9,17 +9,25 @@
import React from 'react';
import styled from 'styled-components';
-import MainHome from '@/containers/MainHome/Loadable';
+import Console from './Console';
+import Timer from './Timer';
const AppWrapper = styled.div`
+ max-width: 830px;
+ width: 100%;
+ height: 100vh;
+ margin: 0 auto;
+ padding: 10px 0;
+
display: flex;
flex-direction: column;
- min-height: 100vh;
`;
const App = () => (
<AppWrapper>
- <MainHome />
+ <Console />
+
+ <Timer />
</AppWrapper>
);
diff --git a/app/containers/MainHome/Loadable.js b/app/containers/MainHome/Loadable.js
deleted file mode 100644
index 004bec9..0000000
--- a/app/containers/MainHome/Loadable.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Asynchronously loads the component for MainHome
- */
-import Loadable from 'react-loadable';
-
-import LoadingIndicator from '@/components/LoadingIndicator';
-
-export default Loadable({
- loader: () => import('./index'),
- loading: LoadingIndicator,
-});
diff --git a/app/containers/MainHome/components/MainHome.js b/app/containers/MainHome/components/MainHome.js
deleted file mode 100644
index fe6b0d1..0000000
--- a/app/containers/MainHome/components/MainHome.js
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * MainHome
- *
- * List all the features
- */
-import React, { PureComponent } from 'react';
-import styled, { css } from 'styled-components';
-import {
- generateMnemonic,
- validateMnemonic,
- mnemonicToSeed,
-} from 'bip39';
-import hdkey from 'ethereumjs-wallet/hdkey';
-import { pubToAddress, toChecksumAddress } from 'ethereumjs-util';
-
-import Input from '@/components/Input';
-import Button from '@/components/Button';
-
-const Wrapper = styled.main`
- max-width: 830px;
- width: 100%;
- margin: 0 auto;
- padding: 60px 15px;
-
- display: flex;
- align-items: flex-start;
- flex-direction: column;
-`;
-
-const Logo = styled.div`
- width: 45px;
- height: 80px;
- margin: 0 auto;
- border-top: 40px solid black;
- border-bottom: 40px solid black;
- border-left: 22.49px solid white;
- border-right: 22.49px solid white;
-`;
-
-const Step = styled.div`
- margin-top: 30px;
- width: 100%;
-`;
-
-const StepNumber = styled.div`
- font-size: 20px;
- font-weight: 700;
- color: #5E6C75;
-`;
-
-const StepTitle = styled.h1`
- margin-top: 30px;
- margin-bottom: 15px;
- font-size: 36px;
- font-weight: 700;
-`;
-
-const ButtonGroup = styled.div`
- width: 100%;
- height: 44px;
- display: flex;
- margin-top: 15px;
-`;
-
-const activeStyle = css`
- border-color: #954a97;
- background-color: rgba(126, 121, 146, 0.1);
-`;
-
-const dimStyle = css`
- color: #d8d8d8;
- border-color: #d8d8d8;
-`;
-
-const StyledButton = styled(Button)`
- height: 100%;
- font-size: 16px;
- flex: 1 0 50px;
- transition: .2s color, .2s background-color, .2s border-color;
-
- &:not(:first-child) {
- margin-left: 10px;
- }
-
- ${props => props.isActive && activeStyle};
- ${props => props.isDim && dimStyle};
-`;
-
-const StyledInput = styled(Input)`
- max-width: 800px;
- margin: 20px 0;
-`;
-
-const Hint = styled.p`
- color: #5E6C75;
- font-size: 16px;
-`;
-
-const Warning = Hint.extend`
- color: #FF435A;
-`;
-
-const UlHead = Hint.extend`
- margin-bottom: 0;
- font-weight: 700;
-`;
-
-const Ul = styled.ul`
- margin-top: 0;
- color: #5E6C75;
-`;
-
-const mnemonicValidators = [
- {
- test: input => validateMnemonic(input),
- message: 'Invalid mnemonic phrases',
- },
- {
- test: input => input.split(' ').length === 24,
- message: 'Should be 24 words in total',
- },
- {
- test: input => /^[a-z\s]*$/.test(input),
- message: 'Words are separated by single space',
- },
-];
-
-// eslint-disable-next-line react/prefer-stateless-function
-class MainHome extends PureComponent {
- state = {
- hasLedger: 'unknown',
- mnemonic: '',
- step2Confirmed: false,
- hdWallet: null,
- address: '',
- };
-
- handleSelect = hasLedger =>
- this.setState({
- hasLedger,
- step2Confirmed: false,
- mnemonic: hasLedger === 'yes' ? '' : generateMnemonic(256),
- address: '',
- }, this.handleProcessMnemonic);
-
- handleMnemonicChange = event =>
- this.setState({
- mnemonic: event.target.value,
- step2Confirmed: validateMnemonic(event.target.value),
- }, this.handleProcessMnemonic);
-
- handleConfirmStep2 = () =>
- this.setState({
- step2Confirmed: true,
- }, () => window.scrollTo(0, document.body.scrollHeight));
-
- handleProcessMnemonic = () => {
- const { mnemonic } = this.state;
-
- if (!validateMnemonic(mnemonic)) {
- return;
- }
-
- const seed = mnemonicToSeed(mnemonic);
- const hdWallet = hdkey.fromMasterSeed(seed);
- const key = hdWallet.derivePath('m/44\'/237\'/0\'/0/0');
- const addressInt = pubToAddress(key._hdkey._publicKey, true); // eslint-disable-line no-underscore-dangle
- const address = toChecksumAddress(addressInt.toString('hex'));
-
- this.setState({
- address,
- }, () => window.scrollTo(0, document.body.scrollHeight));
- }
-
- render() {
- const { hasLedger, mnemonic, step2Confirmed, address } = this.state;
-
- return (
- <Wrapper>
- <Logo />
-
- <Step>
- <StepTitle>
- <StepNumber>Step 1</StepNumber>
- Do you have a Ledger wallet already?
- </StepTitle>
-
- <ButtonGroup>
- <StyledButton
- isSecondary
- isActive={hasLedger === 'yes'}
- isDim={hasLedger === 'no'}
- onClick={() => this.handleSelect('yes')}
- >
- Yes
- </StyledButton>
-
- <StyledButton
- isSecondary
- isActive={hasLedger === 'no'}
- isDim={hasLedger === 'yes'}
- onClick={() => this.handleSelect('no')}
- >
- No
- </StyledButton>
- </ButtonGroup>
- </Step>
-
- {hasLedger === 'yes' && <Step>
- <StepTitle>
- <StepNumber>Step 2</StepNumber>
- Fill in your Ledger recovery phrases
- </StepTitle>
-
- <StyledInput
- isMultiline
- isOptional
- value={mnemonic}
- validators={mnemonicValidators}
- placeholder="Input your 24 recovery phrases separated by single space."
- onChange={this.handleMnemonicChange}
- />
-
- <Warning>
- <b>WARNING: DO NOT do this on a public computer.</b>
- <br />
- If anyone gets your recovery phrases, they will have FULL ACCESS to your accounts.
- </Warning>
- </Step>}
-
- {hasLedger === 'no' && <Step>
- <StepTitle>
- <StepNumber>Step 2</StepNumber>
- Backup your Ledger recovery phrases
- </StepTitle>
-
- <StyledInput
- isMultiline
- isOptional
- readOnly
- value={mnemonic}
- />
-
- <Hint>
- These 24 randomly generated recovery phrases are the keys to your accounts.
- <br />
- You must <b>keep them safe</b>.
- </Hint>
-
- <Warning>
- <b>WARNING 1: DO NOT disclose these phrases to anyone, including anyone from DEXON Foundation.</b>
- <br />
- If anyone gets your recovery phrases, they will have FULL ACCESS to your accounts.
- </Warning>
-
- <Warning>
- <b>WARNING 2: DO NOT lose these phrases.</b>
- <br />
- If you lose them, NOBODY, not even DEXON Foundation, can regain access to your accounts.
- </Warning>
-
- <UlHead>You SHOULD either:</UlHead>
- <Ul>
- <li>Write them down on a piece of paper, or</li>
- <li>Store them encrypted in your computer.</li>
- </Ul>
-
- <UlHead>You SHOULD NOT:</UlHead>
- <Ul>
- <li>Send them through email or online messengers, or</li>
- <li>Store them online, or</li>
- <li>Access them on a public computer.</li>
- </Ul>
-
- <ButtonGroup>
- <StyledButton
- isSecondary
- isActive={step2Confirmed}
- onClick={this.handleConfirmStep2}
- >
- I have safely stored my recovery phrases
- </StyledButton>
- </ButtonGroup>
- </Step>}
-
- {step2Confirmed && <Step>
- <StepTitle>
- <StepNumber>Final Step</StepNumber>
- Send your account address to DEXON Foundation
- </StepTitle>
-
- <StyledInput
- isMultiline
- isOptional
- readOnly
- height={52}
- value={address}
- />
-
- <Hint>
- No worries. You can tell whoever you like about your account address. There is no security risk in doing so.
- </Hint>
- </Step>}
- </Wrapper>
- );
- }
-}
-
-export default MainHome;
diff --git a/app/containers/MainHome/index.js b/app/containers/MainHome/index.js
deleted file mode 100644
index 42a94b1..0000000
--- a/app/containers/MainHome/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import MainHome from './components/MainHome';
-
-export default MainHome;
diff --git a/app/fonts.css b/app/fonts.css
deleted file mode 100644
index 7970551..0000000
--- a/app/fonts.css
+++ /dev/null
@@ -1,17 +0,0 @@
-/* latin */
-@font-face {
- font-family: 'Overpass';
- font-style: normal;
- font-weight: 400;
- src: local("Overpass Regular"), local("Overpass-Regular"), url(./overpass-400.woff2) format("woff2");
- unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
-
-/* latin */
-@font-face {
- font-family: 'Overpass';
- font-style: normal;
- font-weight: 700;
- src: local("Overpass Bold"), local("Overpass-Bold"), url(./overpass-700.woff2) format("woff2");
- unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
diff --git a/app/global-styles.js b/app/global-styles.js
index 1b56895..ab1b54a 100644
--- a/app/global-styles.js
+++ b/app/global-styles.js
@@ -1,5 +1,4 @@
import { injectGlobal } from 'styled-components';
-import { COLOR_WHITE, COLOR_BLUE } from '@/constants/colors';
/* eslint no-unused-expressions: 0 */
injectGlobal`
@@ -13,11 +12,12 @@ injectGlobal`
}
body.fontLoaded {
- font-family: 'Overpass', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: 'Overpass Mono', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
#app {
- background-color: ${COLOR_WHITE};
+ color: white;
+ background-color: black;
min-height: 100%;
min-width: 100%;
}
@@ -27,10 +27,6 @@ injectGlobal`
color: inherit;
}
- a:hover {
- color: ${COLOR_BLUE};
- }
-
ul, ol {
margin-block-start: 0;
margin-block-end: 0;
diff --git a/app/index.html b/app/index.html
index d7dc8ca..ac2af62 100644
--- a/app/index.html
+++ b/app/index.html
@@ -21,7 +21,7 @@
<div id="app"></div>
<!-- Overpass Font -->
- <link href="https://fonts.googleapis.com/css?family=Overpass:400,700|Roboto+Condensed:400,700" rel="stylesheet">
+ <link href="https://fonts.googleapis.com/css?family=Overpass+Mono:400,700" rel="stylesheet">
<!-- A lot of magic happens in this file. HtmlWebpackPlugin automatically includes all assets (e.g. bundle.js, main.css) with the correct HTML tags, which is why they are missing in this HTML file. Don't add any assets here! (Check out the webpack config files in internals/webpack for details) -->
</body>
</html>
diff --git a/app/services/Lottery/constants.js b/app/services/Lottery/constants.js
new file mode 100644
index 0000000..dd6062a
--- /dev/null
+++ b/app/services/Lottery/constants.js
@@ -0,0 +1,2 @@
+export const DEXON_TESTNET = 'https://testnet-rpc.dexon.org';
+export const LOTTERY_ADDRESS = '0xAE64Df55807E2B9a58A124AB7d852EeBCAEb7CB9';
diff --git a/app/services/Lottery/index.js b/app/services/Lottery/index.js
new file mode 100644
index 0000000..4244122
--- /dev/null
+++ b/app/services/Lottery/index.js
@@ -0,0 +1,8 @@
+import Web3 from '@cobinhood/web3';
+import { DEXON_TESTNET, LOTTERY_ADDRESS } from './constants';
+import { abi } from '../../../build/contracts/Lottery.json';
+
+const web3 = new Web3(new Web3.providers.HttpProvider(DEXON_TESTNET));
+const lotteryContract = new web3.eth.Contract(abi, LOTTERY_ADDRESS);
+
+export default lotteryContract;
diff --git a/internals/webpack/webpack.dev.babel.js b/internals/webpack/webpack.dev.babel.js
index 4d4b61e..69a2f00 100644
--- a/internals/webpack/webpack.dev.babel.js
+++ b/internals/webpack/webpack.dev.babel.js
@@ -42,7 +42,6 @@ module.exports = require('./webpack.base.babel')({
// Add hot reloading in development
entry: [
'eventsource-polyfill', // Necessary for hot reloading with IE
- 'webpack-hot-middleware/client?reload=true',
path.join(process.cwd(), 'app/app.js'), // Start with js/app.js
],
diff --git a/package.json b/package.json
index fb69769..39c4966 100644
--- a/package.json
+++ b/package.json
@@ -60,9 +60,11 @@
"eventsource-polyfill": "^0.9.6",
"file-loader": "1.1.11",
"fontfaceobserver": "2.0.13",
+ "glob": "^7.1.3",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"husky": "^1.3.1",
+ "moment": "^2.24.0",
"openzeppelin-solidity": "^2.1.3",
"polished": "^3.0.3",
"prop-types": "^15.6.1",
@@ -77,7 +79,6 @@
"truffle-hdwallet-provider": "^1.0.1",
"webpack": "^4.29.6",
"webpack-dev-server": "^3.2.1",
- "webpack-hot-middleware": "^2.24.3",
"whatwg-fetch": "^3.0.0"
},
"devDependencies": {
diff --git a/runTimer.js b/runTimer.js
index 3981687..f16098d 100644
--- a/runTimer.js
+++ b/runTimer.js
@@ -3,6 +3,7 @@ const { mnemonicToSeed } = require('bip39');
const { fromMasterSeed } = require('ethereumjs-wallet/hdkey');
const { mnemonic } = require('./secret');
const lottery = require('./build/contracts/Lottery.json');
+
const address = '0xd6141c8099670fe22a67eea3224d559c5d05aa55';
const web3 = new Web3('https://testnet-rpc.dexon.org');
@@ -74,7 +75,7 @@ const times = [
let account;
let contract;
-const runTime = time => {
+const runTime = (time) => {
if ((time + 5) > (Date.now() / 1000)) {
setTimeout(() => runTime(time), 5000);
return;
@@ -89,7 +90,7 @@ const runTime = time => {
};
mnemonicToSeed(mnemonic)
- .then(seed => {
+ .then((seed) => {
const hdWallet = fromMasterSeed(seed);
const key = hdWallet.derivePath('m/44\'/237\'/0\'/0/0');
const privateKey = `0x${key._hdkey._privateKey.toString('hex')}`;
diff --git a/yarn.lock b/yarn.lock
index 03b9835..2ac901d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6423,6 +6423,11 @@ mock-fs@^4.1.0:
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.8.0.tgz#eb0784ceba4b34c91a924a5112eeb36e1b5a9e29"
integrity sha512-Gwj4KnJOW15YeTJKO5frFd/WDO5Mc0zxXqL9oHx3+e9rBqW8EVARqQHSaIXznUdljrD6pvbNGW2ZGXKPEfYJfw==
+moment@^2.24.0:
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+ integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
mout@^0.11.0:
version "0.11.1"
resolved "https://registry.yarnpkg.com/mout/-/mout-0.11.1.tgz#ba3611df5f0e5b1ffbfd01166b8f02d1f5fa2b99"
@@ -7679,7 +7684,7 @@ querystring-es3@^0.2.0:
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
-querystring@0.2.0, querystring@^0.2.0:
+querystring@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
@@ -9813,16 +9818,6 @@ webpack-dev-server@^3.2.1:
webpack-log "^2.0.0"
yargs "12.0.2"
-webpack-hot-middleware@^2.24.3:
- version "2.24.3"
- resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.24.3.tgz#5bb76259a8fc0d97463ab517640ba91d3382d4a6"
- integrity sha512-pPlmcdoR2Fn6UhYjAhp1g/IJy1Yc9hD+T6O9mjRcWV2pFbBjIFoJXhP0CoD0xPOhWJuWXuZXGBga9ybbOdzXpg==
- dependencies:
- ansi-html "0.0.7"
- html-entities "^1.2.0"
- querystring "^0.2.0"
- strip-ansi "^3.0.0"
-
webpack-log@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f"