From c3164b241cc1c7e61d7b12dd1e3d4ba73f8fbcab Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Thu, 5 Jul 2018 11:32:51 +0200 Subject: [PATCH] Make tx work for tokens --- .../fether-react/src/Send/TxForm/TxForm.js | 24 ++++++----- packages/fether-react/src/stores/sendStore.js | 40 ++++--------------- .../fether-react/src/utils/estimateGas.js | 25 +++++++----- 3 files changed, 37 insertions(+), 52 deletions(-) diff --git a/packages/fether-react/src/Send/TxForm/TxForm.js b/packages/fether-react/src/Send/TxForm/TxForm.js index 52b0578d..1ad25625 100644 --- a/packages/fether-react/src/Send/TxForm/TxForm.js +++ b/packages/fether-react/src/Send/TxForm/TxForm.js @@ -126,21 +126,25 @@ class Send extends Component { */ validateAmount = debounce(async values => { try { - if (!values.amount || isNaN(values.amount)) { + const { balance, parityStore, token } = this.props; + const amount = +values.amount; + + if (!amount || isNaN(amount)) { return { amount: 'Please enter a valid amount' }; - } else if (values.amount < 0) { + } else if (amount < 0) { return { amount: 'Please enter a positive amount ' }; - } else if (this.props.balance && this.props.balance.lt(values.amount)) { + } else if (balance && balance.lt(amount)) { return { amount: "You don't have enough balance" }; } - const estimated = await estimateGas( - values, - this.props.token, - this.props.parityStore.api - ); + if (token.address !== 'ETH') { + // No need to estimate gas for tokens. + // TODO Make sure that user has enough ETH balance + return; + } + + const estimated = await estimateGas(values, token, parityStore.api); - const { balance } = this.props; if (!balance || isNaN(estimated)) { throw new Error('No "balance" or "estimated" value.'); } @@ -149,7 +153,7 @@ class Send extends Component { toWei(balance).minus(estimated.mul(toWei(values.gasPrice, 'shannon'))) ); - if (values.amount > maxAmount) { + if (amount > maxAmount) { return { amount: "You don't have enough balance" }; } } catch (err) { diff --git a/packages/fether-react/src/stores/sendStore.js b/packages/fether-react/src/stores/sendStore.js index f20c83ef..950dbd8f 100644 --- a/packages/fether-react/src/stores/sendStore.js +++ b/packages/fether-react/src/stores/sendStore.js @@ -3,22 +3,17 @@ // // SPDX-License-Identifier: BSD-3-Clause -import abi from '@parity/shared/lib/contracts/abi/eip20'; import { action, computed, observable } from 'mobx'; -import { BigNumber } from 'bignumber.js'; -import { blockNumber$, makeContract$, post$ } from '@parity/light.js'; +import { blockNumber$, post$ } from '@parity/light.js'; +import { contractForToken, txForErc20, txForEth } from '../utils/estimateGas'; import Debug from '../utils/debug'; import parityStore from './parityStore'; -import { txForErc20, txForEth } from '../utils/estimateGas'; const debug = Debug('sendStore'); -const GAS_MULT_FACTOR = 1.25; // Since estimateGas is not always accurate, we add a 33% factor for buffer. -const DEFAULT_GAS = new BigNumber(21000 * GAS_MULT_FACTOR); // Default gas amount export class SendStore { @observable blockNumber; // Current block number, used to calculate tx confirmations. - @observable estimated = DEFAULT_GAS; // Estimated gas amount for this transaction. tx = {}; // The actual tx we are sending. No need to be observable. @observable txStatus; // Status of the tx, see wiki for details. @@ -51,33 +46,18 @@ export class SendStore { return this.blockNumber - +this.txStatus.confirmed.blockNumber; } - /** - * If it's a token, then return the makeContract$ object. - */ - @computed - get contract () { - if (this.tokenAddress === 'ETH') { - return null; - } - return makeContract$(this.tokenAddress, abi); - } - /** * Create a transaction. */ send = (token, password) => { + const tx = + token.address === 'ETH' ? txForEth(this.tx) : txForErc20(this.tx, token); const send$ = token.address === 'ETH' - ? post$(txForEth(this.tx)) - : this.contract.transfer$( - ...txForErc20(this.tx, token).args, - txForErc20(this.tx, token).options - ); + ? post$(tx) + : contractForToken(token.address).transfer$(...tx.args, tx.options); - debug( - 'Sending tx.', - token.address === 'ETH' ? this.txForEth : this.txForErc20 - ); + debug('Sending tx.', tx); return new Promise((resolve, reject) => { send$.subscribe(txStatus => { @@ -98,12 +78,6 @@ export class SendStore { this.blockNumber = blockNumber; }; - @action - setEstimated = estimated => { - this.estimated = estimated.mul(GAS_MULT_FACTOR); - debug('Estimated gas,', +estimated, ', with buffer,', +this.estimated); - }; - @action setTx = tx => { this.tx = tx; diff --git a/packages/fether-react/src/utils/estimateGas.js b/packages/fether-react/src/utils/estimateGas.js index 375f119b..72ad7ec5 100644 --- a/packages/fether-react/src/utils/estimateGas.js +++ b/packages/fether-react/src/utils/estimateGas.js @@ -3,7 +3,9 @@ // // SPDX-License-Identifier: BSD-3-Clause +import abi from '@parity/shared/lib/contracts/abi/eip20'; import BigNumber from 'bignumber.js'; +import { makeContract$ } from '@parity/light.js'; import memoize from 'lodash/memoize'; import { toWei } from '@parity/api/lib/util/wei'; @@ -12,6 +14,10 @@ import Debug from './debug'; const debug = Debug('estimateGas'); const GAS_MULT_FACTOR = 1.25; // Since estimateGas is not always accurate, we add a 33% factor for buffer. +export const contractForToken = memoize(tokenAddress => + makeContract$(tokenAddress, abi) +); + /** * Estimate the amount of gas for our transaction. */ @@ -23,7 +29,7 @@ export const estimateGas = (tx, token, api) => { if (token.address === 'ETH') { return estimateGasForEth(txForEth(tx), api).then(addBuffer); } else { - return estimateGasForErc20(txForErc20(tx, token), api).then(addBuffer); + return estimateGasForErc20(txForErc20(tx, token), token).then(addBuffer); } }; @@ -31,14 +37,15 @@ export const estimateGas = (tx, token, api) => { * Estimate gas to transfer in ERC20 contract. Expensive function, so we * memoize it. */ -const estimateGasForErc20 = memoize( - txForErc20 => - this.contract.contractObject.instance.transfer.estimateGas( - txForErc20.options, - txForErc20.args - ), - JSON.stringify -); +const estimateGasForErc20 = memoize((txForErc20, token) => { + debug(`Estimating gas for tx on token contract.`, token, txForErc20); + return contractForToken( + token.address + ).contractObject.instance.transfer.estimateGas( + txForErc20.options, + txForErc20.args + ); +}, JSON.stringify); /** * Estimate gas to transfer to an ETH address. Expensive function, so we -- GitLab