2021-10-08 05:47:39 +02:00
|
|
|
import { createSelector } from 'reselect';
|
|
|
|
import * as TRANSACTIONS from 'constants/transaction_types';
|
|
|
|
import { PAGE_SIZE, LATEST_PAGE_SIZE } from 'constants/transaction_list';
|
|
|
|
import { selectClaimIdsByUri } from 'redux/selectors/claims';
|
|
|
|
import parseData from 'util/parse-data';
|
|
|
|
export const selectState = (state) => state.wallet || {};
|
|
|
|
|
|
|
|
export const selectWalletState = selectState;
|
|
|
|
|
|
|
|
export const selectWalletIsEncrypted = createSelector(selectState, (state) => state.walletIsEncrypted);
|
|
|
|
|
|
|
|
export const selectWalletEncryptPending = createSelector(selectState, (state) => state.walletEncryptPending);
|
|
|
|
|
|
|
|
export const selectWalletEncryptSucceeded = createSelector(selectState, (state) => state.walletEncryptSucceded);
|
|
|
|
|
|
|
|
export const selectPendingSupportTransactions = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => state.pendingSupportTransactions
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectPendingOtherTransactions = createSelector(selectState, (state) => state.pendingTxos);
|
|
|
|
|
|
|
|
export const selectAbandonClaimSupportError = createSelector(selectState, (state) => state.abandonClaimSupportError);
|
|
|
|
|
|
|
|
export const makeSelectPendingAmountByUri = (uri) =>
|
|
|
|
createSelector(selectClaimIdsByUri, selectPendingSupportTransactions, (claimIdsByUri, pendingSupports) => {
|
|
|
|
const uriEntry = Object.entries(claimIdsByUri).find(([u, cid]) => u === uri);
|
|
|
|
const claimId = uriEntry && uriEntry[1];
|
|
|
|
const pendingSupport = claimId && pendingSupports[claimId];
|
|
|
|
return pendingSupport ? pendingSupport.effective : undefined;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectWalletEncryptResult = createSelector(selectState, (state) => state.walletEncryptResult);
|
|
|
|
|
|
|
|
export const selectWalletDecryptPending = createSelector(selectState, (state) => state.walletDecryptPending);
|
|
|
|
|
|
|
|
export const selectWalletDecryptSucceeded = createSelector(selectState, (state) => state.walletDecryptSucceded);
|
|
|
|
|
|
|
|
export const selectWalletDecryptResult = createSelector(selectState, (state) => state.walletDecryptResult);
|
|
|
|
|
|
|
|
export const selectWalletUnlockPending = createSelector(selectState, (state) => state.walletUnlockPending);
|
|
|
|
|
|
|
|
export const selectWalletUnlockSucceeded = createSelector(selectState, (state) => state.walletUnlockSucceded);
|
|
|
|
|
|
|
|
export const selectWalletUnlockResult = createSelector(selectState, (state) => state.walletUnlockResult);
|
|
|
|
|
|
|
|
export const selectWalletLockPending = createSelector(selectState, (state) => state.walletLockPending);
|
|
|
|
|
|
|
|
export const selectWalletLockSucceeded = createSelector(selectState, (state) => state.walletLockSucceded);
|
|
|
|
|
|
|
|
export const selectWalletLockResult = createSelector(selectState, (state) => state.walletLockResult);
|
|
|
|
|
|
|
|
export const selectBalance = createSelector(selectState, (state) => state.balance);
|
|
|
|
|
|
|
|
export const selectTotalBalance = createSelector(selectState, (state) => state.totalBalance);
|
|
|
|
|
|
|
|
export const selectReservedBalance = createSelector(selectState, (state) => state.reservedBalance);
|
|
|
|
|
|
|
|
export const selectClaimsBalance = createSelector(selectState, (state) => state.claimsBalance);
|
|
|
|
|
|
|
|
export const selectSupportsBalance = createSelector(selectState, (state) => state.supportsBalance);
|
|
|
|
|
|
|
|
export const selectTipsBalance = createSelector(selectState, (state) => state.tipsBalance);
|
|
|
|
|
|
|
|
export const selectTransactionsById = createSelector(selectState, (state) => state.transactions || {});
|
|
|
|
|
|
|
|
export const selectSupportsByOutpoint = createSelector(selectState, (state) => state.supports || {});
|
|
|
|
|
|
|
|
export const selectTotalSupports = createSelector(selectSupportsByOutpoint, (byOutpoint) => {
|
|
|
|
let total = parseFloat('0.0');
|
|
|
|
|
|
|
|
Object.values(byOutpoint).forEach((support) => {
|
|
|
|
const { amount } = support;
|
|
|
|
total = amount ? total + parseFloat(amount) : total;
|
|
|
|
});
|
|
|
|
|
|
|
|
return total;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectTransactionItems = createSelector(selectTransactionsById, (byId) => {
|
|
|
|
const items = [];
|
|
|
|
|
|
|
|
Object.keys(byId).forEach((txid) => {
|
|
|
|
const tx = byId[txid];
|
|
|
|
|
|
|
|
// ignore dust/fees
|
|
|
|
// it is fee only txn if all infos are also empty
|
|
|
|
if (
|
|
|
|
Math.abs(tx.value) === Math.abs(tx.fee) &&
|
|
|
|
tx.claim_info.length === 0 &&
|
|
|
|
tx.support_info.length === 0 &&
|
|
|
|
tx.update_info.length === 0 &&
|
|
|
|
tx.abandon_info.length === 0
|
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const append = [];
|
|
|
|
|
|
|
|
append.push(
|
|
|
|
...tx.claim_info.map((item) =>
|
|
|
|
Object.assign({}, tx, item, {
|
|
|
|
type: item.claim_name[0] === '@' ? TRANSACTIONS.CHANNEL : TRANSACTIONS.PUBLISH,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
|
|
|
append.push(
|
|
|
|
...tx.support_info.map((item) =>
|
|
|
|
Object.assign({}, tx, item, {
|
|
|
|
type: !item.is_tip ? TRANSACTIONS.SUPPORT : TRANSACTIONS.TIP,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
|
|
|
append.push(...tx.update_info.map((item) => Object.assign({}, tx, item, { type: TRANSACTIONS.UPDATE })));
|
|
|
|
append.push(...tx.abandon_info.map((item) => Object.assign({}, tx, item, { type: TRANSACTIONS.ABANDON })));
|
|
|
|
|
|
|
|
if (!append.length) {
|
|
|
|
append.push(
|
|
|
|
Object.assign({}, tx, {
|
|
|
|
type: tx.value < 0 ? TRANSACTIONS.SPEND : TRANSACTIONS.RECEIVE,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
items.push(
|
|
|
|
...append.map((item) => {
|
|
|
|
// value on transaction, amount on outpoint
|
|
|
|
// amount is always positive, but should match sign of value
|
|
|
|
const balanceDelta = parseFloat(item.balance_delta);
|
|
|
|
const value = parseFloat(item.value);
|
|
|
|
const amount = balanceDelta || value;
|
|
|
|
const fee = parseFloat(tx.fee);
|
|
|
|
|
|
|
|
return {
|
|
|
|
txid,
|
|
|
|
timestamp: tx.timestamp,
|
|
|
|
date: tx.timestamp ? new Date(Number(tx.timestamp) * 1000) : null,
|
|
|
|
amount,
|
|
|
|
fee,
|
|
|
|
claim_id: item.claim_id,
|
|
|
|
claim_name: item.claim_name,
|
|
|
|
type: item.type || TRANSACTIONS.SPEND,
|
|
|
|
nout: item.nout,
|
|
|
|
confirmations: tx.confirmations,
|
|
|
|
};
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
return items.sort((tx1, tx2) => {
|
|
|
|
if (!tx1.timestamp && !tx2.timestamp) {
|
|
|
|
return 0;
|
|
|
|
} else if (!tx1.timestamp && tx2.timestamp) {
|
|
|
|
return -1;
|
|
|
|
} else if (tx1.timestamp && !tx2.timestamp) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx2.timestamp - tx1.timestamp;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectRecentTransactions = createSelector(selectTransactionItems, (transactions) => {
|
|
|
|
const threshold = new Date();
|
|
|
|
threshold.setDate(threshold.getDate() - 7);
|
|
|
|
return transactions.filter((transaction) => {
|
|
|
|
if (!transaction.date) {
|
|
|
|
return true; // pending transaction
|
|
|
|
}
|
|
|
|
|
|
|
|
return transaction.date > threshold;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectHasTransactions = createSelector(
|
|
|
|
selectTransactionItems,
|
|
|
|
(transactions) => transactions && transactions.length > 0
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectIsFetchingTransactions = createSelector(selectState, (state) => state.fetchingTransactions);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* CSV of 'selectTransactionItems'.
|
|
|
|
*/
|
|
|
|
export const selectTransactionsFile = createSelector(selectTransactionItems, (transactions) => {
|
|
|
|
if (!transactions || transactions.length === 0) {
|
|
|
|
// No data.
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
const parsed = parseData(transactions, 'csv');
|
|
|
|
if (!parsed) {
|
|
|
|
// Invalid data, or failed to parse.
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parsed;
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectIsSendingSupport = createSelector(selectState, (state) => state.sendingSupport);
|
|
|
|
|
|
|
|
export const selectReceiveAddress = createSelector(selectState, (state) => state.receiveAddress);
|
|
|
|
|
|
|
|
export const selectGettingNewAddress = createSelector(selectState, (state) => state.gettingNewAddress);
|
|
|
|
|
|
|
|
export const selectDraftTransaction = createSelector(selectState, (state) => state.draftTransaction || {});
|
|
|
|
|
|
|
|
export const selectDraftTransactionAmount = createSelector(selectDraftTransaction, (draft) => draft.amount);
|
|
|
|
|
|
|
|
export const selectDraftTransactionAddress = createSelector(selectDraftTransaction, (draft) => draft.address);
|
|
|
|
|
|
|
|
export const selectDraftTransactionError = createSelector(selectDraftTransaction, (draft) => draft.error);
|
|
|
|
|
|
|
|
export const selectBlocks = createSelector(selectState, (state) => state.blocks);
|
|
|
|
|
|
|
|
export const selectCurrentHeight = createSelector(selectState, (state) => state.latestBlock);
|
|
|
|
|
|
|
|
export const selectTransactionListFilter = createSelector(selectState, (state) => state.transactionListFilter || '');
|
|
|
|
|
|
|
|
export const selectFilteredTransactions = createSelector(
|
|
|
|
selectTransactionItems,
|
|
|
|
selectTransactionListFilter,
|
|
|
|
(transactions, filter) => {
|
|
|
|
return transactions.filter((transaction) => {
|
|
|
|
return filter === TRANSACTIONS.ALL || filter === transaction.type;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectTxoPageParams = createSelector(selectState, (state) => state.txoFetchParams);
|
|
|
|
|
|
|
|
export const selectTxoPage = createSelector(selectState, (state) => (state.txoPage && state.txoPage.items) || []);
|
|
|
|
|
|
|
|
export const selectTxoPageNumber = createSelector(selectState, (state) => (state.txoPage && state.txoPage.page) || 1);
|
|
|
|
|
|
|
|
export const selectTxoItemCount = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => (state.txoPage && state.txoPage.total_items) || 1
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectFetchingTxosError = createSelector(selectState, (state) => state.fetchingTxosError);
|
|
|
|
|
|
|
|
export const selectIsFetchingTxos = createSelector(selectState, (state) => state.fetchingTxos);
|
|
|
|
|
|
|
|
export const makeSelectFilteredTransactionsForPage = (page = 1) =>
|
|
|
|
createSelector(selectFilteredTransactions, (filteredTransactions) => {
|
|
|
|
const start = (Number(page) - 1) * Number(PAGE_SIZE);
|
|
|
|
const end = Number(page) * Number(PAGE_SIZE);
|
|
|
|
return filteredTransactions && filteredTransactions.length ? filteredTransactions.slice(start, end) : [];
|
|
|
|
});
|
|
|
|
|
|
|
|
export const makeSelectLatestTransactions = createSelector(selectTransactionItems, (transactions) => {
|
|
|
|
return transactions && transactions.length ? transactions.slice(0, LATEST_PAGE_SIZE) : [];
|
|
|
|
});
|
|
|
|
|
|
|
|
export const selectFilteredTransactionCount = createSelector(
|
|
|
|
selectFilteredTransactions,
|
|
|
|
(filteredTransactions) => filteredTransactions.length
|
|
|
|
);
|
|
|
|
|
|
|
|
export const selectIsWalletReconnecting = createSelector(selectState, (state) => state.walletReconnecting);
|
|
|
|
|
2022-05-31 20:03:29 +02:00
|
|
|
export const selectWalletRollbackToDefault = createSelector(selectState, (state) => state.walletRollbackToDefault);
|
|
|
|
|
|
|
|
export const selectWalletConnectingToDefault = createSelector(
|
|
|
|
selectState,
|
|
|
|
(state) => state.walletReconnectingToDefault
|
|
|
|
);
|
|
|
|
|
2021-10-08 05:47:39 +02:00
|
|
|
export const selectIsFetchingUtxoCounts = createSelector(selectState, (state) => state.fetchingUtxoCounts);
|
|
|
|
|
|
|
|
export const selectIsConsolidatingUtxos = createSelector(selectState, (state) => state.consolidatingUtxos);
|
|
|
|
|
|
|
|
export const selectIsMassClaimingTips = createSelector(selectState, (state) => state.massClaimingTips);
|
|
|
|
|
|
|
|
export const selectPendingConsolidateTxid = createSelector(selectState, (state) => state.pendingConsolidateTxid);
|
|
|
|
|
|
|
|
export const selectPendingMassClaimTxid = createSelector(selectState, (state) => state.pendingMassClaimTxid);
|
|
|
|
|
|
|
|
export const selectUtxoCounts = createSelector(selectState, (state) => state.utxoCounts);
|