2018-12-20 10:56:45 -08:00
|
|
|
// @flow
|
|
|
|
import { connect } from 'react-redux';
|
2018-12-21 07:44:11 -08:00
|
|
|
import eres from 'eres';
|
2019-01-09 05:14:02 -08:00
|
|
|
import { BigNumber } from 'bignumber.js';
|
2018-12-20 10:56:45 -08:00
|
|
|
|
2019-01-24 06:56:49 -08:00
|
|
|
import store from '../../config/electron-store';
|
2018-12-21 07:44:11 -08:00
|
|
|
import rpc from '../../services/api';
|
2018-12-20 10:56:45 -08:00
|
|
|
import { SendView } from '../views/send';
|
|
|
|
|
2018-12-21 07:44:11 -08:00
|
|
|
import {
|
2019-01-24 06:56:49 -08:00
|
|
|
loadZECPrice,
|
2018-12-21 07:44:11 -08:00
|
|
|
sendTransaction,
|
|
|
|
sendTransactionSuccess,
|
|
|
|
sendTransactionError,
|
2019-01-10 06:51:32 -08:00
|
|
|
resetSendTransaction,
|
2019-01-24 06:56:49 -08:00
|
|
|
validateAddressSuccess,
|
|
|
|
validateAddressError,
|
2018-12-21 07:44:11 -08:00
|
|
|
} from '../redux/modules/send';
|
|
|
|
|
2019-01-29 07:36:13 -08:00
|
|
|
import { filterObjectNullKeys } from '../utils/filter-object-null-keys';
|
2019-01-07 10:59:27 -08:00
|
|
|
|
2018-12-20 10:56:45 -08:00
|
|
|
import type { AppState } from '../types/app-state';
|
2018-12-21 07:44:11 -08:00
|
|
|
import type { Dispatch } from '../types/redux';
|
|
|
|
|
2019-01-24 11:26:03 -08:00
|
|
|
import { loadAddressesSuccess, loadAddressesError } from '../redux/modules/receive';
|
2019-01-24 06:56:49 -08:00
|
|
|
|
2018-12-21 07:44:11 -08:00
|
|
|
export type SendTransactionInput = {
|
|
|
|
from: string,
|
|
|
|
to: string,
|
2019-01-07 10:59:27 -08:00
|
|
|
amount: string,
|
2018-12-21 07:44:11 -08:00
|
|
|
fee: number,
|
|
|
|
memo: string,
|
|
|
|
};
|
2018-12-20 10:56:45 -08:00
|
|
|
|
2019-01-24 06:56:49 -08:00
|
|
|
const mapStateToProps = ({ walletSummary, sendStatus, receive }: AppState) => ({
|
2018-12-20 10:56:45 -08:00
|
|
|
balance: walletSummary.total,
|
2019-01-24 06:56:49 -08:00
|
|
|
zecPrice: sendStatus.zecPrice,
|
|
|
|
addresses: receive.addresses,
|
2018-12-21 07:44:11 -08:00
|
|
|
error: sendStatus.error,
|
|
|
|
isSending: sendStatus.isSending,
|
2019-01-10 06:51:32 -08:00
|
|
|
operationId: sendStatus.operationId,
|
2019-01-24 06:56:49 -08:00
|
|
|
isToAddressValid: sendStatus.isToAddressValid,
|
2018-12-21 07:44:11 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
|
|
|
sendTransaction: async ({
|
2019-01-24 11:26:03 -08:00
|
|
|
from, to, amount, fee, memo,
|
2018-12-21 07:44:11 -08:00
|
|
|
}: SendTransactionInput) => {
|
|
|
|
dispatch(sendTransaction());
|
|
|
|
|
2019-01-28 16:34:07 -08:00
|
|
|
// $FlowFixMe
|
2019-01-10 06:51:32 -08:00
|
|
|
const [sendErr, operationId] = await eres(
|
2019-01-07 10:59:27 -08:00
|
|
|
rpc.z_sendmany(
|
|
|
|
from,
|
|
|
|
// $FlowFixMe
|
|
|
|
[
|
|
|
|
filterObjectNullKeys({
|
|
|
|
address: to,
|
2019-01-09 05:14:02 -08:00
|
|
|
amount: new BigNumber(amount).toNumber(),
|
2019-01-07 10:59:27 -08:00
|
|
|
memo,
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
1,
|
2019-01-09 05:14:02 -08:00
|
|
|
new BigNumber(fee).toNumber(),
|
2019-01-07 10:59:27 -08:00
|
|
|
),
|
2018-12-21 07:44:11 -08:00
|
|
|
);
|
|
|
|
|
2019-01-24 06:56:49 -08:00
|
|
|
// eslint-disable-next-line max-len
|
2019-01-10 06:51:32 -08:00
|
|
|
if (sendErr || !operationId) return dispatch(sendTransactionError({ error: sendErr.message }));
|
2018-12-21 07:44:11 -08:00
|
|
|
|
2019-01-24 06:56:49 -08:00
|
|
|
/**
|
|
|
|
Output is a list of operation status objects.
|
|
|
|
[
|
|
|
|
{“operationid”: “opid-12ee…”,
|
|
|
|
“status”: “queued”},
|
|
|
|
{“operationid”: “opd-098a…”, “status”: ”executing”},
|
|
|
|
{“operationid”: “opid-9876”, “status”: ”failed”}
|
|
|
|
]
|
|
|
|
|
|
|
|
When the operation succeeds, the status object will also include the result.
|
|
|
|
{“operationid”: “opid-0e0e”, “status”:”success”, “execution_time”:”25”, “result”: {“txid”:”af3887654…”,...}}
|
|
|
|
|
|
|
|
then the promise will only be resolved when a "success" or "failure" status is obtained
|
|
|
|
*/
|
|
|
|
const interval = setInterval(async () => {
|
|
|
|
const [, status] = await eres(rpc.z_getoperationstatus());
|
|
|
|
|
|
|
|
const operationStatus = status.find(({ id }) => operationId === id);
|
|
|
|
|
|
|
|
if (operationStatus && operationStatus.status === 'success') {
|
|
|
|
clearInterval(interval);
|
2019-01-24 11:26:03 -08:00
|
|
|
dispatch(sendTransactionSuccess({ operationId: operationStatus.result.txid }));
|
2019-01-24 06:56:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (operationStatus && operationStatus.status === 'failed') {
|
|
|
|
clearInterval(interval);
|
2019-01-24 11:26:03 -08:00
|
|
|
dispatch(sendTransactionError({ error: operationStatus.error.message }));
|
2019-01-24 06:56:49 -08:00
|
|
|
}
|
|
|
|
}, 2000);
|
2018-12-21 07:44:11 -08:00
|
|
|
},
|
2019-01-10 06:51:32 -08:00
|
|
|
resetSendView: () => dispatch(resetSendTransaction()),
|
2019-01-24 06:56:49 -08:00
|
|
|
validateAddress: async ({ address }: { address: string }) => {
|
|
|
|
if (address.startsWith('z')) {
|
|
|
|
const [, validationResult] = await eres(rpc.z_validateaddress(address));
|
|
|
|
|
|
|
|
return dispatch(
|
|
|
|
validateAddressSuccess({
|
|
|
|
isValid: Boolean(validationResult && validationResult.isvalid),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const [, validationResult] = await eres(rpc.validateaddress(address));
|
|
|
|
|
|
|
|
if (validationResult) {
|
|
|
|
return dispatch(
|
|
|
|
validateAddressSuccess({
|
|
|
|
isValid: Boolean(validationResult && validationResult.isvalid),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return dispatch(validateAddressError());
|
|
|
|
},
|
|
|
|
loadAddresses: async () => {
|
|
|
|
const [zAddressesErr, zAddresses] = await eres(rpc.z_listaddresses());
|
|
|
|
|
2019-01-24 11:26:03 -08:00
|
|
|
const [tAddressesErr, transparentAddresses] = await eres(rpc.getaddressesbyaccount(''));
|
2019-01-24 06:56:49 -08:00
|
|
|
|
|
|
|
if (zAddressesErr || tAddressesErr) return dispatch(loadAddressesError({ error: 'Something went wrong!' }));
|
|
|
|
|
|
|
|
dispatch(
|
|
|
|
loadAddressesSuccess({
|
|
|
|
addresses: [...zAddresses, ...transparentAddresses],
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
loadZECPrice: () => dispatch(
|
|
|
|
loadZECPrice({
|
2019-01-28 16:34:07 -08:00
|
|
|
value: Number(store.get('ZEC_DOLLAR_PRICE')),
|
2019-01-24 06:56:49 -08:00
|
|
|
}),
|
|
|
|
),
|
2018-12-20 10:56:45 -08:00
|
|
|
});
|
|
|
|
|
2019-01-21 16:08:35 -08:00
|
|
|
// $FlowFixMe
|
2018-12-21 07:44:11 -08:00
|
|
|
export const SendContainer = connect(
|
|
|
|
mapStateToProps,
|
|
|
|
mapDispatchToProps,
|
|
|
|
)(SendView);
|