diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/index.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/index.js index 016c3392877..e4b5316282d 100644 --- a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/index.js +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/index.js @@ -18,12 +18,12 @@ class BchBalance extends React.PureComponent { componentWillMount () { if (Remote.NotAsked.is(this.props.data)) { - this.props.actions.fetchData(this.props.context) + this.props.actions.fetchSpendableBalance(this.props.context) } } handleRefresh () { - this.props.actions.fetchData(this.props.context) + this.props.actions.fetchSpendableBalance(this.props.context) } render () { diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/selectors.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/selectors.js index ccafd34d21d..32b23fe0aea 100644 --- a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/selectors.js +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchBalance/selectors.js @@ -1,3 +1,3 @@ import { selectors } from 'data' -export const getData = selectors.core.data.bch.getBalance +export const getData = selectors.core.data.bch.getSpendableBalance diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/index.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/index.js new file mode 100644 index 00000000000..906f1ff15ad --- /dev/null +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/index.js @@ -0,0 +1,53 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { bindActionCreators } from 'redux' + +import { Remote } from 'blockchain-wallet-v4/src' +import { actions } from 'data' +import { getData } from './selectors' +import Error from './template.error' +import Loading from './template.loading' +import Success from './template.success' + +class BchWatchOnlyBalance extends React.PureComponent { + constructor (props) { + super(props) + this.handleRefresh = this.handleRefresh.bind(this) + } + + componentWillMount () { + if (Remote.NotAsked.is(this.props.data)) { + this.props.actions.fetchUnspendableBalance(this.props.context) + } + } + + handleRefresh () { + this.props.actions.fetchUnspendableBalance(this.props.context) + } + + render () { + const { data, large } = this.props + + return data.cata({ + Success: (value) => , + Failure: (message) => , + Loading: () => , + NotAsked: () => + }) + } +} + +BchWatchOnlyBalance.propTypes = { + context: PropTypes.string.isRequired +} + +const mapStateToProps = (state) => ({ + data: getData(state) +}) + +const mapDispatchToProps = (dispatch) => ({ + actions: bindActionCreators(actions.core.data.bch, dispatch) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(BchWatchOnlyBalance) diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/selectors.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/selectors.js new file mode 100644 index 00000000000..ee431f53a90 --- /dev/null +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/selectors.js @@ -0,0 +1,3 @@ +import { selectors } from 'data' + +export const getData = selectors.core.data.bch.getUnspendableBalance diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.error.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.error.js new file mode 100644 index 00000000000..92dd7adf455 --- /dev/null +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.error.js @@ -0,0 +1,22 @@ +import React from 'react' +import styled from 'styled-components' +import { FormattedMessage } from 'react-intl' +import { Link } from 'blockchain-info-components' + +const Wrapper = styled.div` + display: flex; + box-sizing: border-box; + justify-content: flex-end; + padding-right: 25px; +` +const ErrorLink = styled(Link)` + text-decoration: underline; +` + +export default (props) => ( + + props.onRefresh()}> + + + +) diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.loading.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.loading.js new file mode 100644 index 00000000000..861608801ed --- /dev/null +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.loading.js @@ -0,0 +1,21 @@ +import React from 'react' +import styled from 'styled-components' + +import { FlatLoader } from 'blockchain-info-components' + +const Wrapper = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 5px; + box-sizing: border-box; +` + +export default (props) => { + return ( + + + + ) +} diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.success.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.success.js new file mode 100644 index 00000000000..5700ebf018a --- /dev/null +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/BchWatchOnlyBalance/template.success.js @@ -0,0 +1,46 @@ +import React from 'react' +import PropTypes from 'prop-types' +import styled from 'styled-components' +import FiatDisplay from 'components/Display/FiatDisplay' +import { LinkContainer } from 'react-router-bootstrap' +import { FormattedMessage } from 'react-intl' +import { Banner, Text } from 'blockchain-info-components' + +const Wrapper = styled.div` + display: inline-flex; + flex-direction: row; + align-items: center; + padding-left: 5px; + margin-bottom: 10px; + padding-right: ${props => props.large ? '15px' : '25px'}; + > div:last-child { + margin-left: 10px; + > div { + color: ${props => props.theme['gray-3']} + } + } +` + +const Success = props => { + const { balance } = props + + return ( + + + BCH + + {balance} + + + + + + + ) +} + +Success.propTypes = { + balance: PropTypes.number.isRequired +} + +export default Success diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/TotalBalance/selectors.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/TotalBalance/selectors.js index 8a10171ea13..393de9a6b30 100644 --- a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/TotalBalance/selectors.js +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/TotalBalance/selectors.js @@ -5,8 +5,8 @@ import * as Currency from 'blockchain-wallet-v4/src/exchange/currency' export const getData = (state) => { const btcBalanceR = selectors.core.data.bitcoin.getSpendableBalance(state) + const bchBalanceR = selectors.core.data.bch.getSpendableBalance(state) const ethBalanceR = selectors.core.data.ethereum.getBalance(state) - const bchBalanceR = selectors.core.data.bch.getBalance(state) const btcBalance = btcBalanceR.getOrElse(0) const ethBalance = ethBalanceR.getOrElse(0) const bchBalance = bchBalanceR.getOrElse(0) diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/index.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/index.js index f0601fb079b..badb8bef7c1 100644 --- a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/index.js +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/index.js @@ -12,7 +12,13 @@ class Balance extends React.PureComponent { render () { const { data } = this.props return data.cata({ - Success: (value) => , + Success: (value) => , Failure: (message) => {message}, Loading: () => , NotAsked: () => diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/selectors.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/selectors.js index ae35f3ab196..6eec009537d 100644 --- a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/selectors.js +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/selectors.js @@ -1,20 +1,17 @@ import { Remote } from 'blockchain-wallet-v4/src' import { selectors } from 'data' -import { filter, reject, prop, lift } from 'ramda' +import { lift } from 'ramda' export const getData = (state) => { const ethContextR = selectors.core.kvStore.ethereum.getContext(state) - const bchContextR = Remote.of(selectors.core.kvStore.bch.getContext(state)) - const btcActiveAccountsR = selectors.core.common.btc.getActiveHDAccounts(state) - const btcActiveAddressesR = selectors.core.common.btc.getActiveAddresses(state) + const btcContextR = Remote.of(selectors.core.wallet.getSpendableContext(state)) + const bchContextR = Remote.of(selectors.core.kvStore.bch.getSpendableContext(state)) + const btcUnspendableContextR = Remote.of(selectors.core.wallet.getUnspendableContext(state)) + const bchUnspendableContextR = Remote.of(selectors.core.kvStore.bch.getUnspendableContext(state)) const path = state.router.location.pathname - const transform = lift((btcActiveAddresses, btcActiveAccounts, ethContext, bchContext) => { - const spendable = (a) => a.priv - const accounts = btcActiveAccounts.map(prop('xpub')) - const btcUnspendableContext = reject(spendable, btcActiveAddresses).map(prop('addr')) - const btcSpendableContext = filter(spendable, btcActiveAddresses).map(prop('addr')).concat(accounts) - return {btcSpendableContext, btcUnspendableContext, ethContext, bchContext, path} + const transform = lift((btcContext, ethContext, bchContext, btcUnspendableContext, bchUnspendableContext) => { + return {btcContext, ethContext, bchContext, btcUnspendableContext, bchUnspendableContext, path} }) - return transform(btcActiveAddressesR, btcActiveAccountsR, ethContextR, bchContextR) + return transform(btcContextR, ethContextR, bchContextR, btcUnspendableContextR, bchUnspendableContextR) } diff --git a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/template.success.js b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/template.success.js index 3359c458ede..72111ae5b86 100644 --- a/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/template.success.js +++ b/packages/blockchain-wallet-v4-frontend/src/layouts/Wallet/MenuTop/Balance/template.success.js @@ -6,6 +6,7 @@ import BtcBalance from './BtcBalance' import EthBalance from './EthBalance' import BchBalance from './BchBalance' import BtcWatchOnlyBalance from './BtcWatchOnlyBalance' +import BchWatchOnlyBalance from './BchWatchOnlyBalance' import { FormattedMessage } from 'react-intl' import { ComponentDropdown, Separator, Text } from 'blockchain-info-components' @@ -64,9 +65,14 @@ const BalanceDropdown = styled.div` position: relative; } ` +const SubItems = styled.div` + display: flex; + align-items: flex-end; + flex-direction: column; +` const Success = props => { - const { btcContext, ethContext, bchContext, btcUnspendableContext, path } = props + const { btcContext, ethContext, bchContext, btcUnspendableContext, bchUnspendableContext, path } = props const getComponentOrder = () => { switch (path) { @@ -87,10 +93,11 @@ const Success = props => { } const getSubBalances = () => { - return btcUnspendableContext.length ? + return btcUnspendableContext.length || bchUnspendableContext.length ? - : null + + : null } return ( diff --git a/packages/blockchain-wallet-v4-frontend/src/scenes/Home/BalancesChart/selectors.js b/packages/blockchain-wallet-v4-frontend/src/scenes/Home/BalancesChart/selectors.js index 1f40cfa1b8e..139bc438d15 100644 --- a/packages/blockchain-wallet-v4-frontend/src/scenes/Home/BalancesChart/selectors.js +++ b/packages/blockchain-wallet-v4-frontend/src/scenes/Home/BalancesChart/selectors.js @@ -5,8 +5,8 @@ import { Color } from 'blockchain-info-components' export const getData = (state) => { const btcBalanceR = selectors.core.data.bitcoin.getSpendableBalance(state) + const bchBalanceR = selectors.core.data.bch.getSpendableBalance(state) const ethBalanceR = selectors.core.data.ethereum.getBalance(state) - const bchBalanceR = selectors.core.data.bch.getBalance(state) const btcBalance = btcBalanceR.getOrElse(0) const ethBalance = ethBalanceR.getOrElse(0) const bchBalance = bchBalanceR.getOrElse(0) diff --git a/packages/blockchain-wallet-v4/src/redux/data/bch/actionTypes.js b/packages/blockchain-wallet-v4/src/redux/data/bch/actionTypes.js index f27555f3b79..87a63e0f718 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/bch/actionTypes.js +++ b/packages/blockchain-wallet-v4/src/redux/data/bch/actionTypes.js @@ -29,3 +29,15 @@ export const FETCH_BCH_TRANSACTION_HISTORY = '@CORE.FETCH_BCH_TRANSACTION_HISTOR export const FETCH_BCH_TRANSACTION_HISTORY_LOADING = '@CORE.FETCH_BCH_TRANSACTION_HISTORY_LOADING' export const FETCH_BCH_TRANSACTION_HISTORY_SUCCESS = '@CORE.FETCH_BCH_TRANSACTION_HISTORY_SUCCESS' export const FETCH_BCH_TRANSACTION_HISTORY_FAILURE = '@CORE.FETCH_BCH_TRANSACTION_HISTORY_FAILURE' + +// FETCH_BCH_TRANSACTION_HISTORY +export const FETCH_BCH_SPENDABLE_BALANCE = '@CORE.FETCH_BCH_SPENDABLE_BALANCE' +export const FETCH_BCH_SPENDABLE_BALANCE_LOADING = '@CORE.FETCH_BCH_SPENDABLE_BALANCE_LOADING' +export const FETCH_BCH_SPENDABLE_BALANCE_SUCCESS = '@CORE.FETCH_BCH_SPENDABLE_BALANCE_SUCCESS' +export const FETCH_BCH_SPENDABLE_BALANCE_FAILURE = '@CORE.FETCH_BCH_SPENDABLE_BALANCE_FAILURE' + +// FETCH_BCH_TRANSACTION_HISTORY +export const FETCH_BCH_UNSPENDABLE_BALANCE = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE' +export const FETCH_BCH_UNSPENDABLE_BALANCE_LOADING = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE_LOADING' +export const FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS' +export const FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE' diff --git a/packages/blockchain-wallet-v4/src/redux/data/bch/actions.js b/packages/blockchain-wallet-v4/src/redux/data/bch/actions.js index d535cc1d0f9..3c308e38be2 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/bch/actions.js +++ b/packages/blockchain-wallet-v4/src/redux/data/bch/actions.js @@ -31,3 +31,14 @@ export const fetchTransactionHistory = (address, start, end) => ({ type: AT.FETC export const fetchTransactionHistoryLoading = () => ({ type: AT.FETCH_BCH_TRANSACTION_HISTORY_LOADING }) export const fetchTransactionHistorySuccess = (data) => ({ type: AT.FETCH_BCH_TRANSACTION_HISTORY_SUCCESS, payload: data }) export const fetchTransactionHistoryFailure = (error) => ({ type: AT.FETCH_BCH_TRANSACTION_HISTORY_FAILURE, payload: error }) + +export const fetchSpendableBalance = (context) => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE, payload: { context } }) +export const fetchSpendableBalanceLoading = () => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE_LOADING }) +export const fetchSpendableBalanceSuccess = (data) => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE_SUCCESS, payload: data }) +export const fetchSpendableBalanceFailure = (error) => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE_FAILURE, payload: error }) + +// FETCH_BCH_UNSPENDABLE_BALANCE +export const fetchUnspendableBalance = (context) => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE, payload: { context } }) +export const fetchUnspendableBalanceLoading = () => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE_LOADING }) +export const fetchUnspendableBalanceSuccess = (data) => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS, payload: data }) +export const fetchUnspendableBalanceFailure = (error) => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE, payload: error }) diff --git a/packages/blockchain-wallet-v4/src/redux/data/bch/reducers.js b/packages/blockchain-wallet-v4/src/redux/data/bch/reducers.js index 6f8a72a96e3..7b1bb04e6ce 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/bch/reducers.js +++ b/packages/blockchain-wallet-v4/src/redux/data/bch/reducers.js @@ -9,6 +9,8 @@ const INITIAL_STATE = { latest_block: Remote.NotAsked, rates: Remote.NotAsked, transactions: [], + spendable_balance: Remote.NotAsked, + unspendable_balance: Remote.NotAsked, transaction_history: Remote.NotAsked } @@ -87,6 +89,28 @@ const bchReducer = (state = INITIAL_STATE, action) => { case AT.FETCH_BCH_TRANSACTION_HISTORY_FAILURE: { return assoc('transaction_history', Remote.Failure(payload), state) } + case AT.FETCH_BCH_SPENDABLE_BALANCE_LOADING: { + return assoc('spendable_balance', Remote.Loading, state) + } + case AT.FETCH_BCH_SPENDABLE_BALANCE_SUCCESS: { + const { wallet } = payload + const balance = wallet.final_balance + return assoc('spendable_balance', Remote.Success(balance), state) + } + case AT.FETCH_BCH_SPENDABLE_BALANCE_FAILURE: { + return assoc('spendable_balance', Remote.Failure(payload), state) + } + case AT.FETCH_BCH_UNSPENDABLE_BALANCE_LOADING: { + return assoc('unspendable_balance', Remote.Loading, state) + } + case AT.FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS: { + const { wallet } = payload + const balance = wallet.final_balance + return assoc('unspendable_balance', Remote.Success(balance), state) + } + case AT.FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE: { + return assoc('unspendable_balance', Remote.Failure(payload), state) + } default: return state } diff --git a/packages/blockchain-wallet-v4/src/redux/data/bch/sagaRegister.js b/packages/blockchain-wallet-v4/src/redux/data/bch/sagaRegister.js index 648e17c7d5e..edb1a954c5a 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/bch/sagaRegister.js +++ b/packages/blockchain-wallet-v4/src/redux/data/bch/sagaRegister.js @@ -10,6 +10,8 @@ export default ({ api }) => { yield takeLatest(AT.FETCH_BCH_RATES, dataBchSagas.fetchRates) yield takeLatest(AT.FETCH_BCH_FEE, dataBchSagas.fetchFee) yield fork(dataBchSagas.watchTransactions) + yield takeLatest(AT.FETCH_BCH_SPENDABLE_BALANCE, dataBchSagas.fetchSpendableBalance) + yield takeLatest(AT.FETCH_BCH_UNSPENDABLE_BALANCE, dataBchSagas.fetchUnspendableBalance) yield takeLatest(AT.FETCH_BCH_TRANSACTION_HISTORY, dataBchSagas.fetchTransactionHistory) } } diff --git a/packages/blockchain-wallet-v4/src/redux/data/bch/sagas.js b/packages/blockchain-wallet-v4/src/redux/data/bch/sagas.js index c0a9f5fe99d..7f5b8547842 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/bch/sagas.js +++ b/packages/blockchain-wallet-v4/src/redux/data/bch/sagas.js @@ -95,6 +95,28 @@ export default ({ api }) => { } } + const fetchSpendableBalance = function * (action) { + try { + const { context } = action.payload + yield put(A.fetchSpendableBalanceLoading()) + const data = yield call(api.fetchBchData, context) + yield put(A.fetchSpendableBalanceSuccess(data)) + } catch (e) { + yield put(A.fetchSpendableBalanceFailure(e)) + } + } + + const fetchUnspendableBalance = function * (action) { + try { + const { context } = action.payload + yield put(A.fetchUnspendableBalanceLoading()) + const data = yield call(api.fetchBchData, context) + yield put(A.fetchUnspendableBalanceSuccess(data)) + } catch (e) { + yield put(A.fetchUnspendableBalanceFailure(e)) + } + } + const multiaddrSaga = function * (data) { const bchData = { addresses: indexBy(prop('address'), prop('addresses', data)), @@ -105,11 +127,13 @@ export default ({ api }) => { } return { + fetchFee, fetchData, fetchRates, - fetchFee, + fetchUnspent, watchTransactions, - fetchTransactionHistory, - fetchUnspent + fetchSpendableBalance, + fetchUnspendableBalance, + fetchTransactionHistory } } diff --git a/packages/blockchain-wallet-v4/src/redux/data/bch/selectors.js b/packages/blockchain-wallet-v4/src/redux/data/bch/selectors.js index 5fe85ee7702..97b7fee56ae 100644 --- a/packages/blockchain-wallet-v4/src/redux/data/bch/selectors.js +++ b/packages/blockchain-wallet-v4/src/redux/data/bch/selectors.js @@ -17,6 +17,10 @@ export const getTransactionHistory = path([dataPath, 'bch', 'transaction_history export const getCoins = path([dataPath, 'bch', 'payment', 'coins']) +export const getSpendableBalance = path([dataPath, 'bch', 'spendable_balance']) + +export const getUnspendableBalance = path([dataPath, 'bch', 'unspendable_balance']) + // Specific export const getChangeIndex = curry((xpub, state) => getAddresses(state).map(path([xpub, 'change_index']))) diff --git a/packages/blockchain-wallet-v4/src/redux/kvStore/bch/selectors.js b/packages/blockchain-wallet-v4/src/redux/kvStore/bch/selectors.js index 63d0c8f6260..afd611e029b 100644 --- a/packages/blockchain-wallet-v4/src/redux/kvStore/bch/selectors.js +++ b/packages/blockchain-wallet-v4/src/redux/kvStore/bch/selectors.js @@ -1,8 +1,9 @@ -import { curry, keys, filter, lift, map, path } from 'ramda' +import { curry, keys, filter, reject, lift, map, path } from 'ramda' import { BCH } from '../config' import { kvStorePath } from '../../paths' import * as walletSelectors from '../../wallet/selectors' +const isSpendable = (a) => a.priv export const getMetadata = path([kvStorePath, BCH]) // Attention: returns an object with index as keys, not an array @@ -14,13 +15,27 @@ export const getAccountsList = state => { return lift(a => map(key => a[key], keys(a)))(accountsObj) } -export const getContext = (state) => { +export const getContext = (state, spendable) => { const btcHDAccountContext = walletSelectors.getHDAccounts(state) const btcContext = btcHDAccountContext.map(x => x.xpub) try { const accountsObj = getAccounts(state) + const xpubs = filter(x => x.includes('xpub'), btcContext) const btcAddressesContext = walletSelectors.getAddressContext(state) + + return xpubs.filter((xpub, i) => !accountsObj.data[i].archived).concat(btcAddressesContext) + } catch (e) { + return btcContext + } +} + +export const getSpendableContext = (state) => { + const btcHDAccountContext = walletSelectors.getHDAccounts(state) + const btcContext = btcHDAccountContext.map(x => x.xpub) + try { + const accountsObj = getAccounts(state) const xpubs = filter(x => x.includes('xpub'), btcContext) + const btcAddressesContext = filter(isSpendable, walletSelectors.getAddressContext(state)) return xpubs.filter((xpub, i) => !accountsObj.data[i].archived).concat(btcAddressesContext) } catch (e) { @@ -28,6 +43,11 @@ export const getContext = (state) => { } } +export const getUnspendableContext = (state) => { + const btcAddressesContext = walletSelectors.getAddressContext(state) + return reject(isSpendable, btcAddressesContext) +} + export const getDefaultAccountIndex = state => getMetadata(state).map(path(['value', 'default_account_idx'])) export const getAccountLabel = curry((state, index) => getAccounts(state).map(path([index, 'label']))) diff --git a/packages/blockchain-wallet-v4/src/redux/wallet/selectors.js b/packages/blockchain-wallet-v4/src/redux/wallet/selectors.js index f5ced158f53..7a118f5c809 100644 --- a/packages/blockchain-wallet-v4/src/redux/wallet/selectors.js +++ b/packages/blockchain-wallet-v4/src/redux/wallet/selectors.js @@ -15,6 +15,8 @@ export const getWrapper = prop(walletPath) export const getWallet = compose(Wrapper.selectWallet, getWrapper) export const getDefaultHDWallet = compose(HDWalletList.selectHDWallet, Wallet.selectHdWallets, getWallet) export const getWalletContext = compose(ImtoJS, Wallet.selectContext, getWallet) +export const getSpendableContext = compose(ImtoJS, Wallet.selectSpendableContext, getWallet) +export const getUnspendableContext = compose(ImtoJS, Wallet.selectUnspendableContext, getWallet) export const getAddressContext = compose(ImtoJS, Wallet.selectAddrContext, getWallet) export const getXpubsContext = compose(ImtoJS, Wallet.selectXpubsContext, getWallet) export const getSharedKey = compose(Wallet.selectSharedKey, getWallet) diff --git a/packages/blockchain-wallet-v4/src/types/AddressMap.js b/packages/blockchain-wallet-v4/src/types/AddressMap.js index 3455f77dc5a..1c28c13eac4 100644 --- a/packages/blockchain-wallet-v4/src/types/AddressMap.js +++ b/packages/blockchain-wallet-v4/src/types/AddressMap.js @@ -1,4 +1,4 @@ -import { indexBy, map, prop, compose, is, pipe, curry, filter } from 'ramda' +import { indexBy, map, prop, compose, is, pipe, curry, filter, reject } from 'ramda' import { view } from 'ramda-lens' import Type from './Type' import * as Address from './Address' @@ -18,6 +18,8 @@ export const selectContext = pipe(AddressMap.guard, (addressMap) => { }) export const selectActive = pipe(AddressMap.guard, filter(Address.isActive)) export const selectArchived = pipe(AddressMap.guard, filter(Address.isArchived)) +export const selectSpendable = pipe(AddressMap.guard, reject(Address.isWatchOnly)) +export const selectUnspendable = pipe(AddressMap.guard, filter(Address.isWatchOnly)) export const deleteAddress = curry((string, addressMap) => pipe(AddressMap.guard, amap => amap.delete(string))(addressMap) diff --git a/packages/blockchain-wallet-v4/src/types/Wallet.js b/packages/blockchain-wallet-v4/src/types/Wallet.js index ee31fa58009..990d3ebb096 100644 --- a/packages/blockchain-wallet-v4/src/types/Wallet.js +++ b/packages/blockchain-wallet-v4/src/types/Wallet.js @@ -68,11 +68,15 @@ export const selectAddresses = view(addresses) export const selectHdWallets = view(hdWallets) export const isDoubleEncrypted = compose(Boolean, view(doubleEncryption)) -export const selectArchivedContext = compose(AddressMap.selectContext, AddressMap.selectActive, selectAddresses) export const selectAddrContext = compose(AddressMap.selectContext, AddressMap.selectActive, selectAddresses) +export const selectArchivedContext = compose(AddressMap.selectContext, AddressMap.selectActive, selectAddresses) export const selectXpubsContext = compose(HDWallet.selectContext, HDWalletList.selectHDWallet, selectHdWallets) -export const selectHDAccounts = w => selectHdWallets(w).flatMap(HDWallet.selectAccounts) +export const selectSpendableAddrContext = compose(AddressMap.selectContext, AddressMap.selectSpendable, selectAddresses) +export const selectUnspendableAddrContext = compose(AddressMap.selectContext, AddressMap.selectUnspendable, selectAddresses) export const selectContext = w => selectAddrContext(w).concat(selectXpubsContext(w)) +export const selectHDAccounts = w => selectHdWallets(w).flatMap(HDWallet.selectAccounts) +export const selectSpendableContext = w => selectSpendableAddrContext(w).concat(selectXpubsContext(w)) +export const selectUnspendableContext = w => selectUnspendableAddrContext(w).concat(selectXpubsContext(w)) const shiftWallet = compose(shiftIProp('keys', 'addresses'), shift)