// Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity. If not, see . import BigNumber from 'bignumber.js'; import { outTransaction } from '~/api/format/output'; import { trackRequest as trackRequestUtil, parseTransactionReceipt } from '~/util/tx'; import SavedRequests from '~/views/Application/Requests/savedRequests'; const savedRequests = new SavedRequests(); export const init = (api) => (dispatch) => { api.subscribe('parity_postTransaction', (error, request) => { if (error) { return console.error(error); } dispatch(watchRequest(request)); }); api.once('connected', () => { savedRequests.load(api).then((requests) => { requests.forEach((request) => dispatch(watchRequest(request))); }); }); }; export const watchRequest = (request) => (dispatch, getState) => { const { requestId } = request; // Convert value to BigNumber request.transaction = outTransaction(request.transaction); dispatch(setRequest(requestId, request)); dispatch(trackRequest(requestId, request)); }; export const trackRequest = (requestId, { transactionHash = null } = {}) => (dispatch, getState) => { const { api } = getState(); trackRequestUtil(api, { requestId, transactionHash }, (error, _data = {}) => { const data = { ..._data }; if (error) { console.error(error); return dispatch(setRequest(requestId, { error })); } // Hide the request after 6 mined blocks if (data.transactionReceipt) { const { transactionReceipt } = data; const { requests } = getState(); const requestData = requests[requestId]; let blockSubscriptionId = -1; // Set the block height to 0 at the beggining data.blockHeight = new BigNumber(0); // If the request was a contract deployment, // then add the contract with the saved metadata to the account if (requestData.metadata && requestData.metadata.deployment) { const { metadata } = requestData; const options = { ...requestData.transaction, metadata }; parseTransactionReceipt(api, options, data.transactionReceipt) .then((contractAddress) => { // No contract address given, might need some confirmations // from the wallet owners... if (!contractAddress || /^(0x)?0*$/.test(contractAddress)) { return false; } metadata.blockNumber = data.transactionReceipt ? data.transactionReceipt.blockNumber.toNumber() : null; const prevRequest = getState().requests[requestId]; const nextTransaction = { ...prevRequest.transaction, creates: contractAddress }; dispatch(setRequest(requestId, { transaction: nextTransaction })); return Promise.all([ api.parity.setAccountName(contractAddress, metadata.name), api.parity.setAccountMeta(contractAddress, metadata) ]); }) .catch((error) => { console.error(error); }); } api .subscribe('eth_blockNumber', (error, blockNumber) => { if (error || !blockNumber) { return; } // Transaction included in `blockHeight` blocks const blockHeight = blockNumber.minus(transactionReceipt.blockNumber).plus(1); const nextData = { blockHeight }; // Hide the transaction after 6 blocks if (blockHeight.gt(6)) { return dispatch(hideRequest(requestId)); } return dispatch(setRequest(requestId, nextData, false)); }) .then((subId) => { blockSubscriptionId = subId; return dispatch(setRequest(requestId, { blockSubscriptionId }, false)); }); } return dispatch(setRequest(requestId, data)); }); }; export const hideRequest = (requestId) => (dispatch, getState) => { const { api, requests } = getState(); const request = requests[requestId]; dispatch(setRequest(requestId, { show: false })); // Delete it if an error occured or if completed if (request.error || request.transactionReceipt) { // Wait for the animation to be done to delete the request setTimeout(() => { dispatch(deleteRequest(requestId)); }, 1000); } // Unsubscribe to eth-blockNumber if subscribed if (request.blockSubscriptionId) { api.unsubscribe(request.blockSubscriptionId); dispatch(setRequest(requestId, { blockSubscriptionId: null }, false)); } }; export const setRequest = (requestId, requestData, autoSetShow = true) => { if (autoSetShow && requestData.show === undefined) { requestData.show = true; } savedRequests.save(requestId, requestData); return { type: 'setRequest', requestId, requestData }; }; export const deleteRequest = (requestId) => { savedRequests.remove(requestId); return { type: 'deleteRequest', requestId }; };