diff --git a/src/components/CurrencyInputPanel/index.js b/src/components/CurrencyInputPanel/index.js
index 513461874f..ff9fc31208 100644
--- a/src/components/CurrencyInputPanel/index.js
+++ b/src/components/CurrencyInputPanel/index.js
@@ -56,6 +56,7 @@ class CurrencyInputPanel extends Component {
addExchange: PropTypes.func.isRequired,
filteredTokens: PropTypes.arrayOf(PropTypes.string),
disableUnlock: PropTypes.bool,
+ renderInput: PropTypes.func,
};
static defaultProps = {
@@ -249,16 +250,76 @@ class CurrencyInputPanel extends Component {
);
}
+ renderInput() {
+ const {
+ errorMessage,
+ value,
+ onValueChange,
+ selectedTokenAddress,
+ disableTokenSelect,
+ renderInput,
+ } = this.props;
+
+ if (typeof renderInput === 'function') {
+ return renderInput();
+ }
+
+ return (
+
+ onValueChange(e.target.value)}
+ onKeyPress={e => {
+ const charCode = e.which ? e.which : e.keyCode;
+
+ // Prevent 'minus' character
+ if (charCode === 45) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }}
+ value={value}
+ />
+ { this.renderUnlockButton() }
+
+
+ );
+ }
+
render() {
const {
title,
description,
extraText,
errorMessage,
- value,
- onValueChange,
- selectedTokenAddress,
- disableTokenSelect,
} = this.props;
return (
@@ -277,52 +338,7 @@ class CurrencyInputPanel extends Component {
{extraText}
-
- onValueChange(e.target.value)}
- onKeyPress={e => {
- const charCode = e.which ? e.which : e.keyCode;
-
- // Prevent 'minus' character
- if (charCode === 45) {
- e.preventDefault();
- e.stopPropagation();
- }
- }}
- value={value}
- />
- { this.renderUnlockButton() }
-
-
+ {this.renderInput()}
{this.renderModal()}
diff --git a/src/ducks/web3connect.js b/src/ducks/web3connect.js
index 92e4025d54..0d01633a91 100644
--- a/src/ducks/web3connect.js
+++ b/src/ducks/web3connect.js
@@ -44,6 +44,7 @@ const initialState = {
const TOKEN_LABEL_FALLBACK = {
'0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359': 'DAI',
'0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2': 'MKR',
+ '0x9B913956036a3462330B0642B20D3879ce68b450': 'BAT + ETH'
};
// selectors
@@ -246,6 +247,7 @@ export const sync = () => async (dispatch, getState) => {
}
const contract = contracts[tokenAddress] || new web3.eth.Contract(ERC20_ABI, tokenAddress);
+ const contractBytes32 = contracts[tokenAddress] || new web3.eth.Contract(ERC20_WITH_BYTES_ABI, tokenAddress);
if (!contracts[tokenAddress]) {
dispatch({
@@ -262,7 +264,17 @@ export const sync = () => async (dispatch, getState) => {
const tokenBalance = getBalance(address, tokenAddress);
const balance = await contract.methods.balanceOf(address).call();
const decimals = tokenBalance.decimals || await contract.methods.decimals().call();
- const symbol = TOKEN_LABEL_FALLBACK[tokenAddress] || tokenBalance.label || await contract.methods.symbol().call();
+ let symbol = tokenBalance.symbol;
+
+ try {
+ symbol = symbol || await contract.methods.symbol().call().catch();
+ } catch (e) {
+ try {
+ symbol = symbol || web3.utils.hexToString(await contractBytes32.methods.symbol().call().catch());
+ } catch (err) {
+
+ }
+ }
if (tokenBalance.value.isEqualTo(BN(balance)) && tokenBalance.label && tokenBalance.decimals) {
return;
diff --git a/src/pages/App.js b/src/pages/App.js
index e2a3055dff..76525bf8e6 100644
--- a/src/pages/App.js
+++ b/src/pages/App.js
@@ -54,6 +54,7 @@ class App extends Component {
+
diff --git a/src/pages/Pool/RemoveLiquidity.js b/src/pages/Pool/RemoveLiquidity.js
new file mode 100644
index 0000000000..b686b5a9f9
--- /dev/null
+++ b/src/pages/Pool/RemoveLiquidity.js
@@ -0,0 +1,294 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import classnames from "classnames";
+import { connect } from 'react-redux';
+import { BigNumber as BN } from 'bignumber.js';
+import NavigationTabs from "../../components/NavigationTabs";
+import ModeSelector from "./ModeSelector";
+import CurrencyInputPanel from "../../components/CurrencyInputPanel";
+import { selectors } from '../../ducks/web3connect';
+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";
+
+class RemoveLiquidity extends Component {
+ static propTypes = {
+ account: PropTypes.string,
+ balances: PropTypes.object,
+ web3: PropTypes.object,
+ exchangeAddresses: PropTypes.shape({
+ fromToken: PropTypes.object.isRequired,
+ }).isRequired,
+ };
+
+ state = {
+ tokenAddress: '',
+ value: '',
+ totalSupply: BN(0),
+ };
+
+ reset() {
+ this.setState({
+ value: '',
+ });
+ }
+
+ validate() {
+ const { tokenAddress, value } = this.state;
+ const { account, selectors, exchangeAddresses: { fromToken }, web3 } = this.props;
+ const exchangeAddress = fromToken[tokenAddress];
+
+ if (!web3 || !exchangeAddress || !account || !value) {
+ return {
+ isValid: false,
+ };
+ }
+
+ const { getBalance } = selectors();
+
+ const { value: liquidityBalance, decimals: liquidityDecimals } = getBalance(account, exchangeAddress);
+
+ if (liquidityBalance.isLessThan(BN(value).multipliedBy(10 ** liquidityDecimals))) {
+ return { isValid: false, errorMessage: 'Insufficient balance' };
+ }
+
+ return {
+ isValid: true,
+ };
+ }
+
+ onTokenSelect = async tokenAddress => {
+ const { exchangeAddresses: { fromToken }, web3 } = this.props;
+ const exchangeAddress = fromToken[tokenAddress];
+ this.setState({ tokenAddress });
+
+ if (!web3 || !exchangeAddress) {
+ return;
+ }
+
+ const exchange = new web3.eth.Contract(EXCHANGE_ABI, exchangeAddress);
+
+ const totalSupply = await exchange.methods.totalSupply().call();
+ this.setState({
+ totalSupply: BN(totalSupply),
+ });
+ };
+
+ onInputChange = value => {
+ this.setState({ value });
+ };
+
+ onRemoveLiquidity = async () => {
+ const { tokenAddress, value: input, totalSupply } = this.state;
+ const {
+ exchangeAddresses: { fromToken },
+ web3,
+ selectors,
+ account,
+ } = this.props;
+ const exchangeAddress = fromToken[tokenAddress];
+ const { getBalance } = selectors();
+ if (!web3 || !exchangeAddress) {
+ return;
+ }
+ const exchange = new web3.eth.Contract(EXCHANGE_ABI, exchangeAddress);
+ const SLIPPAGE = .02;
+ const { decimals } = getBalance(account, exchangeAddress);
+ const { value: ethReserve } = getBalance(exchangeAddress);
+ const { value: tokenReserve } = getBalance(exchangeAddress, tokenAddress);
+ const amount = BN(input).multipliedBy(10 ** decimals);
+
+ const ownership = amount.dividedBy(totalSupply);
+ const ethWithdrawn = ethReserve.multipliedBy(ownership);
+ const tokenWithdrawn = tokenReserve.multipliedBy(ownership);
+ const blockNumber = await promisify(web3, 'getBlockNumber');
+ const block = await promisify(web3, 'getBlock', blockNumber);
+ const deadline = block.timestamp + 300;
+
+ exchange.methods.removeLiquidity(
+ amount.toFixed(0),
+ ethWithdrawn.multipliedBy(1 - SLIPPAGE).toFixed(0),
+ tokenWithdrawn.multipliedBy(1 - SLIPPAGE).toFixed(0),
+ deadline,
+ ).send({ from: account }, (err, data) => {
+ if (data) {
+ this.reset();
+ }
+ });
+ };
+
+ getBalance = () => {
+ const {
+ exchangeAddresses: { fromToken },
+ account,
+ web3,
+ selectors,
+ } = this.props;
+
+ const { tokenAddress } = this.state;
+
+ if (!web3) {
+ return '';
+ }
+
+ const exchangeAddress = fromToken[tokenAddress];
+ if (!exchangeAddress) {
+ return '';
+ }
+ const { value, decimals } = selectors().getBalance(account, exchangeAddress);
+ return `Balance: ${value.dividedBy(10 ** decimals).toFixed(7)}`;
+ };
+
+ renderOutput() {
+ const {
+ exchangeAddresses: { fromToken },
+ account,
+ web3,
+ selectors,
+ } = this.props;
+ const { getBalance } = selectors();
+
+ const { tokenAddress, totalSupply, value: input } = this.state;
+
+
+ const exchangeAddress = fromToken[tokenAddress];
+ if (!exchangeAddress || !web3 || !input) {
+ return [
+ (
+
+ )}
+ disableTokenSelect
+ disableUnlock
+ />,
+
+
+
+ Exchange Rate
+ -
+
+
+ Current Pool Size
+ -
+
+
+ Your Pool Share
+ -
+
+
+
+ ];
+ }
+ const { value, decimals } = getBalance(account, exchangeAddress);
+ const { value: ethReserve } = getBalance(exchangeAddress);
+ const { value: tokenReserve, label } = getBalance(exchangeAddress, tokenAddress);
+
+ const ownership = value.dividedBy(totalSupply);
+ const ethPer = ethReserve.dividedBy(totalSupply);
+ const tokenPer = tokenReserve.dividedBy(totalSupply);
+
+ return [
+ (
+
+
+ {`${ethPer.multipliedBy(input).toFixed(3)} ETH`}
+
+
+
+
+ {`${tokenPer.multipliedBy(input).toFixed(3)} ${label}`}
+
+
+ )}
+ disableTokenSelect
+ disableUnlock
+ />,
+
+
+
+ Exchange Rate
+ {` ${ethReserve.dividedBy(10 ** 18).toFixed(2)} ETH + ${tokenReserve.dividedBy(10 ** decimals).toFixed(2)} ${label}`}
+
+
+ Current Pool Size
+ {totalSupply.dividedBy(10 ** decimals).toFixed(4)}
+
+
+ Your Pool Share
+ {ownership.multipliedBy(100).toFixed(2)}%
+
+
+
+ ];
+ }
+
+ render() {
+ const { isConnected } = this.props;
+ const { tokenAddress, value } = this.state;
+ const { isValid, errorMessage } = this.validate();
+
+ return (
+
+
+
+
+
+
+
+
+
+ { this.renderOutput() }
+
+
+
+
+ );
+ }
+}
+
+export default connect(
+ state => ({
+ isConnected: Boolean(state.web3connect.account),
+ web3: state.web3connect.web3,
+ balances: state.web3connect.balances,
+ account: state.web3connect.account,
+ exchangeAddresses: state.addresses.exchangeAddresses,
+ }),
+ dispatch => ({
+ selectors: () => dispatch(selectors()),
+ })
+)(RemoveLiquidity);
diff --git a/src/pages/Pool/index.js b/src/pages/Pool/index.js
index 0833e4c71d..7ec36badb7 100644
--- a/src/pages/Pool/index.js
+++ b/src/pages/Pool/index.js
@@ -2,7 +2,8 @@ import React, { Component } from 'react';
import Header from '../../components/Header';
import AddLiquidity from './AddLiquidity';
import CreateExchange from './CreateExchange';
-import { Switch, Redirect, Route } from 'react-router-dom';
+import RemoveLiquidity from './RemoveLiquidity';
+import { Switch, Route } from 'react-router-dom';
import "./pool.scss";
import MediaQuery from "react-responsive";
@@ -16,7 +17,7 @@ class Pool extends Component {
- {/**/}
+
diff --git a/src/pages/Pool/pool.scss b/src/pages/Pool/pool.scss
index faecf346ee..531a4f7736 100644
--- a/src/pages/Pool/pool.scss
+++ b/src/pages/Pool/pool.scss
@@ -150,3 +150,22 @@
color: $dove-gray;
}
}
+
+.remove-liquidity {
+ &__output {
+ @extend %row-nowrap;
+ min-height: 3.5rem;
+ }
+
+ &__output-text {
+ font-size: 1.25rem;
+ line-height: 1.5rem;
+ padding: 1rem .75rem;
+ }
+
+ &__output-plus {
+ font-size: 1.25rem;
+ line-height: 1.5rem;
+ padding: 1rem 0;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/Send/index.js b/src/pages/Send/index.js
index e9275deb3d..8bbddd11dd 100644
--- a/src/pages/Send/index.js
+++ b/src/pages/Send/index.js
@@ -666,7 +666,7 @@ class Send extends Component {
);
}
-
+ console.log(outputLabel)
return (
diff --git a/src/pages/Swap/index.js b/src/pages/Swap/index.js
index bce1034b6e..ba55040dde 100644
--- a/src/pages/Swap/index.js
+++ b/src/pages/Swap/index.js
@@ -450,13 +450,6 @@ class Swap extends Component {
return;
}
- console.log(
- BN(outputValue).multipliedBy(10 ** outputDecimals).toFixed(0),
- BN(inputValue).multipliedBy(10 ** inputDecimals).multipliedBy(1 + TOKEN_ALLOWED_SLIPPAGE).toFixed(0),
- inputAmountB.multipliedBy(1.2).toFixed(0),
- deadline,
- outputCurrency,
- )
new web3.eth.Contract(EXCHANGE_ABI, fromToken[inputCurrency])
.methods
.tokenToTokenSwapOutput(