Skip to content

Commit

Permalink
Feat: Optimize gas price (#341)
Browse files Browse the repository at this point in the history
* handle send flow and exchange

* support walletconnect txs

* reorder imports

* clean up

* remmove unused import
  • Loading branch information
brunobar79 committed Feb 5, 2020
1 parent f3de0e1 commit fb180ef
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 55 deletions.
7 changes: 2 additions & 5 deletions src/hoc/withDataInit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
dataTokenOverridesInit,
} from '../redux/data';
import { explorerClearState, explorerInit } from '../redux/explorer';
import { gasClearState, gasPricesInit } from '../redux/gas';
import { gasPricesStartPolling } from '../redux/gas';
import { clearIsWalletEmpty } from '../redux/isWalletEmpty';
import { setIsWalletEthZero } from '../redux/isWalletEthZero';
import { nonceClearState } from '../redux/nonce';
Expand Down Expand Up @@ -60,8 +60,7 @@ export default Component =>
dataTokenOverridesInit,
explorerClearState,
explorerInit,
gasClearState,
gasPricesInit,
gasPricesStartPolling,
nonceClearState,
openStateSettingsLoadState,
requestsClearState,
Expand Down Expand Up @@ -92,7 +91,6 @@ export default Component =>
},
clearAccountData: ownProps => async () => {
web3ListenerClearState();
gasClearState();
const p0 = ownProps.explorerClearState();
const p1 = ownProps.dataClearState();
const p2 = ownProps.clearIsWalletEmpty();
Expand Down Expand Up @@ -120,7 +118,6 @@ export default Component =>
sentryUtils.addInfoBreadcrumb('Initialize account data');
ownProps.explorerInit();
ownProps.uniswapPairsInit();
ownProps.gasPricesInit();
ownProps.web3ListenerInit();
await ownProps.uniqueTokensRefreshState();
} catch (error) {
Expand Down
4 changes: 4 additions & 0 deletions src/hoc/withGas.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { connect } from 'react-redux';
import {
gasPricesStartPolling,
gasPricesStopPolling,
gasUpdateDefaultGasLimit,
gasUpdateGasPriceOption,
gasUpdateTxFee,
Expand All @@ -25,6 +27,8 @@ const mapStateToProps = ({

export default Component =>
connect(mapStateToProps, {
gasPricesStartPolling,
gasPricesStopPolling,
gasUpdateDefaultGasLimit,
gasUpdateGasPriceOption,
gasUpdateTxFee,
Expand Down
113 changes: 65 additions & 48 deletions src/redux/gas.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ethUnits from '../references/ethereum-units.json';
import { ethereumUtils, gasUtils } from '../utils';

// -- Constants ------------------------------------------------------------- //

const GAS_MULTIPLIER = 1.101;
const GAS_UPDATE_DEFAULT_GAS_LIMIT = 'gas/GAS_UPDATE_DEFAULT_GAS_LIMIT';
const GAS_PRICES_DEFAULT = 'gas/GAS_PRICES_DEFAULT';
const GAS_PRICES_SUCCESS = 'gas/GAS_PRICES_SUCCESS';
Expand All @@ -21,7 +21,7 @@ const GAS_UPDATE_TX_FEE = 'gas/GAS_UPDATE_TX_FEE';
const GAS_UPDATE_GAS_PRICE_OPTION = 'gas/GAS_UPDATE_GAS_PRICE_OPTION';

// -- Actions --------------------------------------------------------------- //
let getGasPricesInterval = null;
let getGasPricesTimeoutHandler = null;

const getDefaultTxFees = () => (dispatch, getState) => {
const { assets } = getState().data;
Expand All @@ -46,53 +46,55 @@ const getDefaultTxFees = () => (dispatch, getState) => {
};
};

export const gasPricesInit = () => (dispatch, getState) =>
new Promise((resolve, reject) => {
const { fallbackGasPrices, selectedGasPrice, txFees } = dispatch(
getDefaultTxFees()
);
dispatch({
payload: {
gasPrices: fallbackGasPrices,
selectedGasPrice,
txFees,
},
type: GAS_PRICES_DEFAULT,
});
export const gasPricesStartPolling = () => async (dispatch, getState) => {
const { fallbackGasPrices, selectedGasPrice, txFees } = dispatch(
getDefaultTxFees()
);
dispatch({
payload: {
gasPrices: fallbackGasPrices,
selectedGasPrice,
txFees,
},
type: GAS_PRICES_DEFAULT,
});

const getGasPrices = () =>
new Promise((fetchResolve, fetchReject) => {
const { useShortGasFormat } = getState().gas;
apiGetGasPrices()
.then(({ data }) => {
const gasPrices = parseGasPrices(data, useShortGasFormat);
dispatch({
payload: gasPrices,
type: GAS_PRICES_SUCCESS,
});
fetchResolve(true);
})
.catch(error => {
dispatch({
payload: fallbackGasPrices,
type: GAS_PRICES_FAILURE,
});
captureException(error);
fetchReject(error);
const getGasPrices = () =>
new Promise((fetchResolve, fetchReject) => {
const { useShortGasFormat } = getState().gas;
apiGetGasPrices()
.then(({ data }) => {
const adjustedGasPrices = bumpGasPrices(data);
let gasPrices = parseGasPrices(adjustedGasPrices, useShortGasFormat);
dispatch({
payload: gasPrices,
type: GAS_PRICES_SUCCESS,
});
});
return getGasPrices()
.then(() => {
clearInterval(getGasPricesInterval);
getGasPricesInterval = setInterval(getGasPrices, 15000); // 15 secs
resolve(true);
})
.catch(error => {
clearInterval(getGasPricesInterval);
getGasPricesInterval = setInterval(getGasPrices, 15000); // 15 secs
reject(error);
});
});
fetchResolve(true);
})
.catch(error => {
dispatch({
payload: fallbackGasPrices,
type: GAS_PRICES_FAILURE,
});
captureException(error);
fetchReject(error);
});
});

const gasPricesPolling = async () => {
getGasPricesTimeoutHandler && clearTimeout(getGasPricesTimeoutHandler);
try {
await getGasPrices();
// eslint-disable-next-line no-empty
} catch (e) {
} finally {
getGasPricesTimeoutHandler = setTimeout(gasPricesPolling, 15000); // 15 secs
}
};

gasPricesPolling();
};

export const gasUpdateGasPriceOption = newGasPriceOption => (
dispatch,
Expand Down Expand Up @@ -178,7 +180,22 @@ const getSelectedGasPrice = (
};
};

export const gasClearState = () => clearInterval(getGasPricesInterval);
const bumpGasPrices = data => {
const processedData = { ...data };
const gasPricesKeys = ['average', 'fast', 'fastest', 'safeLow'];
Object.keys(processedData).forEach(key => {
if (gasPricesKeys.indexOf(key) !== -1) {
processedData[key] = (
parseFloat(processedData[key]) * GAS_MULTIPLIER
).toFixed(2);
}
});
return processedData;
};

export const gasPricesStopPolling = () => () => {
getGasPricesTimeoutHandler && clearTimeout(getGasPricesTimeoutHandler);
};

// -- Reducer --------------------------------------------------------------- //
const INITIAL_STATE = {
Expand Down
6 changes: 6 additions & 0 deletions src/screens/ExchangeModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ class ExchangeModal extends Component {
chainId: PropTypes.number,
dataAddNewTransaction: PropTypes.func,
gasLimit: PropTypes.number,
gasPricesStartPolling: PropTypes.func,
gasPricesStopPolling: PropTypes.func,
gasUpdateDefaultGasLimit: PropTypes.func,
gasUpdateTxFee: PropTypes.func,
inputReserve: PropTypes.object,
Expand Down Expand Up @@ -129,6 +131,9 @@ class ExchangeModal extends Component {

componentDidMount() {
this.props.gasUpdateDefaultGasLimit(ethUnits.basic_swap);
InteractionManager.runAfterInteractions(() => {
this.props.gasPricesStartPolling();
});
}

shouldComponentUpdate = (nextProps, nextState) => {
Expand Down Expand Up @@ -236,6 +241,7 @@ class ExchangeModal extends Component {
);
}
this.props.uniswapClearCurrenciesAndReserves();
this.props.gasPricesStopPolling();
};

lastFocusedInput = null;
Expand Down
19 changes: 18 additions & 1 deletion src/screens/SendSheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import analytics from '@segment/analytics-react-native';
import { get, isEmpty, isString, toLower } from 'lodash';
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useState } from 'react';
import { Keyboard, KeyboardAvoidingView, StatusBar } from 'react-native';
import {
InteractionManager,
Keyboard,
KeyboardAvoidingView,
StatusBar,
} from 'react-native';
import { getStatusBarHeight, isIphoneX } from 'react-native-iphone-x-helper';
import { useNavigation, useNavigationParam } from 'react-navigation-hooks';
import styled from 'styled-components/primitives';
Expand Down Expand Up @@ -56,6 +61,8 @@ const SendSheet = ({
fetchData,
gasLimit,
gasPrices,
gasPricesStartPolling,
gasPricesStopPolling,
gasUpdateDefaultGasLimit,
gasUpdateGasPriceOption,
gasUpdateTxFee,
Expand Down Expand Up @@ -86,6 +93,16 @@ const SendSheet = ({
const showAssetList = isValidAddress && isEmpty(selected);
const showAssetForm = isValidAddress && !isEmpty(selected);

useEffect(() => {
InteractionManager.runAfterInteractions(() => {
gasPricesStartPolling();
});
return () => {
gasPricesStopPolling();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const sendUpdateAssetAmount = useCallback(
newAssetAmount => {
const _assetAmount = newAssetAmount.replace(/[^0-9.]/g, '');
Expand Down
9 changes: 8 additions & 1 deletion src/screens/TransactionConfirmationScreenWithData.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import lang from 'i18n-js';
import { get, isNil, omit } from 'lodash';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import { Alert, Vibration } from 'react-native';
import { Alert, InteractionManager, Vibration } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
import { compose } from 'recompact';
import { withGas, withTransactionConfirmationScreen } from '../hoc';
Expand All @@ -28,6 +28,8 @@ class TransactionConfirmationScreenWithData extends PureComponent {
static propTypes = {
dataAddNewTransaction: PropTypes.func,
gasPrices: PropTypes.object,
gasPricesStartPolling: PropTypes.func,
gasPricesStopPolling: PropTypes.func,
navigation: PropTypes.any,
removeRequest: PropTypes.func,
transactionCountNonce: PropTypes.number,
Expand All @@ -43,6 +45,10 @@ class TransactionConfirmationScreenWithData extends PureComponent {
if (openAutomatically) {
Vibration.vibrate();
}

InteractionManager.runAfterInteractions(() => {
this.props.gasPricesStartPolling();
});
}

handleConfirm = async () => {
Expand Down Expand Up @@ -207,6 +213,7 @@ class TransactionConfirmationScreenWithData extends PureComponent {

closeScreen = () => {
this.props.navigation.popToTop();
this.props.gasPricesStopPolling();
};

render = () => {
Expand Down

0 comments on commit fb180ef

Please sign in to comment.