Commit bab0217d authored by Chi Kei Chan's avatar Chi Kei Chan

Add Drizzle to manage web3 and smart contracts call

parent e77330ec
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react';
import PropTypes from 'prop-types';
import './address-input-panel.scss';
......@@ -39,4 +39,4 @@ class AddressInputPanel extends Component {
}
}
export default connect()(AddressInputPanel);
export default drizzleConnect(AddressInputPanel);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react'
import PropTypes from 'prop-types';
import { CSSTransitionGroup } from "react-transition-group";
import classnames from 'classnames';
......@@ -32,7 +32,11 @@ class CurrencyInputPanel extends Component {
title: PropTypes.string,
description: PropTypes.string,
extraText: PropTypes.string,
web3: PropTypes.object.isRequired,
initialized: PropTypes.bool,
};
static contextTypes = {
drizzle: PropTypes.object,
};
state = {
......@@ -44,15 +48,19 @@ class CurrencyInputPanel extends Component {
getBalance() {
const {
balance,
web3,
initialized,
} = this.props;
const { selectedTokenAddress } = this.state;
const { drizzle: { web3 } } = this.context;
if (!selectedTokenAddress) {
if (!selectedTokenAddress || !initialized || !web3 || !balance) {
return '';
}
if (selectedTokenAddress === 'ETH') {
return `Balance: ${web3.utils.fromWei(balance, 'ether')}`;
}
const bn = balance[selectedTokenAddress];
if (!bn) {
......@@ -147,8 +155,6 @@ class CurrencyInputPanel extends Component {
const {
title,
description,
balance,
web3,
} = this.props;
const { selectedTokenAddress } = this.state;
......@@ -201,13 +207,22 @@ class CurrencyInputPanel extends Component {
}
}
export default connect(
state => ({
tokenAddresses: state.web3.tokenAddresses,
balance: state.web3.balance,
web3: state.web3.web3,
}),
export default drizzleConnect(
CurrencyInputPanel,
state => {
const {
drizzleStatus: { initialized },
accounts,
accountBalances,
} = state;
return {
tokenAddresses: state.addresses.tokenAddresses,
initialized,
balance: accountBalances[accounts[0]] || null,
};
},
dispatch => ({
updateField: (name, value) => dispatch(updateField({ name, value })),
})
)(CurrencyInputPanel);
}),
);
......@@ -3,7 +3,7 @@ import React, { Component }from 'react';
import SelectToken from './SelectToken';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { setInteractionState, setExchangeType } from '../ducks/web3';
import { setInteractionState, setExchangeType } from '../ducks/addresses';
import { setExchangeInputValue, setExchangeOutputValue, setExchangeRate, setExchangeFee, setInputToken, setOutputToken, setInputBalance, setOutputBalance, setAllowanceApprovalState } from '../ducks/exchange';
class Exchange extends Component {
......
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react'
import classnames from 'classnames';
import UAParser from 'ua-parser-js';
import Logo from '../Logo';
......@@ -57,7 +57,9 @@ function Header (props) {
})}
>
<div>No Ethereum wallet found</div>
<div className="header__dialog__description">Please visit us from a web3-enabled mobile browser, such as Trust Wallet and Cipher Browser.</div>
<div className="header__dialog__description">
Please visit us from a web3-enabled mobile browser, such as Trust Wallet and Cipher Browser.
</div>
<div className="header__download">
<img src={CipherLogo} onClick={() => window.open(getCipherLink(), '_blank')} />
<img src={TrustLogo} onClick={() => window.open(getTrustLink(), '_blank')} />
......@@ -72,7 +74,7 @@ function Header (props) {
<div className="header__center-group">
<span className="header__title">Uniswap</span>
</div>
<Web3Status address="0xcf1de0b4d1e492080336909f70413a5f4e7eec62" isConnected />
<Web3Status isConnected />
</div>
<NavigationTabs
className={classnames('header__navigation', {
......@@ -84,15 +86,15 @@ function Header (props) {
}
Header.propTypes = {
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired,
};
export default connect(
export default drizzleConnect(
Header,
state => ({
web3: state.web3.web3,
currentAddress: state.web3.currentAddress,
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
// web3: console.log(state) || state.web3,
currentAddress: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
}),
)(Header)
\ No newline at end of file
);
......@@ -2,7 +2,7 @@ import React, { Component }from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { subscribe } from 'redux-subscriber';
import { setWeb3ConnectionStatus, setInteractionState, setNetworkMessage, metamaskLocked } from '../ducks/web3';
import { setWeb3ConnectionStatus, setInteractionState, setNetworkMessage, metamaskLocked } from '../ducks/addresses';
class NetworkStatus extends Component {
componentDidMount(){
......
import React, { Component } from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux';
import { setBlockTimestamp, setInteractionState } from '../ducks/web3';
import { setBlockTimestamp, setInteractionState } from '../ducks/addresses';
import { setExchangeInputValue, setExchangeOutputValue } from '../ducks/exchange';
class Purchase extends Component {
......
import React, { Component } from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux';
import { setBlockTimestamp, setInteractionState } from '../ducks/web3';
import { setBlockTimestamp, setInteractionState } from '../ducks/addresses';
import { setExchangeInputValue, setExchangeOutputValue } from '../ducks/exchange';
class Purchase extends Component {
......
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { updateBalance } from '../../ducks/web3';
class Watcher extends Component {
state = {
watchlist: {},
};
componentWillMount() {
this.startWatching();
}
componentWillUnmount() {
}
add(address) {
const { watchlist } = this.state;
this.setState({
...watchlist,
[address]: true,
});
}
remove(address) {
const { watchlist } = this.state;
this.setState({
...watchlist,
[address]: false,
});
}
startWatching() {
if (this.interval) {
clearInterval(this.interval);
return;
}
this.interval = setInterval(() => {
this.props.updateBalance();
Object.keys(this.state.watchlist).forEach(address => {
});
}, 15000);
}
stopWatching() {
if (this.interval) {
clearInterval(this.interval);
}
}
render() {
return <noscript />;
}
}
export default connect(
null,
dispatch => ({
updateBalance: () => dispatch(updateBalance()),
}),
)(Watcher);
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react'
import classnames from 'classnames';
import Web3 from 'web3';
import Jazzicon from 'jazzicon';
......@@ -26,6 +26,7 @@ function Web3Status(props) {
return;
}
el.innerHTML = '';
el.appendChild(Jazzicon(18, parseInt(address.slice(2), 16)));
}}
/>
......@@ -41,7 +42,7 @@ function getText(text) {
return 'Disconnected';
}
const address = Web3.utils.toChecksumAddress(text)
const address = Web3.utils.toChecksumAddress(text);
return `${address.substring(0, 6)}...${address.substring(38)}`;
}
......@@ -56,9 +57,10 @@ Web3Status.defaultProps = {
address: 'Disconnected',
};
export default connect(
({ web3: { web3, currentAddress } }) => ({
address: currentAddress,
isConnected: !!(web3 && currentAddress),
export default drizzleConnect(
Web3Status,
state => ({
address: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
})
)(Web3Status);
);
import Web3 from "web3";
const INITIALIZE = 'app/web3/initialize';
const UPDATE_CURRENT_ADDRESS = 'app/web3/updateCurrentAddress';
const UPDATE_BALANCE = 'app/web3/updateBalance';
const initialState = {
web3: {},
currentAddress: '',
balance: {},
exchangeAddresses: {
......@@ -28,77 +21,8 @@ const initialState = {
},
};
export const initialize = () => dispatch => {
if (typeof window.web3 !== 'undefined') {
const web3 = new Web3(window.web3.currentProvider);
dispatch({
type: INITIALIZE,
payload: web3,
});
dispatch(updateCurrentAddress());
setInterval(() => dispatch(updateBalance()), 15000)
}
};
export const updateCurrentAddress = () => (dispatch, getState) => {
const { web3: { web3 } } = getState();
if (!web3) {
return;
}
web3.eth.getAccounts((err, accounts) => {
if (err) {
return;
}
dispatch({
type: UPDATE_CURRENT_ADDRESS,
payload: accounts[0],
});
dispatch(updateBalance());
});
};
export const updateBalance = () => (dispatch, getState) => {
const { web3: { web3, currentAddress } } = getState();
if (!web3 || !currentAddress) {
return;
}
web3.eth.getBalance(currentAddress, (e, data) => {
if (e) {
return;
}
dispatch({
type: UPDATE_BALANCE,
payload: {
address: 'ETH',
balance: data,
}
});
});
};
export default (state = initialState, { type, payload }) => {
export default (state = initialState, { type }) => {
switch (type) {
case INITIALIZE:
return { ...state, web3: payload };
case UPDATE_CURRENT_ADDRESS:
return { ...state, currentAddress: payload };
case UPDATE_BALANCE:
return {
...state,
balance: {
...state.balance,
[payload.address]: payload.balance,
},
};
default: return state;
}
}
import { combineReducers } from 'redux';
// import global from './global-reducer';
import web3 from './web3';
import { drizzleReducers } from 'drizzle'
import addresses from './addresses';
import exchangeContracts from './exchange-contract';
import tokenContracts from './token-contract';
import exchange from './exchange';
import swap from './swap';
export default combineReducers({
web3,
addresses,
exchangeContracts,
tokenContracts,
exchange,
swap,
...drizzleReducers,
});
import React from 'react';
import ReactDOM from 'react-dom';
import Web3 from 'web3';
import { DrizzleProvider } from 'drizzle-react';
import App from './pages/App';
import { Provider } from 'react-redux';
import store from './store';
import './index.scss';
import registerServiceWorker from './registerServiceWorker';
window.addEventListener('load', function() {
ReactDOM.render(
<Provider store={store}>
<DrizzleProvider options={{
contracts: [],
events: [],
polls: { accounts: 3000, blocks: 3000 },
}} store={store}>
<App />
</Provider>
</DrizzleProvider>
, document.getElementById('root')
);
......
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react'
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { AnimatedSwitch } from 'react-router-transition';
import { initialize } from '../ducks/web3'
import Watcher from '../components/Watcher';
import Swap from './Swap';
import Send from './Send';
import Pool from './Pool';
......@@ -11,35 +9,32 @@ import Pool from './Pool';
import './App.scss';
class App extends Component {
componentWillMount() {
this.props.initializeWeb3();
}
render() {
if (!this.props.initialized) {
return <noscript />;
}
return (
<div style={{ width: '100%', height: '100%' }}>
<Watcher />
<BrowserRouter>
<AnimatedSwitch
atEnter={{ opacity: 0 }}
atLeave={{ opacity: 0 }}
atActive={{ opacity: 1 }}
className="app__switch-wrapper"
>
<Route exact path="/swap" component={Swap} />
<Route exact path="/send" component={Send} />
<Route exact path="/pool" component={Pool} />
<Route component={Swap} />
</AnimatedSwitch>
</BrowserRouter>
</div>
<BrowserRouter>
<AnimatedSwitch
atEnter={{ opacity: 0 }}
atLeave={{ opacity: 0 }}
atActive={{ opacity: 1 }}
className="app__switch-wrapper"
>
<Route exact path="/swap" component={Swap} />
<Route exact path="/send" component={Send} />
<Route exact path="/pool" component={Pool} />
<Route component={Swap} />
</AnimatedSwitch>
</BrowserRouter>
);
}
}
export default connect(
null,
dispatch => ({
initializeWeb3: () => dispatch(initialize()),
})
)(App);
export default drizzleConnect(
App,
state => ({
initialized: state.drizzleStatus.initialized,
}),
);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import classnames from "classnames";
......@@ -20,7 +20,6 @@ class Pool extends Component {
// Injected by React Router Dom
push: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired,
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired,
};
......@@ -84,13 +83,13 @@ class Pool extends Component {
}
export default withRouter(
connect(
drizzleConnect(
Pool,
(state, ownProps) => ({
push: ownProps.history.push,
pathname: ownProps.location.pathname,
web3: state.web3.web3,
currentAddress: state.web3.currentAddress,
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
currentAddress: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
}),
)(Pool)
),
);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import classnames from 'classnames';
......@@ -16,7 +16,6 @@ class Send extends Component {
// Injected by React Router Dom
push: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired,
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired,
};
......@@ -75,13 +74,13 @@ class Send extends Component {
}
export default withRouter(
connect(
drizzleConnect(
Send,
(state, ownProps) => ({
push: ownProps.history.push,
pathname: ownProps.location.pathname,
web3: state.web3.web3,
currentAddress: state.web3.currentAddress,
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
currentAddress: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
}),
)(Send)
),
);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import classnames from 'classnames';
......@@ -15,7 +15,6 @@ class Swap extends Component {
// Injected by React Router Dom
push: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired,
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired,
};
......@@ -67,13 +66,13 @@ class Swap extends Component {
}
export default withRouter(
connect(
drizzleConnect(
Swap,
(state, ownProps) => ({
push: ownProps.history.push,
pathname: ownProps.location.pathname,
web3: state.web3.web3,
currentAddress: state.web3.currentAddress,
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
currentAddress: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
}),
)(Swap)
),
);
import { generateContractsInitialState } from 'drizzle'
export default {
web3: {
web3: {},
addresses: {
exchangeAddresses: {
addresses: [
['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'],
......@@ -20,6 +21,7 @@ export default {
]
}
},
contracts: generateContractsInitialState({ contracts: [], events: [], polls: [] }),
exchangeContracts: {},
tokenContracts: {},
exchange: {
......
import { applyMiddleware, compose, createStore } from 'redux';
import reducer from '../ducks';
import thunk from 'redux-thunk'
import initSubscriber from 'redux-subscriber';
import initialState from './initial-state';
import reducer from '../ducks';
import createSagaMiddleware from 'redux-saga';
import { all, fork } from 'redux-saga/effects'
import { drizzleSagas } from 'drizzle'
function* root() {
yield all(
drizzleSagas.map(saga => fork(saga))
)
}
const middleware = [thunk];
const sagaMiddleware = createSagaMiddleware();
const middleware = [thunk, sagaMiddleware];
const enhancers = [];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(applyMiddleware(...middleware), ...enhancers)
composeEnhancers(
applyMiddleware(...middleware),
...enhancers,
)
);
// redux-subscribe solution attempt
// eslint-disable-next-line no-unused-vars
const subscribe = initSubscriber(store);
sagaMiddleware.run(root);
export default store;
\ No newline at end of file
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment