Newer
Older
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
import React, { Component } from 'react';
import debounce from 'debounce-promise';
import { estimateGas } from '../../utils/estimateGas';
import { Field, Form } from 'react-final-form';
import { Form as FetherForm, Header } from 'fether-ui';
import { fromWei, toWei } from '@parity/api/lib/util/wei';
import { inject, observer } from 'mobx-react';
import { isAddress } from '@parity/api/lib/util/address';
import { withProps } from 'recompose';
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('parityStore', 'sendStore', 'tokensStore')
@withProps(({ match: { params: { tokenAddress } }, tokensStore }) => ({
token: tokensStore.tokens[tokenAddress]
}))
@withBalance
@observer
class Send extends Component {
handleSubmit = event => {
event.preventDefault();
const { history, sendStore, token } = this.props;
sendStore.setTx(event);
history.push(`/send/${token.address}/signer`);
<Link to='/tokens' className='icon -close'>
Close
</Link>
title={token && <h1>Send {token.name}</h1>}
<div className='window_content'>
<div className='box -padded'>
initialValues={{ gasPrice: 4, ...tx }}
validate={this.validateForm}
render={({ handleSubmit, valid, validating, values }) => (
<form className='send-form' onSubmit={handleSubmit}>
<fieldset className='form_fields'>
<Field
className='form_field_amount'
formNoValidate
label='Amount'
name='amount'
placeholder='1.00'
render={FetherForm.Field}
required
type='number' // In ETH or coin
/>
<Field
as='textarea'
render={FetherForm.Field}
/>
<Field
centerText={`${values.gasPrice} GWEI`}
className='-range'
label='Gas'
leftText='Cheap'
max={MAX_GAS_PRICE}
min={MIN_GAS_PRICE}
name='gasPrice'
render={FetherForm.Slider}
required
rightText='Fast'
step={0.5}
type='range' // In Gwei
</fieldset>
<nav className='form-nav'>
<button
disabled={!valid || validating}
className='button'
>
{validating ? 'Checking...' : 'Send'}
</button>
</nav>
</form>
)}
/>
onClick={null} // To disable cursor:pointer on card // TODO Can this be done better?
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/**
* Estimate gas amount, and validate that the user has enough balance to make
* the tx.
*/
validateBalance = debounce(async values => {
try {
const estimated = await estimateGas(
values,
this.props.token,
this.props.parityStore.api
);
const { balance } = this.props;
if (!balance || isNaN(estimated)) {
throw new Error('No "balance" or "estimated" value.');
}
// Calculate the max amount the user can send
const maxAmount = +fromWei(
toWei(balance).minus(estimated.mul(toWei(values.gasPrice, 'shannon')))
);
if (values.amount > maxAmount) {
return { amount: "You don't have enough balance" };
}
} catch (err) {
return {
amount: 'Failed estimating balance, please try again'
};
}
}, 1000);
validateForm = values => {
if (!values.amount || isNaN(values.amount)) {
return { amount: 'Please enter a valid amount' };
}
if (values.amount < 0) {
return { amount: 'Please enter a positive amount ' };
}
if (this.props.balance && this.props.balance.lt(values.amount)) {
return { amount: "You don't have enough balance" };
}
if (!isAddress(values.to)) {
return { to: 'Please enter a valid Ethereum address' };
}
return this.validateBalance(values);
};