This commit is contained in:
Chi Kei Chan 2018-10-28 04:05:08 -07:00
parent c33adf5158
commit 7db118e841
14 changed files with 108 additions and 367 deletions

@ -17,6 +17,7 @@
"react": "^16.2.0",
"react-cookies": "^0.1.0",
"react-dom": "^16.2.0",
"react-ga": "^2.5.3",
"react-helmet": "^5.2.0",
"react-redux": "^5.0.7",
"react-responsive": "^5.0.0",

@ -85,15 +85,15 @@ class BlockingWarning extends Component {
if (!isConnected && initialized) {
content = [
<div>No Ethereum wallet found</div>,
<div className="header__dialog__description">
<div key="warning-title">No Ethereum wallet found</div>,
<div key="warning-desc" className="header__dialog__description">
{
isMobile()
? 'Please visit us from a web3-enabled mobile browser, such as Trust Wallet and Cipher Browser.'
: 'Please visit us after installing Metamask on Chrome or Brave.'
}
</div>,
<div className="header__download">
<div key="warning-logos" className="header__download">
{
isMobile()
? (
@ -115,13 +115,12 @@ class BlockingWarning extends Component {
const correctNetworkId = process.env.REACT_APP_NETWORK_ID || 1;
const correctNetwork = process.env.REACT_APP_NETWORK || 'Main Ethereum Network';
console.log({correctNetworkId, correctNetwork, networkId })
const wrongNetwork = networkId != correctNetworkId;
if (wrongNetwork) {
content = [
<div>You are on the wrong network</div>,
<div className="header__dialog__description">
<div key="warning-title">You are on the wrong network</div>,
<div key="warning-desc" className="header__dialog__description">
{`Please switch to ${correctNetwork}`}
</div>,
];

@ -1,18 +0,0 @@
import {
EXCHANGE_CONTRACT_READY
} from '../constants/actionTypes';
// definitely needs to be redux thunk
export const exchangeContractReady = (symbol, exchangeContract) => ({
type: EXCHANGE_CONTRACT_READY,
payload: { [symbol]: exchangeContract }
});
export default (state = {}, action) => {
const { payload } = action;
switch(action.type) {
case EXCHANGE_CONTRACT_READY:
return Object.assign({}, state, payload )
default: return state;
}
}

@ -1,237 +0,0 @@
import {
SET_INPUT_BALANCE,
SET_OUTPUT_BALANCE,
SET_INPUT_TOKEN,
SET_OUTPUT_TOKEN,
SET_ETH_POOL_1,
SET_ETH_POOL_2,
SET_TOKEN_POOL_1,
SET_TOKEN_POOL_2,
SET_ALLOWANCE_APPROVAL_STATE,
SET_EXCHANGE_INPUT_VALUE,
SET_EXCHANGE_OUTPUT_VALUE,
SET_EXCHANGE_RATE,
SET_EXCHANGE_FEE,
SET_INVEST_TOKEN,
SET_INVEST_ETH_POOL,
SET_INVEST_TOKEN_POOL,
SET_INVEST_TOKEN_ALLOWANCE,
SET_INVEST_SHARES,
SET_USER_SHARES,
SET_INVEST_ETH_BALANCE,
SET_INVEST_TOKEN_BALANCE,
SET_INVEST_SHARES_INPUT,
SET_INVEST_ETH_REQUIRED,
SET_INVEST_TOKENS_REQUIRED,
SET_INVEST_CHECKED
} from '../constants/actionTypes';
export const setInputBalance = (inputBalance) => ({
type: SET_INPUT_BALANCE,
inputBalance
});
export const setOutputBalance = (outputBalance) => ({
type: SET_OUTPUT_BALANCE,
outputBalance
})
export const setInputToken = (inputToken) => ({
type: SET_INPUT_TOKEN,
inputToken
});
export const setOutputToken = (outputToken) => ({
type: SET_OUTPUT_TOKEN,
outputToken
});
export const setEthPool1 = (ethPool1) => ({
type: SET_ETH_POOL_1,
ethPool1
});
export const setEthPool2 = (ethPool2) => ({
type: SET_ETH_POOL_2,
ethPool2
});
export const setTokenPool1 = (tokenPool1) => ({
type: SET_TOKEN_POOL_1,
tokenPool1
});
export const setTokenPool2 = (tokenPool2) => ({
type: SET_TOKEN_POOL_2,
tokenPool2
});
export const setAllowanceApprovalState = (allowanceApproved) => ({
type: SET_ALLOWANCE_APPROVAL_STATE,
allowanceApproved
});
export const setExchangeInputValue = (inputValue) => ({
type: SET_EXCHANGE_INPUT_VALUE,
inputValue
});
export const setExchangeOutputValue = (outputValue) => ({
type: SET_EXCHANGE_OUTPUT_VALUE,
outputValue
});
export const setExchangeRate = (rate) => ({
type: SET_EXCHANGE_RATE,
rate
});
export const setExchangeFee = (fee) => ({
type: SET_EXCHANGE_FEE,
fee
});
export const setInvestToken = (investToken) => ({
type: SET_INVEST_TOKEN,
investToken
});
export const setInvestEthPool = (investEthPool) => ({
type: SET_INVEST_ETH_POOL,
investEthPool
});
export const setInvestTokenPool = (investTokenPool) => ({
type: SET_INVEST_TOKEN_POOL,
investTokenPool
});
export const setInvestShares = (investShares) => ({
type: SET_INVEST_SHARES,
investShares
});
export const setUserShares = (userShares) => ({
type: SET_USER_SHARES,
userShares
});
export const setInvestTokenBalance = (investTokenBalance) => ({
type: SET_INVEST_TOKEN_BALANCE,
investTokenBalance
});
export const setInvestEthBalance = (investEthBalance) => ({
type: SET_INVEST_ETH_BALANCE,
investEthBalance
});
export const setInvestTokenAllowance = (investTokenAllowance) => ({
type: SET_INVEST_TOKEN_ALLOWANCE,
investTokenAllowance
});
export const setInvestSharesInput = (investSharesInput) => ({
type: SET_INVEST_SHARES_INPUT,
investSharesInput
});
export const setInvestEthRequired = (investEthRequired) => ({
type: SET_INVEST_ETH_REQUIRED,
investEthRequired
});
export const setInvestTokensRequired = (investTokensRequired) => ({
type: SET_INVEST_TOKENS_REQUIRED,
investTokensRequired
});
export const setInvestChecked = (investChecked) => ({
type: SET_INVEST_CHECKED,
investChecked
});
export default (state = {}, action) => {
const {
inputBalance,
outputBalance,
inputToken,
outputToken,
ethPool1,
ethPool2,
tokenPool1,
tokenPool2,
allowanceApproved,
inputValue,
outputValue,
rate,
fee,
investToken,
investEthPool,
investTokenPool,
investShares,
userShares,
investEthBalance,
investTokenBalance,
investTokenAllowance,
investSharesInput,
investEthRequired,
investTokensRequired,
investChecked
} = action;
switch(action.type) {
case SET_INPUT_BALANCE:
return Object.assign({}, state, { inputBalance: inputBalance });
case SET_OUTPUT_BALANCE:
return Object.assign({}, state, { outputBalance: outputBalance });
case SET_INPUT_TOKEN:
return Object.assign({}, state, { inputToken: inputToken });
case SET_OUTPUT_TOKEN:
return Object.assign({}, state, { outputToken: outputToken });
case SET_ETH_POOL_1:
return Object.assign({}, state, { ethPool1: ethPool1 });
case SET_ETH_POOL_2:
return Object.assign({}, state, { ethPool2: ethPool2 });
case SET_TOKEN_POOL_1:
return Object.assign({}, state, { tokenPool1: tokenPool1 });
case SET_TOKEN_POOL_2:
return Object.assign({}, state, { tokenPool2: tokenPool2 });
case SET_ALLOWANCE_APPROVAL_STATE:
return Object.assign({}, state, { allowanceApproved: allowanceApproved });
case SET_EXCHANGE_INPUT_VALUE:
return Object.assign({}, state, { inputValue: inputValue });
case SET_EXCHANGE_OUTPUT_VALUE:
return Object.assign({}, state, { outputValue: outputValue });
case SET_EXCHANGE_RATE:
return Object.assign({}, state, { rate: rate });
case SET_EXCHANGE_FEE:
return Object.assign({}, state, { fee: fee });
case SET_INVEST_TOKEN:
return Object.assign({}, state, { investToken: investToken });
case SET_INVEST_ETH_POOL:
return Object.assign({}, state, { investEthPool: investEthPool });
case SET_INVEST_TOKEN_POOL:
return Object.assign({}, state, { investTokenPool: investTokenPool });
case SET_INVEST_SHARES:
return Object.assign({}, state, { investShares: investShares });
case SET_USER_SHARES:
return Object.assign({}, state, { userShares: userShares });
case SET_INVEST_ETH_BALANCE:
return Object.assign({}, state, { investEthBalance: investEthBalance });
case SET_INVEST_TOKEN_BALANCE:
return Object.assign({}, state, { investTokenBalance: investTokenBalance });
case SET_INVEST_TOKEN_ALLOWANCE:
return Object.assign({}, state, { investTokenAllowance: investTokenAllowance });
case SET_INVEST_SHARES_INPUT:
return Object.assign({}, state, { investSharesInput: investSharesInput });
case SET_INVEST_ETH_REQUIRED:
return Object.assign({}, state, { investEthRequired: investEthRequired });
case SET_INVEST_TOKENS_REQUIRED:
return Object.assign({}, state, { investTokensRequired: investTokensRequired });
case SET_INVEST_CHECKED:
return Object.assign({}, state, { investChecked: investChecked });
default: return state;
}
}

@ -1,86 +0,0 @@
const UPDATE_FIELD = 'app/swap/updateField';
const ADD_ERROR = 'app/swap/addError';
const REMOVE_ERROR = 'app/swap/removeError';
const RESET_SWAP = 'app/swap/resetSwap';
const getInitialState = () => {
return {
input: '',
output: '',
inputCurrency: '',
outputCurrency: '',
lastEditedField: '',
inputErrors: [],
outputErrors: [],
};
};
export const isValidSwap = (state) => {
const { swap } = state;
return swap.outputCurrency !== '' &&
swap.inputCurrency !== '' &&
swap.input !== '' &&
swap.output !== '' &&
swap.inputErrors.length === 0 &&
swap.outputErrors.length === 0;
};
export const updateField = ({ name, value }) => ({
type: UPDATE_FIELD,
payload: { name, value },
});
export const addError = ({ name, value }) => ({
type: ADD_ERROR,
payload: { name, value },
});
export const removeError = ({ name, value }) => ({
type: REMOVE_ERROR,
payload: { name, value },
});
export const resetSwap = () => ({
type: RESET_SWAP,
});
function reduceAddError(state, payload) {
const { name, value } = payload;
let nextErrors = state[name];
if (nextErrors.indexOf(value) === -1) {
nextErrors = [...nextErrors, value];
}
return {
...state,
[name]: nextErrors,
};
}
function reduceRemoveError(state, payload) {
const { name, value } = payload;
return {
...state,
[name]: state[name].filter(error => error !== value),
};
}
export default function swapReducer(state = getInitialState(), { type, payload }) {
switch (type) {
case UPDATE_FIELD:
return {
...state,
[payload.name]: payload.value,
};
case ADD_ERROR:
return reduceAddError(state, payload);
case REMOVE_ERROR:
return reduceRemoveError(state, payload);
case RESET_SWAP:
return getInitialState();
default:
return state;
}
}

@ -1,18 +0,0 @@
import {
TOKEN_CONTRACT_READY
} from '../constants/actionTypes';
// again, needs to be redux thunk
export const tokenContractReady = (symbol, tokenContract) => ({
type: TOKEN_CONTRACT_READY,
payload: { [symbol]: tokenContract }
});
export default (state = {}, action) => {
const { payload } = action;
switch(action.type) {
case TOKEN_CONTRACT_READY:
return Object.assign({}, state, payload )
default: return state;
}
}

@ -1,11 +1,15 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import ReactGA from 'react-ga';
import App from './pages/App';
import store from './store';
import './index.scss';
ReactGA.initialize('UA-128182339-1');
ReactGA.pageview(window.location.pathname + window.location.search);
window.addEventListener('load', function() {
ReactDOM.render(
<Provider store={store}>

@ -16,6 +16,7 @@ import {BigNumber as BN} from 'bignumber.js';
import EXCHANGE_ABI from '../../abi/exchange';
import "./pool.scss";
import promisify from "../../helpers/web3-promisfy";
import ReactGA from "react-ga";
const INPUT = 0;
const OUTPUT = 1;
@ -40,6 +41,15 @@ class AddLiquidity extends Component {
showSummaryModal: false,
};
reset = () => {
this.setState({
inputValue: '',
outputValue: '',
lastEditedField: '',
showSummaryModal: false,
});
};
shouldComponentUpdate(nextProps, nextState) {
const { isConnected, account, exchangeAddresses, balances, web3 } = this.props;
const { inputValue, outputValue, inputCurrency, outputCurrency, lastEditedField, showSummaryModal } = this.state;
@ -143,9 +153,17 @@ class AddLiquidity extends Component {
const maxTokens = tokenAmount.multipliedBy(1 + MAX_LIQUIDITY_SLIPPAGE);
try {
await exchange.methods.addLiquidity(minLiquidity.toFixed(0), maxTokens.toFixed(0), deadline).send({
exchange.methods.addLiquidity(minLiquidity.toFixed(0), maxTokens.toFixed(0), deadline).send({
from: account,
value: ethAmount.toFixed(0)
}, (err, data) => {
this.reset();
if (data) {
ReactGA.event({
category: 'Pool',
action: 'AddLiquidity',
});
}
});
} catch (err) {
console.error(err);
@ -417,6 +435,11 @@ class AddLiquidity extends Component {
return null;
}
ReactGA.event({
category: 'TransactionDetail',
action: 'Open',
});
const { value, decimals, label } = selectors().getTokenBalance(outputCurrency, fromToken[outputCurrency]);
const SLIPPAGE = 0.025;

@ -9,6 +9,7 @@ import AddressInputPanel from "../../components/AddressInputPanel";
import OversizedPanel from "../../components/OversizedPanel";
import FACTORY_ABI from "../../abi/factory";
import {addExchange} from "../../ducks/addresses";
import ReactGA from "react-ga";
class CreateExchange extends Component {
static propTypes = {
@ -118,6 +119,10 @@ class CreateExchange extends Component {
decimals: 0,
tokenAddress: '',
});
ReactGA.event({
category: 'Pool',
action: 'CreateExchange',
});
}
})
};

@ -11,6 +11,7 @@ import OversizedPanel from "../../components/OversizedPanel";
import ArrowPlus from "../../assets/images/plus-blue.svg";
import EXCHANGE_ABI from "../../abi/exchange";
import promisify from "../../helpers/web3-promisfy";
import ReactGA from "react-ga";
class RemoveLiquidity extends Component {
static propTypes = {
@ -114,6 +115,10 @@ class RemoveLiquidity extends Component {
).send({ from: account }, (err, data) => {
if (data) {
this.reset();
ReactGA.event({
category: 'Pool',
action: 'RemoveLiquidity',
});
}
});
};

@ -6,9 +6,13 @@ import RemoveLiquidity from './RemoveLiquidity';
import { Switch, Route } from 'react-router-dom';
import "./pool.scss";
import MediaQuery from "react-responsive";
import ReactGA from "react-ga";
class Pool extends Component {
componentWillMount() {
ReactGA.pageview(window.location.pathname + window.location.search);
}
render() {
return (
<div className="pool">

@ -19,6 +19,7 @@ import EXCHANGE_ABI from '../../abi/exchange';
import "./send.scss";
import promisify from "../../helpers/web3-promisfy";
import MediaQuery from "react-responsive";
import ReactGA from "react-ga";
const INPUT = 0;
const OUTPUT = 1;
@ -42,6 +43,10 @@ class Send extends Component {
showSummaryModal: false,
};
componentWillMount() {
ReactGA.pageview(window.location.pathname + window.location.search);
}
shouldComponentUpdate(nextProps, nextState) {
return true;
}
@ -377,6 +382,10 @@ class Send extends Component {
const deadline = block.timestamp + 300;
if (lastEditedField === INPUT) {
ReactGA.event({
category: type,
action: 'TransferInput',
});
// send input
switch(type) {
case 'ETH_TO_TOKEN':
@ -427,6 +436,10 @@ class Send extends Component {
if (lastEditedField === OUTPUT) {
// send output
ReactGA.event({
category: type,
action: 'TransferOutput',
});
switch (type) {
case 'ETH_TO_TOKEN':
new web3.eth.Contract(EXCHANGE_ABI, fromToken[outputCurrency])
@ -556,6 +569,11 @@ class Send extends Component {
return null;
}
ReactGA.event({
category: 'TransactionDetail',
action: 'Open',
});
const ALLOWED_SLIPPAGE = 0.025;
const TOKEN_ALLOWED_SLIPPAGE = 0.04;

@ -3,9 +3,10 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import {BigNumber as BN} from "bignumber.js";
import MediaQuery from 'react-responsive';
import ReactGA from 'react-ga';
import { selectors } from '../../ducks/web3connect';
import { CSSTransitionGroup } from "react-transition-group";
import MediaQuery from 'react-responsive';
import Header from '../../components/Header';
import NavigationTabs from '../../components/NavigationTabs';
import Modal from '../../components/Modal';
@ -40,6 +41,10 @@ class Swap extends Component {
showSummaryModal: false,
};
componentWillMount() {
ReactGA.pageview(window.location.pathname + window.location.search);
}
shouldComponentUpdate(nextProps, nextState) {
return true;
}
@ -373,6 +378,10 @@ class Swap extends Component {
if (lastEditedField === INPUT) {
// swap input
ReactGA.event({
category: type,
action: 'SwapInput',
});
switch(type) {
case 'ETH_TO_TOKEN':
// let exchange = new web3.eth.Contract(EXCHANGE_ABI, fromToken[outputCurrency]);
@ -420,6 +429,10 @@ class Swap extends Component {
if (lastEditedField === OUTPUT) {
// swap output
ReactGA.event({
category: type,
action: 'SwapOutput',
});
switch (type) {
case 'ETH_TO_TOKEN':
new web3.eth.Contract(EXCHANGE_ABI, fromToken[outputCurrency])
@ -541,6 +554,11 @@ class Swap extends Component {
return null;
}
ReactGA.event({
category: 'TransactionDetail',
action: 'Open',
});
const ALLOWED_SLIPPAGE = 0.025;
const TOKEN_ALLOWED_SLIPPAGE = 0.04;

@ -8999,6 +8999,13 @@ react-error-overlay@^5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.0.4.tgz#39cf184d770f98b65a2ee59a779d03b8d092b69e"
react-ga@^2.5.3:
version "2.5.3"
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.5.3.tgz#0f447c73664c069a5fc341f6f431262e3d4c23c4"
optionalDependencies:
prop-types "^15.6.0"
react "^15.6.2 || ^16.0"
react-helmet@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7"
@ -9156,6 +9163,15 @@ react-transition-group@1.x:
prop-types "^15.5.6"
warning "^3.0.0"
"react@^15.6.2 || ^16.0":
version "16.6.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.6.0.tgz#b34761cfaf3e30f5508bc732fb4736730b7da246"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.10.0"
react@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba"
@ -9779,6 +9795,13 @@ saxes@^3.1.2:
dependencies:
xmlchars "^1.3.1"
scheduler@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.10.0.tgz#7988de90fe7edccc774ea175a783e69c40c521e1"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
schema-utils@^0.4.4, schema-utils@^0.4.5:
version "0.4.7"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"