diff --git a/packages/light-react/src/Send/TxForm/TxForm.js b/packages/light-react/src/Send/TxForm/TxForm.js
index 932dfb3605f51e1e408d5f665db567ff4c41e70b..3c4d90b2d946ae19f19c3399083f9f468e3777d1 100644
--- a/packages/light-react/src/Send/TxForm/TxForm.js
+++ b/packages/light-react/src/Send/TxForm/TxForm.js
@@ -5,21 +5,40 @@
import React, { Component } from 'react';
import { FormField, Header } from 'light-ui';
+import { fromWei, toWei } from '@parity/api/lib/util/wei';
import { inject, observer } from 'mobx-react';
import { Link } from 'react-router-dom';
import TokenBalance from '../../Tokens/TokensList/TokenBalance';
+import withBalance from '../../utils/withBalance';
const MAX_GAS_PRICE = 40; // In Gwei
const MIN_GAS_PRICE = 3; // Safelow gas price from GasStation, in Gwei
@inject('sendStore')
+@withBalance(({ sendStore: { token } }) => token)
@observer
class Send extends Component {
componentDidMount () {
this.props.sendStore.estimateGas();
}
+ getMaxAmount = () => {
+ const {
+ balance,
+ sendStore: { estimated, tx }
+ } = this.props;
+
+ // TODO this in sendStore as @computed?
+ return balance && estimated
+ ? +fromWei(
+ toWei(balance).minus(
+ estimated.multipliedBy(toWei(tx.gasPrice, 'shannon'))
+ )
+ )
+ : 0.01;
+ };
+
handleChangeAmount = ({ target: { value } }) =>
this.props.sendStore.setTxAmount(value);
@@ -35,6 +54,8 @@ class Send extends Component {
}
};
+ handleMax = () => this.props.sendStore.setTxAmount(this.getMaxAmount());
+
handleSubmit = e => {
e.preventDefault();
const { history, sendStore } = this.props;
@@ -65,6 +86,7 @@ class Send extends Component {
@@ -94,12 +124,14 @@ class Send extends Component {
}
diff --git a/packages/light-react/src/Tokens/TokensList/TokenBalance/TokenBalance.js b/packages/light-react/src/Tokens/TokensList/TokenBalance/TokenBalance.js
index 4d4406c149adbcbafee1de5fd71a53e3f1162084..8b231f415390020cd2234b254ac2d72a8d012746 100644
--- a/packages/light-react/src/Tokens/TokensList/TokenBalance/TokenBalance.js
+++ b/packages/light-react/src/Tokens/TokensList/TokenBalance/TokenBalance.js
@@ -4,42 +4,14 @@
// SPDX-License-Identifier: MIT
import React, { Component } from 'react';
-import abi from '@parity/shared/lib/contracts/abi/eip20';
-import { empty } from 'rxjs';
-import {
- defaultAccount$,
- isNullOrLoading,
- makeContract$,
- myBalance$
-} from '@parity/light.js';
-import { filter, map, switchMap } from 'rxjs/operators';
-import { fromWei } from '@parity/api/lib/util/wei';
import { inject } from 'mobx-react';
-import light from 'light-hoc';
import PropTypes from 'prop-types';
import { TokenCard } from 'light-ui';
import { withRouter } from 'react-router-dom';
-@light({
- balance: ({ token: { address, decimals } }) => {
- if (!address) {
- return empty();
- }
- return address === 'ETH'
- ? myBalance$().pipe(
- map(value => (isNullOrLoading(value) ? null : value)),
- map(value => value && +fromWei(value))
- )
- : defaultAccount$().pipe(
- filter(x => x),
- switchMap(defaultAccount =>
- makeContract$(address, abi).balanceOf$(defaultAccount)
- ),
- map(value => (isNullOrLoading(value) ? null : value)),
- map(value => value && +value.div(10 ** decimals))
- );
- }
-})
+import withBalance from '../../../utils/withBalance';
+
+@withBalance()
@inject('sendStore')
@withRouter
class TokenBalance extends Component {
diff --git a/packages/light-react/src/stores/sendStore.js b/packages/light-react/src/stores/sendStore.js
index 5a1ac63c279d3a75294066c799c486cb506eaa8e..fea2d9938520af8d9b85ff148b2dfa73cd80ebc5 100644
--- a/packages/light-react/src/stores/sendStore.js
+++ b/packages/light-react/src/stores/sendStore.js
@@ -14,7 +14,7 @@ import { toWei } from '@parity/api/lib/util/wei';
import parityStore from './parityStore';
import tokensStore from './tokensStore';
-const DEFAULT_GAS = 21000; // Default gas amount to show
+const DEFAULT_GAS = new BigNumber(21000); // Default gas amount to show
class SendStore {
@observable blockNumber; // Current block number, used to calculate tx confirmations.
@@ -22,9 +22,9 @@ class SendStore {
@observable tokenAddress; // 'ETH', or the token contract address
@observable
tx = {
- amount: 0.01, // In Ether or in token
+ amount: '', // In Ether or in token
gasPrice: 4, // in Gwei
- to: '0x00Ae02834e91810B223E54ce3f9B7875258a1747'
+ to: ''
}; // The actual tx we are sending. No need to be observable.
@observable txStatus; // Status of the tx, see wiki for details.
@@ -106,6 +106,7 @@ class SendStore {
if (
!this.tx || // There should be a tx
!isAddress(this.tx.to) || // The address should be okay
+ !this.tx.amount ||
isNaN(this.tx.amount) ||
isNaN(this.tx.gasPrice)
) {
@@ -161,6 +162,10 @@ class SendStore {
*/
@computed
get txForEth () {
+ if (!this.isTxValid) {
+ return {};
+ }
+
return {
gasPrice: toWei(this.tx.gasPrice, 'shannon'), // shannon == gwei
to: this.tx.to,
@@ -174,6 +179,10 @@ class SendStore {
*/
@computed
get txForErc20 () {
+ if (!this.isTxValid) {
+ return {};
+ }
+
return {
args: [
this.tx.to,
@@ -222,7 +231,7 @@ class SendStore {
// Since estimateGas is not always accurate, we add a 120% factor for buffer.
const GAS_MULT_FACTOR = 1.2;
- this.estimated = +estimated * GAS_MULT_FACTOR; // Don't store as BigNumber
+ this.estimated = estimated.multipliedBy(GAS_MULT_FACTOR);
};
@action
diff --git a/packages/light-react/src/stores/tokensStore.js b/packages/light-react/src/stores/tokensStore.js
index 4e3fd24212fa5e56a12c9ab504381285a3ce63de..2c55ecffe59a5d88ed2fb1cc9d9f92754142c039 100644
--- a/packages/light-react/src/stores/tokensStore.js
+++ b/packages/light-react/src/stores/tokensStore.js
@@ -52,6 +52,7 @@ class TokensStore {
this.tokens = {
ETH: {
address: 'ETH',
+ decimals: 18,
logo: ethereumIcon,
name: 'Ethereum',
symbol: 'ETH'
diff --git a/packages/light-react/src/utils/withBalance.js b/packages/light-react/src/utils/withBalance.js
new file mode 100644
index 0000000000000000000000000000000000000000..48454daed661d996872739a0a711f24ae3ff311c
--- /dev/null
+++ b/packages/light-react/src/utils/withBalance.js
@@ -0,0 +1,50 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import abi from '@parity/shared/lib/contracts/abi/eip20';
+import { empty } from 'rxjs';
+import {
+ defaultAccount$,
+ isNullOrLoading,
+ makeContract$,
+ myBalance$
+} from '@parity/light.js';
+import { filter, map, switchMap } from 'rxjs/operators';
+import { fromWei } from '@parity/api/lib/util/wei';
+import light from 'light-hoc';
+
+/**
+ * A HOC on light.js to get the current balance.
+ *
+ * @example
+ * @withBalance
+ * class MyComponent extends React.Component{
+ *
+ * }
+ */
+export default (propsSelector = ({ token }) => token) =>
+ light({
+ balance: ownProps => {
+ // Find our token object in the props
+ const token = propsSelector(ownProps);
+
+ if (!token.address) {
+ return empty();
+ }
+ return token.address === 'ETH'
+ ? myBalance$().pipe(
+ map(value => (isNullOrLoading(value) ? null : value)), // Transform loading state to null
+ map(value => value && fromWei(value))
+ )
+ : defaultAccount$().pipe(
+ filter(x => x),
+ switchMap(defaultAccount =>
+ makeContract$(token.address, abi).balanceOf$(defaultAccount)
+ ),
+ map(value => (isNullOrLoading(value) ? null : value)), // Transform loading state to null
+ map(value => value && value.div(10 ** token.decimals))
+ );
+ }
+ });
diff --git a/packages/light-ui/src/TokenCard/TokenCard.js b/packages/light-ui/src/TokenCard/TokenCard.js
index 1af15ee5d15f904d52dd8aa2be8001309923e2e0..e1383899c0fb1bc10f5282d2e431a661ce3d3c95 100644
--- a/packages/light-ui/src/TokenCard/TokenCard.js
+++ b/packages/light-ui/src/TokenCard/TokenCard.js
@@ -30,7 +30,7 @@ const TokenCard = ({
{token.name ? token.name : }
- {Number.isFinite(balance) ? (
+ {balance ? (
{balance.toFixed(decimals)}
) : showBalance ? (
@@ -48,7 +48,6 @@ TokenCard.defaultProps = {
};
TokenCard.propTypes = {
- balance: PropTypes.number,
decimals: PropTypes.number.isRequired,
token: PropTypes.shape({
logo: PropTypes.string,