diff --git a/packages/blockchain-wallet-v4-frontend/src/modals/Transactions/TransactionReport/selectors.js b/packages/blockchain-wallet-v4-frontend/src/modals/Transactions/TransactionReport/selectors.js index 65614498089..97f9763a76a 100644 --- a/packages/blockchain-wallet-v4-frontend/src/modals/Transactions/TransactionReport/selectors.js +++ b/packages/blockchain-wallet-v4-frontend/src/modals/Transactions/TransactionReport/selectors.js @@ -14,36 +14,39 @@ export const getData = (state, coin) => { } } +const reportHeaders = [ + 'date', + 'time', + 'coin', + 'type', + 'amount', + 'value_then', + 'value_now', + 'exchange_rate_then', + 'tx', + 'note' +] + const getEthData = createSelector( [selectors.core.data.eth.getTransactionHistory], dataR => { const transform = data => { - const headers = [ - 'date', - 'time', - 'type', - 'amount_btc', - 'value_then', - 'value_now', - 'exchange_rate_then', - 'tx', - 'note' - ] const transformedData = map( d => [ d.date, d.time, + 'ETH', d.type, - d.amount_btc, + d.amount, d.value_then, d.value_now, d.exchange_rate_then, - d.tx, - d.note + d.hash, + d.description ], data ) - return [headers].concat(transformedData) + return [reportHeaders].concat(transformedData) } return { csvData: dataR.map(transform).getOrElse(undefined) @@ -58,21 +61,11 @@ const getBtcData = createSelector( ], (wallet, dataR) => { const transform = data => { - const headers = [ - 'date', - 'time', - 'type', - 'amount_btc', - 'value_then', - 'value_now', - 'exchange_rate_then', - 'tx', - 'note' - ] const transformedData = map( d => [ d.date, d.time, + 'BTC', d.type, d.amount_btc, d.value_then, @@ -83,7 +76,7 @@ const getBtcData = createSelector( ], data ) - return [headers].concat(transformedData) + return [reportHeaders].concat(transformedData) } return { csvData: dataR @@ -101,21 +94,11 @@ const getBchData = createSelector( ], (notesR, dataR) => { const transform = data => { - const headers = [ - 'date', - 'time', - 'type', - 'amount_bch', - 'value_then', - 'value_now', - 'exchange_rate_then', - 'tx', - 'note' - ] const transformedData = map( d => [ d.date, d.time, + 'BCH', d.type, d.amount_bch, d.value_then, @@ -126,7 +109,7 @@ const getBchData = createSelector( ], data ) - return [headers].concat(transformedData) + return [reportHeaders].concat(transformedData) } const notes = notesR.getOrElse({}) return { diff --git a/packages/blockchain-wallet-v4/src/redux/data/btc/actionTypes.js b/packages/blockchain-wallet-v4/src/redux/data/btc/actionTypes.js index 163a773f8c0..9c80cf6cf45 100755 --- a/packages/blockchain-wallet-v4/src/redux/data/btc/actionTypes.js +++ b/packages/blockchain-wallet-v4/src/redux/data/btc/actionTypes.js @@ -48,6 +48,8 @@ export const FETCH_BTC_TRANSACTION_HISTORY_FAILURE = '@CORE.FETCH_BTC_TRANSACTION_HISTORY_FAILURE' export const CLEAR_BTC_TRANSACTION_HISTORY = '@CORE.CLEAR_BTC_TRANSACTION_HISTORY' + +// FETCH_BTC_UNSPENDABLE_BALANCE export const FETCH_BTC_UNSPENDABLE_BALANCE_LOADING = '@CORE.FETCH_BTC_UNSPENDABLE_BALANCE_LOADING' export const FETCH_BTC_UNSPENDABLE_BALANCE_SUCCESS = diff --git a/packages/blockchain-wallet-v4/src/redux/data/eth/actionTypes.js b/packages/blockchain-wallet-v4/src/redux/data/eth/actionTypes.js index f17b74a193a..7f71437280a 100755 --- a/packages/blockchain-wallet-v4/src/redux/data/eth/actionTypes.js +++ b/packages/blockchain-wallet-v4/src/redux/data/eth/actionTypes.js @@ -2,16 +2,19 @@ // ETH // +// DATA export const FETCH_ETH_DATA = '@CORE.FETCH_ETH_DATA' export const FETCH_ETH_DATA_LOADING = '@CORE.FETCH_ETH_DATA_LOADING' export const FETCH_ETH_DATA_SUCCESS = '@CORE.FETCH_ETH_DATA_SUCCESS' export const FETCH_ETH_DATA_FAILURE = '@CORE.FETCH_ETH_DATA_FAILURE' +// FEES export const FETCH_ETH_FEE = '@CORE.FETCH_ETH_FEE' export const FETCH_ETH_FEE_LOADING = '@CORE.FETCH_ETH_FEE_LOADING' export const FETCH_ETH_FEE_SUCCESS = '@CORE.FETCH_ETH_FEE_SUCCESS' export const FETCH_ETH_FEE_FAILURE = '@CORE.FETCH_ETH_FEE_FAILURE' +// BLOCKS export const FETCH_ETH_LATEST_BLOCK = '@CORE.FETCH_ETH_LATEST_BLOCK' export const FETCH_ETH_LATEST_BLOCK_LOADING = '@CORE.FETCH_ETH_LATEST_BLOCK_LOADING' @@ -20,6 +23,7 @@ export const FETCH_ETH_LATEST_BLOCK_SUCCESS = export const FETCH_ETH_LATEST_BLOCK_FAILURE = '@CORE.FETCH_ETH_LATEST_BLOCK_FAILURE' +// BALANCES export const FETCH_ETH_CURRENT_BALANCE = '@CORE.FETCH_ETH_CURRENT_BALANCE' export const FETCH_ETH_CURRENT_BALANCE_LOADING = '@CORE.FETCH_ETH_CURRENT_BALANCE_LOADING' @@ -28,6 +32,7 @@ export const FETCH_ETH_CURRENT_BALANCE_SUCCESS = export const FETCH_ETH_CURRENT_BALANCE_FAILURE = '@CORE.FETCH_ETH_CURRENT_BALANCE_FAILURE' +// LEGACY BALANCES export const FETCH_ETH_LEGACY_BALANCE = '@CORE.FETCH_ETH_LEGACY_BALANCE' export const FETCH_ETH_LEGACY_BALANCE_LOADING = '@CORE.FETCH_ETH_LEGACY_BALANCE_LOADING' @@ -36,11 +41,13 @@ export const FETCH_ETH_LEGACY_BALANCE_SUCCESS = export const FETCH_ETH_LEGACY_BALANCE_FAILURE = '@CORE.FETCH_ETH_LEGACY_BALANCE_FAILURE' +// RATES export const FETCH_ETH_RATES = '@CORE.FETCH_ETH_RATES' export const FETCH_ETH_RATES_LOADING = '@CORE.FETCH_ETH_RATES_LOADING' export const FETCH_ETH_RATES_SUCCESS = '@CORE.FETCH_ETH_RATES_SUCCESS' export const FETCH_ETH_RATES_FAILURE = '@CORE.FETCH_ETH_RATES_FAILURE' +// TRANSACTIONS export const FETCH_ETH_TRANSACTIONS = '@CORE.FETCH_ETH_TRANSACTIONS' export const FETCH_ETH_TRANSACTIONS_LOADING = '@CORE.FETCH_ETH_TRANSACTIONS_LOADING' @@ -48,12 +55,20 @@ export const FETCH_ETH_TRANSACTIONS_SUCCESS = '@CORE.FETCH_ETH_TRANSACTIONS_SUCCESS' export const FETCH_ETH_TRANSACTIONS_FAILURE = '@CORE.FETCH_ETH_TRANSACTIONS_FAILURE' +export const ETH_TRANSACTIONS_AT_BOUND = '@CORE.ETH_TRANSACTIONS_AT_BOUND' +// TRANSACTION HISTORY export const FETCH_ETH_TRANSACTION_HISTORY = '@CORE.FETCH_ETH_TRANSACTION_HISTORY' - -export const ETH_TRANSACTIONS_AT_BOUND = '@CORE.ETH_TRANSACTIONS_AT_BOUND' - +export const FETCH_ETH_TRANSACTION_HISTORY_LOADING = + '@CORE.FETCH_ETH_TRANSACTION_HISTORY_LOADING' +export const FETCH_ETH_TRANSACTION_HISTORY_SUCCESS = + '@CORE.FETCH_ETH_TRANSACTION_HISTORY_SUCCESS' +export const FETCH_ETH_TRANSACTION_HISTORY_FAILURE = + '@CORE.FETCH_ETH_TRANSACTION_HISTORY_FAILURE' +export const CLEAR_ETH_TRANSACTION_HISTORY = '@CORE.CLEAR_TRANSACTION_HISTORY' + +// LOW BALANCE export const CHECK_LOW_ETH_BALANCE = '@CORE.CHECK_LOW_ETH_BALANCE' export const CHECK_LOW_ETH_BALANCE_SUCCESS = '@CORE.CHECK_LOW_ETH_BALANCE_SUCCESS' diff --git a/packages/blockchain-wallet-v4/src/redux/data/eth/actions.js b/packages/blockchain-wallet-v4/src/redux/data/eth/actions.js index 8fe150ca842..d62d21b39e5 100755 --- a/packages/blockchain-wallet-v4/src/redux/data/eth/actions.js +++ b/packages/blockchain-wallet-v4/src/redux/data/eth/actions.js @@ -4,6 +4,7 @@ import * as AT from './actionTypes' // ETH // +// DATA export const fetchData = () => ({ type: AT.FETCH_ETH_DATA }) export const fetchDataLoading = () => ({ type: AT.FETCH_ETH_DATA_LOADING @@ -17,6 +18,7 @@ export const fetchDataFailure = error => ({ payload: error }) +// FEES export const fetchFee = () => ({ type: AT.FETCH_ETH_FEE }) export const fetchFeeLoading = () => ({ type: AT.FETCH_ETH_FEE_LOADING }) export const fetchFeeSuccess = data => ({ @@ -28,6 +30,7 @@ export const fetchFeeFailure = error => ({ payload: error }) +// BLOCKS export const fetchLatestBlock = () => ({ type: AT.FETCH_ETH_LATEST_BLOCK }) @@ -43,6 +46,7 @@ export const fetchLatestBlockFailure = error => ({ payload: error }) +// BALANCES export const fetchCurrentBalance = () => ({ type: AT.FETCH_ETH_CURRENT_BALANCE }) @@ -58,6 +62,7 @@ export const fetchCurrentBalanceFailure = error => ({ payload: error }) +// LEGACY BALANCES export const fetchLegacyBalance = () => ({ type: AT.FETCH_ETH_LEGACY_BALANCE }) @@ -73,6 +78,7 @@ export const fetchLegacyBalanceFailure = error => ({ payload: error }) +// RATES export const fetchRates = () => ({ type: AT.FETCH_ETH_RATES }) export const fetchRatesLoading = () => ({ type: AT.FETCH_ETH_RATES_LOADING @@ -86,6 +92,7 @@ export const fetchRatesFailure = error => ({ payload: error }) +// TRANSACTIONS export const fetchTransactions = (address, reset) => ({ type: AT.FETCH_ETH_TRANSACTIONS, payload: { address, reset } @@ -102,16 +109,32 @@ export const fetchTransactionsFailure = error => ({ type: AT.FETCH_ETH_TRANSACTIONS_FAILURE, payload: error }) +export const transactionsAtBound = payload => ({ + type: AT.ETH_TRANSACTIONS_AT_BOUND, + payload +}) +// TRANSACTION HISTORY export const fetchTransactionHistory = (address, startDate, endDate) => ({ type: AT.FETCH_ETH_TRANSACTION_HISTORY, payload: { address, endDate, startDate } }) - -export const transactionsAtBound = payload => ({ - type: AT.ETH_TRANSACTIONS_AT_BOUND, - payload +export const fetchTransactionHistoryLoading = () => ({ + type: AT.FETCH_ETH_TRANSACTION_HISTORY_LOADING +}) +export const fetchTransactionHistorySuccess = data => ({ + type: AT.FETCH_ETH_TRANSACTION_HISTORY_SUCCESS, + payload: data }) +export const fetchTransactionHistoryFailure = error => ({ + type: AT.FETCH_ETH_TRANSACTION_HISTORY_FAILURE, + payload: error +}) +export const clearTransactionHistory = () => ({ + type: AT.CLEAR_ETH_TRANSACTION_HISTORY +}) + +// LOW BALANCE export const checkLowEthBalance = () => ({ type: AT.CHECK_LOW_ETH_BALANCE }) diff --git a/packages/blockchain-wallet-v4/src/redux/data/eth/reducers.js b/packages/blockchain-wallet-v4/src/redux/data/eth/reducers.js index 69f43285f1f..361a04e8ac9 100755 --- a/packages/blockchain-wallet-v4/src/redux/data/eth/reducers.js +++ b/packages/blockchain-wallet-v4/src/redux/data/eth/reducers.js @@ -163,6 +163,18 @@ export default (state = INITIAL_STATE, action) => { case AT.ETH_TRANSACTIONS_AT_BOUND: { return assocPath(['transactions_at_bound', 'eth'], payload, state) } + case AT.FETCH_ETH_TRANSACTION_HISTORY_LOADING: { + return assoc('transaction_history', Remote.Loading, state) + } + case AT.FETCH_ETH_TRANSACTION_HISTORY_SUCCESS: { + return assoc('transaction_history', Remote.Success(payload), state) + } + case AT.FETCH_ETH_TRANSACTION_HISTORY_FAILURE: { + return assoc('transaction_history', Remote.Failure(payload), state) + } + case AT.CLEAR_ETH_TRANSACTION_HISTORY: { + return assoc('transaction_history', Remote.NotAsked, state) + } case AT.CHECK_LOW_ETH_BALANCE_SUCCESS: { return assoc('warn_low_eth_balance', payload, state) } diff --git a/packages/blockchain-wallet-v4/src/redux/data/eth/sagas.js b/packages/blockchain-wallet-v4/src/redux/data/eth/sagas.js index 7ddc9981ba7..98bb8ec29a0 100755 --- a/packages/blockchain-wallet-v4/src/redux/data/eth/sagas.js +++ b/packages/blockchain-wallet-v4/src/redux/data/eth/sagas.js @@ -9,18 +9,22 @@ import { call, put, select, take } from 'redux-saga/effects' import { concat, dissoc, + filter, head, isNil, + join, length, map, mapObjIndexed, path, prop, sum, + takeLast, toUpper, values } from 'ramda' import { getLockboxEthContext } from '../../kvStore/lockbox/selectors' +import moment from 'moment' const { calculateEthTxFee, transformTx, transformErc20Tx } = transactions.eth const TX_PER_PAGE = 40 @@ -113,16 +117,58 @@ export default ({ api }) => { } const fetchTransactionHistory = function * (action) { + const { payload } = action + const { address, endDate, startDate } = payload try { - const { payload } = action - const { address, endDate, startDate } = payload + yield put(A.fetchTransactionHistoryLoading()) const defaultAccountR = yield select(selectors.kvStore.eth.getContext) const ethAddress = address || defaultAccountR.getOrFail(CONTEXT_FAILURE) - console.info(ethAddress, endDate, startDate) // eslint-disable-line no-console + // TODO: loop and ensure all transactions are fetched + const data = yield call(api.getEthTransactions, ethAddress, 0) + const rawTxs = path([ethAddress, 'txns'], data) + const txs = yield call(__processReportTxs, rawTxs, startDate, endDate) + yield put(A.fetchTransactionHistorySuccess(txs)) } catch (e) { - console.info('error') // eslint-disable-line no-console + yield put(A.fetchTransactionHistoryFailure(e.message)) } } + const __processReportTxs = function * (rawTxList, startDate, endDate) { + const fullTxList = yield call(__processTxs, rawTxList) + // remove txs that are ERC20 or not within date range + let prunedTxs = filter( + tx => !tx.erc20 && moment.unix(tx.time).isBetween(startDate, endDate), + fullTxList + ) + // build model for report + return map( + tx => ({ + amount: Exchange.convertEtherToEther({ + value: tx.amount, + fromUnit: 'WEI', + toUnit: 'ETH' + }).value, + date: moment.unix(tx.time).format('YYYY-MM-DD'), + description: tx.description, + hash: tx.hash, + time: join( + ' ', + takeLast( + 2, + moment + .unix(tx.time) + .toString() + .split(' ') + ) + ), + type: tx.type, + value_then: '?', + value_now: '?', + exchange_rate_then: '?' + }), + prunedTxs + ) + } + const __processTxs = function * (txs) { const accountsR = yield select(kvStoreSelectors.getAccounts) const erc20ContractsR = yield select(kvStoreSelectors.getErc20ContractAddrs)