Commit fd67c060 authored by Chi Kei Chan's avatar Chi Kei Chan Committed by GitHub

Implements calculateInput ETH to ERC20 (#38)

* Update Rinkeby exchange address

* Implement ETH to ERC20 calculateInput and calculateOutput
parent 12445c00
...@@ -12,6 +12,7 @@ import SearchIcon from '../../assets/images/magnifying-glass.svg'; ...@@ -12,6 +12,7 @@ import SearchIcon from '../../assets/images/magnifying-glass.svg';
import ERC20_ABI from '../../abi/erc20'; import ERC20_ABI from '../../abi/erc20';
import './currency-panel.scss'; import './currency-panel.scss';
import EXCHANGE_ABI from "../../abi/exchange";
const FUSE_OPTIONS = { const FUSE_OPTIONS = {
includeMatches: false, includeMatches: false,
...@@ -37,6 +38,9 @@ class CurrencyInputPanel extends Component { ...@@ -37,6 +38,9 @@ class CurrencyInputPanel extends Component {
initialized: PropTypes.bool, initialized: PropTypes.bool,
onCurrencySelected: PropTypes.func, onCurrencySelected: PropTypes.func,
onValueChange: PropTypes.func, onValueChange: PropTypes.func,
exchangeAddresses: PropTypes.shape({
fromToken: PropTypes.object.isRequired,
}).isRequired,
}; };
static defaultProps = { static defaultProps = {
...@@ -141,15 +145,32 @@ class CurrencyInputPanel extends Component { ...@@ -141,15 +145,32 @@ class CurrencyInputPanel extends Component {
this.props.onCurrencySelected(address); this.props.onCurrencySelected(address);
if (address && address !== 'ETH') { if (address && address !== 'ETH') {
// Add Token Contract
const { drizzle } = this.context; const { drizzle } = this.context;
const { fromToken } = this.props.exchangeAddresses;
const { web3 } = drizzle; const { web3 } = drizzle;
const contractConfig = { const tokenConfig = {
contractName: address, contractName: address,
web3Contract: new web3.eth.Contract(ERC20_ABI, address), web3Contract: new web3.eth.Contract(ERC20_ABI, address),
}; };
const events = ['Approval', 'Transfer']; const tokenEvents = ['Approval', 'Transfer'];
this.context.drizzle.addContract(contractConfig, events, { from: this.props.account }); this.context.drizzle.addContract(tokenConfig, tokenEvents, { from: this.props.account });
// Add Exchange Contract
const exchangeAddress = fromToken[address];
if (!exchangeAddress) {
return;
}
const exchangeConfig = {
contractName: exchangeAddress,
web3Contract: new web3.eth.Contract(EXCHANGE_ABI, exchangeAddress),
};
const exchangeEvents = ['Approval', 'Transfer', 'TokenPurchase', 'EthPurchase', 'AddLiquidity', 'RemoveLiquidity'];
this.context.drizzle.addContract(exchangeConfig, exchangeEvents , { from: this.props.account });
} }
}; };
...@@ -280,6 +301,7 @@ export default drizzleConnect( ...@@ -280,6 +301,7 @@ export default drizzleConnect(
return { return {
tokenAddresses: state.addresses.tokenAddresses, tokenAddresses: state.addresses.tokenAddresses,
exchangeAddresses: state.addresses.exchangeAddresses,
initialized, initialized,
balance: accountBalances[accounts[0]] || null, balance: accountBalances[accounts[0]] || null,
account: accounts[0], account: accounts[0],
......
...@@ -97,7 +97,7 @@ function Header (props) { ...@@ -97,7 +97,7 @@ function Header (props) {
isMobile() isMobile()
? ( ? (
[ [
<img src={CoinbaseWalletLogo} onClick={() => window.open(getCoinbaseWalletLink(), '_blank')} />, <img src={CoinbaseWalletLogo} key="coinbase-wallet" onClick={() => window.open(getCoinbaseWalletLink(), '_blank')} />,
<img src={TrustLogo} key="trust" onClick={() => window.open(getTrustLink(), '_blank')} /> <img src={TrustLogo} key="trust" onClick={() => window.open(getTrustLink(), '_blank')} />
] ]
) )
......
...@@ -11,11 +11,6 @@ export default class Modal extends Component { ...@@ -11,11 +11,6 @@ export default class Modal extends Component {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
}; };
constructor(props) {
super(props);
// this.el = document.createElement('div');
}
componentDidMount() { componentDidMount() {
// The portal element is inserted in the DOM tree after // The portal element is inserted in the DOM tree after
// the Modal's children are mounted, meaning that children // the Modal's children are mounted, meaning that children
......
...@@ -4,7 +4,7 @@ import EthereumLogo from '../../assets/images/ethereum-logo.png'; ...@@ -4,7 +4,7 @@ import EthereumLogo from '../../assets/images/ethereum-logo.png';
import GenericTokenLogo from '../../assets/images/generic-token-logo.png'; import GenericTokenLogo from '../../assets/images/generic-token-logo.png';
const TOKEN_ICON_API = 'https://raw.githubusercontent.com/TrustWallet/tokens/master/images'; const TOKEN_ICON_API = 'https://raw.githubusercontent.com/TrustWallet/tokens/master/images';
const BAD_IMAGES = {};
export default class TokenLogo extends Component { export default class TokenLogo extends Component {
static propTypes = { static propTypes = {
address: PropTypes.string, address: PropTypes.string,
...@@ -30,11 +30,10 @@ export default class TokenLogo extends Component { ...@@ -30,11 +30,10 @@ export default class TokenLogo extends Component {
path = EthereumLogo; path = EthereumLogo;
} }
if (!this.state.error) { if (!this.state.error && !BAD_IMAGES[address]) {
path = `${TOKEN_ICON_API}/${address}.png`; path = `${TOKEN_ICON_API}/${address}.png`;
} }
return ( return (
<img <img
src={path} src={path}
...@@ -43,7 +42,10 @@ export default class TokenLogo extends Component { ...@@ -43,7 +42,10 @@ export default class TokenLogo extends Component {
width: size, width: size,
height: size, height: size,
}} }}
onError={() => this.setState({ error: true })} onError={() => {
this.setState({ error: true });
BAD_IMAGES[address] = true;
}}
/> />
); );
} }
......
...@@ -5,26 +5,26 @@ const initialState = { ...@@ -5,26 +5,26 @@ const initialState = {
addresses: [ addresses: [
['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'], ['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'],
['DAI','0x9eb0461bcc20229bE61319372cCA84d782823FCb'], ['DAI','0x9eb0461bcc20229bE61319372cCA84d782823FCb'],
['MKR','0x4c86a3b3cf926de3644f60658071ca604949609f'], ['MKR','0x93bB63aFe1E0180d0eF100D774B473034fd60C36'],
['OMG','0x1033f09e293200de63AF16041e83000aFBBfF5c0'], ['OMG','0x26C226EBb6104676E593F8A070aD6f25cDa60F8D'],
['ZRX','0x42E109452F4055c82a513A527690F2D73251367e'] ['ZRX','0xaBD44a1D1b9Fb0F39fE1D1ee6b1e2a14916D067D'],
], ],
fromToken: { fromToken: {
'0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B': '0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d', '0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B': '0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d',
'0x2448eE2641d78CC42D7AD76498917359D961A783': '0x9eb0461bcc20229bE61319372cCA84d782823FCb', '0x2448eE2641d78CC42D7AD76498917359D961A783': '0x9eb0461bcc20229bE61319372cCA84d782823FCb',
'0xf9ba5210f91d0474bd1e1dcdaec4c58e359aad85': '0x4c86a3b3cf926de3644f60658071ca604949609f', '0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85': '0x93bB63aFe1E0180d0eF100D774B473034fd60C36',
'0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0': '0x1033f09e293200de63AF16041e83000aFBBfF5c0', '0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0': '0x26C226EBb6104676E593F8A070aD6f25cDa60F8D',
'0xF22e3F33768354c9805d046af3C0926f27741B43': '0x42E109452F4055c82a513A527690F2D73251367e', '0xF22e3F33768354c9805d046af3C0926f27741B43': '0xaBD44a1D1b9Fb0F39fE1D1ee6b1e2a14916D067D',
} },
}, },
tokenAddresses: { tokenAddresses: {
addresses: [ addresses: [
['BAT','0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B'], ['BAT','0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B'],
['DAI','0x2448eE2641d78CC42D7AD76498917359D961A783'], ['DAI','0x2448eE2641d78CC42D7AD76498917359D961A783'],
['MKR','0xf9ba5210f91d0474bd1e1dcdaec4c58e359aad85'], ['MKR','0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85'],
['OMG','0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0'], ['OMG','0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0'],
['ZRX','0xF22e3F33768354c9805d046af3C0926f27741B43'], ['ZRX','0xF22e3F33768354c9805d046af3C0926f27741B43'],
] ],
}, },
}; };
......
...@@ -5,6 +5,7 @@ const initialState = { ...@@ -5,6 +5,7 @@ const initialState = {
output: '', output: '',
inputCurrency: '', inputCurrency: '',
outputCurrency: '', outputCurrency: '',
lastEditedField: '',
}; };
export const updateField = ({ name, value }) => ({ export const updateField = ({ name, value }) => ({
......
import EXCHANGE_ABI from "../abi/exchange";
import {BigNumber as BN} from "bignumber.js"; import {BigNumber as BN} from "bignumber.js";
export const calculateExchangeRate = async ({drizzleCtx, contractStore, input, inputCurrency, outputCurrency, exchangeAddresses }) => { export const calculateExchangeRateFromInput = async opts => {
if (!inputCurrency || !outputCurrency || !input) { const { inputCurrency, outputCurrency } = opts;
return 0; if (inputCurrency === outputCurrency) {
console.error(`Input and Output currency cannot be the same`);
return;
}
if (inputCurrency === 'ETH' && outputCurrency !== 'ETH') {
return ETH_TO_ERC20.calculateOutput(opts);
} }
if (outputCurrency === 'ETH' && inputCurrency !== 'ETH') {
return ERC20_TO_ETH.calculateOutput(opts);
}
};
export const calculateExchangeRateFromOutput = async opts => {
const { inputCurrency, outputCurrency } = opts;
if (inputCurrency === outputCurrency) { if (inputCurrency === outputCurrency) {
console.error(`Input and Output currency cannot be the same`); console.error(`Input and Output currency cannot be the same`);
return 0; return;
} }
const currencies = [ inputCurrency, outputCurrency ]; if (inputCurrency === 'ETH' && outputCurrency !== 'ETH') {
const exchangeAddress = exchangeAddresses.fromToken[currencies.filter(d => d !== 'ETH')[0]]; return ETH_TO_ERC20.calculateInput(opts);
}
if (!exchangeAddress) { if (outputCurrency === 'ETH' && inputCurrency !== 'ETH') {
return 0; return ERC20_TO_ETH.calculateInput(opts);
} }
};
const ETH_TO_ERC20 = {
calculateOutput: async ({drizzleCtx, contractStore, input, inputCurrency, outputCurrency, exchangeAddresses }) => {
if (inputCurrency !== 'ETH') {
console.error('Input Currency should be ETH');
return;
}
if (!outputCurrency || outputCurrency === 'ETH') {
console.error('Output Currency should be ERC20');
return;
}
const exchangeAddress = exchangeAddresses.fromToken[outputCurrency];
if (!exchangeAddress) {
console.error(`Cannot find Exchange Address for ${outputCurrency}`);
return;
}
const inputReserve = await getBalance({
currency: inputCurrency,
address: exchangeAddress,
drizzleCtx,
contractStore,
});
const outputReserve = await getBalance({
currency: outputCurrency,
address: exchangeAddress,
drizzleCtx,
contractStore,
});
const inputAmount = BN(input).multipliedBy(BN(10 ** 18));
const numerator = inputAmount.multipliedBy(BN(outputReserve).multipliedBy(997));
const denominator = BN(inputReserve).multipliedBy(1000).plus(BN(inputAmount).multipliedBy(997));
const outputAmount = numerator.dividedBy(denominator);
const exchangeRate = outputAmount.dividedBy(inputAmount);
if (exchangeRate.isNaN()) {
return;
}
return exchangeRate;
},
calculateInput: async ({drizzleCtx, contractStore, output, inputCurrency, outputCurrency, exchangeAddresses }) => {
if (inputCurrency !== 'ETH') {
console.error('Input Currency should be ETH');
return;
}
if (!outputCurrency || outputCurrency === 'ETH') {
console.error('Output Currency should be ERC20');
return;
}
const exchangeAddress = exchangeAddresses.fromToken[outputCurrency];
if (!exchangeAddress) {
console.error(`Cannot find Exchange Address for ${outputCurrency}`);
return;
}
const inputReserve = await getBalance({
currency: inputCurrency,
address: exchangeAddress,
drizzleCtx,
contractStore,
});
const outputReserve = await getBalance({
currency: outputCurrency,
address: exchangeAddress,
drizzleCtx,
contractStore,
});
const outputDecimals = await getDecimals({ address: inputCurrency, contractStore, drizzleCtx });
const outputAmount = BN(output).multipliedBy(10 ** outputDecimals);
const numerator = outputAmount .multipliedBy(BN(inputReserve).multipliedBy(1000));
const denominator = BN(outputReserve).minus(outputAmount).multipliedBy(997);
const inputAmount = numerator.dividedBy(denominator.plus(1));
const exchangeRate = outputAmount.dividedBy(inputAmount);
if (exchangeRate.isNaN()) {
return;
}
return exchangeRate;
},
};
const ERC20_TO_ETH = {
calculateOutput: async ({drizzleCtx, contractStore, input, inputCurrency, outputCurrency, exchangeAddresses }) => {
if (outputCurrency !== 'ETH') {
console.error('Output Currency should be ETH');
return;
}
if (!inputCurrency || inputCurrency === 'ETH') {
console.error('Input Currency should be ERC20');
return;
}
const exchangeAddress = exchangeAddresses.fromToken[inputCurrency];
if (!exchangeAddress) {
console.error(`Cannot find Exchange Address for ${inputCurrency}`);
return;
}
if (currencies.includes('ETH')) {
const inputReserve = await getBalance({ const inputReserve = await getBalance({
currency: inputCurrency, currency: inputCurrency,
address: exchangeAddress, address: exchangeAddress,
...@@ -33,8 +157,7 @@ export const calculateExchangeRate = async ({drizzleCtx, contractStore, input, i ...@@ -33,8 +157,7 @@ export const calculateExchangeRate = async ({drizzleCtx, contractStore, input, i
contractStore, contractStore,
}); });
const inputDecimals = await getDecimals({ address: inputCurrency, drizzleCtx, contractStore }); const inputDecimals = await getDecimals({ address: inputCurrency, contractStore, drizzleCtx });
const outputDecimals = await getDecimals({ address: outputCurrency, drizzleCtx, contractStore });
const inputAmount = BN(input).multipliedBy(BN(10 ** inputDecimals)); const inputAmount = BN(input).multipliedBy(BN(10 ** inputDecimals));
const numerator = inputAmount.multipliedBy(BN(outputReserve).multipliedBy(997)); const numerator = inputAmount.multipliedBy(BN(outputReserve).multipliedBy(997));
const denominator = BN(inputReserve).multipliedBy(1000).plus(BN(inputAmount).multipliedBy(997)); const denominator = BN(inputReserve).multipliedBy(1000).plus(BN(inputAmount).multipliedBy(997));
...@@ -42,15 +165,60 @@ export const calculateExchangeRate = async ({drizzleCtx, contractStore, input, i ...@@ -42,15 +165,60 @@ export const calculateExchangeRate = async ({drizzleCtx, contractStore, input, i
const exchangeRate = outputAmount.dividedBy(inputAmount); const exchangeRate = outputAmount.dividedBy(inputAmount);
if (exchangeRate.isNaN()) { if (exchangeRate.isNaN()) {
return 0; return;
} }
return exchangeRate.toFixed(7); return exchangeRate;
} else { },
return 0; calculateInput: async ({drizzleCtx, contractStore, output, inputCurrency, outputCurrency, exchangeAddresses }) => {
} if (outputCurrency !== 'ETH') {
console.error('Output Currency should be ETH');
return;
}
if (!inputCurrency || inputCurrency === 'ETH') {
console.error('Output Currency should be ERC20');
return;
}
const exchangeAddress = exchangeAddresses.fromToken[inputCurrency];
if (!exchangeAddress) {
console.error(`Cannot find Exchange Address for ${inputCurrency}`);
return;
}
const inputReserve = await getBalance({
currency: inputCurrency,
address: exchangeAddress,
drizzleCtx,
contractStore,
});
const outputReserve = await getBalance({
currency: outputCurrency,
address: exchangeAddress,
drizzleCtx,
contractStore,
});
// const outputDecimals = await getDecimals({ address: inputCurrency, contractStore, drizzleCtx });
const outputAmount = BN(output).multipliedBy(10 ** 18);
const numerator = outputAmount .multipliedBy(BN(inputReserve).multipliedBy(1000));
const denominator = BN(outputReserve).minus(outputAmount).multipliedBy(997);
const inputAmount = numerator.dividedBy(denominator.plus(1));
const exchangeRate = outputAmount.dividedBy(inputAmount);
if (exchangeRate.isNaN()) {
return;
}
return exchangeRate;
},
}; };
function getDecimals({ address, drizzleCtx, contractStore }) { function getDecimals({ address, drizzleCtx, contractStore }) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (address === 'ETH') { if (address === 'ETH') {
......
// eslint-disable-next-line no-unused-escape
const SPECIAL_CHARS_REGEX = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g const SPECIAL_CHARS_REGEX = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g
export default function (text, pattern, tokenSeparator = / +/g) { export default function (text, pattern, tokenSeparator = / +/g) {
......
import Bitap from "./index";
import bitapScore from './bitap_score'; import bitapScore from './bitap_score';
import matchedIndices from './bitap_matched_indices'; import matchedIndices from './bitap_matched_indices';
......
...@@ -3,15 +3,15 @@ import { drizzleConnect } from 'drizzle-react'; ...@@ -3,15 +3,15 @@ import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import {BigNumber as BN} from "bignumber.js";
import { updateField } from '../../ducks/swap'; import { updateField } from '../../ducks/swap';
import Header from '../../components/Header'; import Header from '../../components/Header';
import CurrencyInputPanel from '../../components/CurrencyInputPanel'; import CurrencyInputPanel from '../../components/CurrencyInputPanel';
import OversizedPanel from '../../components/OversizedPanel'; import OversizedPanel from '../../components/OversizedPanel';
import ArrowDown from '../../assets/images/arrow-down-blue.svg'; import ArrowDown from '../../assets/images/arrow-down-blue.svg';
import { calculateExchangeRate } from '../../helpers/exchange-utils'; import { calculateExchangeRateFromInput, calculateExchangeRateFromOutput } from '../../helpers/exchange-utils';
import "./swap.scss"; import "./swap.scss";
import EXCHANGE_ABI from "../../abi/exchange";
class Swap extends Component { class Swap extends Component {
static propTypes = { static propTypes = {
...@@ -25,6 +25,7 @@ class Swap extends Component { ...@@ -25,6 +25,7 @@ class Swap extends Component {
output: PropTypes.string, output: PropTypes.string,
inputCurrency: PropTypes.string, inputCurrency: PropTypes.string,
outputCurrency: PropTypes.string, outputCurrency: PropTypes.string,
lastEditedField: PropTypes.string,
}; };
static contextTypes = { static contextTypes = {
...@@ -32,7 +33,7 @@ class Swap extends Component { ...@@ -32,7 +33,7 @@ class Swap extends Component {
}; };
state = { state = {
exchangeRate: 0, exchangeRate: BN(0),
}; };
getTokenLabel(address) { getTokenLabel(address) {
...@@ -62,36 +63,20 @@ class Swap extends Component { ...@@ -62,36 +63,20 @@ class Swap extends Component {
return symbol.value; return symbol.value;
} }
async updateInput(input) { updateInput(amount) {
const { this.props.updateField('input', amount);
outputCurrency, if (!amount) {
exchangeAddresses: { fromToken }, this.props.updateField('output', '');
} = this.props;
this.props.updateField('input', input);
if (!outputCurrency) {
return;
} }
this.props.updateField('lastEditedField', 'input');
}
const { drizzle } = this.context; updateOutput(amount) {
const { web3 } = drizzle; this.props.updateField('output', amount);
const exchangeAddress = fromToken[outputCurrency]; if (!amount) {
const token = drizzle.contracts[outputCurrency]; this.props.updateField('input', '');
if (!exchangeAddress || !token) {
return;
}
if (!drizzle.contracts[exchangeAddress]) {
const contractConfig = {
contractName: exchangeAddress,
web3Contract: new web3.eth.Contract(EXCHANGE_ABI, exchangeAddress),
};
const events = ['Approval', 'Transfer', 'TokenPurchase', 'EthPurchase', 'AddLiquidity', 'RemoveLiquidity'];
this.context.drizzle.addContract(contractConfig, events, { from: this.props.account });
} }
this.props.updateField('lastEditedField', 'output');
} }
async getExchangeRate(props) { async getExchangeRate(props) {
...@@ -101,18 +86,31 @@ class Swap extends Component { ...@@ -101,18 +86,31 @@ class Swap extends Component {
inputCurrency, inputCurrency,
outputCurrency, outputCurrency,
exchangeAddresses, exchangeAddresses,
lastEditedField,
contracts, contracts,
} = props; } = props;
const { drizzle } = this.context; const { drizzle } = this.context;
return await calculateExchangeRate({
drizzleCtx: drizzle, return lastEditedField === 'input'
contractStore: contracts, ? await calculateExchangeRateFromInput({
input, drizzleCtx: drizzle,
output, contractStore: contracts,
inputCurrency, input,
outputCurrency, output,
exchangeAddresses, inputCurrency,
}); outputCurrency,
exchangeAddresses,
})
: await calculateExchangeRateFromOutput({
drizzleCtx: drizzle,
contractStore: contracts,
input,
output,
inputCurrency,
outputCurrency,
exchangeAddresses,
}) ;
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
...@@ -122,7 +120,12 @@ class Swap extends Component { ...@@ -122,7 +120,12 @@ class Swap extends Component {
if (!exchangeRate) { if (!exchangeRate) {
return; return;
} }
this.props.updateField('output', `${nextProps.input * exchangeRate}`);
if (nextProps.lastEditedField === 'input') {
this.props.updateField('output', `${BN(nextProps.input).multipliedBy(exchangeRate).toFixed(7)}`);
} else if (nextProps.lastEditedField === 'output') {
this.props.updateField('input', `${BN(nextProps.output).multipliedBy(BN(1).dividedBy(exchangeRate)).toFixed(7)}`);
}
}); });
} }
...@@ -131,6 +134,12 @@ class Swap extends Component { ...@@ -131,6 +134,12 @@ class Swap extends Component {
this.props.updateField('input', ''); this.props.updateField('input', '');
this.props.updateField('outputCurrency', ''); this.props.updateField('outputCurrency', '');
this.props.updateField('inputCurrency', ''); this.props.updateField('inputCurrency', '');
this.props.updateField('lastEditedField', '');
}
onCurrencySelected(field, data) {
this.props.updateField(field, data);
// this.props
} }
render() { render() {
...@@ -162,14 +171,14 @@ class Swap extends Component { ...@@ -162,14 +171,14 @@ class Swap extends Component {
title="Output" title="Output"
description="(estimated)" description="(estimated)"
onCurrencySelected={d => this.props.updateField('outputCurrency', d)} onCurrencySelected={d => this.props.updateField('outputCurrency', d)}
onValueChange={d => this.props.updateField('output', d)} onValueChange={d => this.updateOutput(d)}
value={output} value={output}
/> />
<OversizedPanel hideBottom> <OversizedPanel hideBottom>
<div className="swap__exchange-rate-wrapper"> <div className="swap__exchange-rate-wrapper">
<span className="swap__exchange-rate">Exchange Rate</span> <span className="swap__exchange-rate">Exchange Rate</span>
<span> <span>
{exchangeRate ? `1 ${inputLabel} = ${exchangeRate} ${outputLabel}` : ' - '} {exchangeRate ? `1 ${inputLabel} = ${exchangeRate.toFixed(7)} ${outputLabel}` : ' - '}
</span> </span>
</div> </div>
</OversizedPanel> </OversizedPanel>
...@@ -218,6 +227,7 @@ export default withRouter( ...@@ -218,6 +227,7 @@ export default withRouter(
output: state.swap.output, output: state.swap.output,
inputCurrency: state.swap.inputCurrency, inputCurrency: state.swap.inputCurrency,
outputCurrency: state.swap.outputCurrency, outputCurrency: state.swap.outputCurrency,
lastEditedField: state.swap.lastEditedField,
exchangeAddresses: state.addresses.exchangeAddresses, exchangeAddresses: state.addresses.exchangeAddresses,
}), }),
dispatch => ({ dispatch => ({
...@@ -225,9 +235,3 @@ export default withRouter( ...@@ -225,9 +235,3 @@ export default withRouter(
}) })
), ),
); );
function timeout(time = 0) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
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