1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-24 09:18:09 +00:00

Account balance - pending txs

This commit is contained in:
Szymon Lesisz 2018-05-28 11:21:47 +02:00
parent 43ddffb6e9
commit 00ee6465c9
8 changed files with 63 additions and 26 deletions

View File

@ -36,6 +36,7 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct
const locationChange: boolean = action.type === LOCATION_CHANGE; const locationChange: boolean = action.type === LOCATION_CHANGE;
const state: State = getState(); const state: State = getState();
const location = state.router.location; const location = state.router.location;
const prevLocation = prevState.router.location;
let needUpdate: boolean = false; let needUpdate: boolean = false;
@ -51,13 +52,14 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct
|| prevState.accounts !== state.accounts || prevState.accounts !== state.accounts
|| prevState.discovery !== state.discovery || prevState.discovery !== state.discovery
|| prevState.tokens !== state.tokens || prevState.tokens !== state.tokens
|| prevState.pending !== state.pending
|| prevState.web3 !== state.web3) { || prevState.web3 !== state.web3) {
const account = stateUtils.getSelectedAccount(state); const account = stateUtils.getSelectedAccount(state);
const network = stateUtils.getSelectedNetwork(state); const network = stateUtils.getSelectedNetwork(state);
const discovery = stateUtils.getDiscoveryProcess(state); const discovery = stateUtils.getDiscoveryProcess(state);
const tokens = stateUtils.getAccountTokens(state, account); const tokens = stateUtils.getAccountTokens(state, account);
const pending = stateUtils.getAccountPendingTx(state, account); const pending = stateUtils.getAccountPendingTx(state.pending, account);
const web3 = stateUtils.getWeb3(state); const web3 = stateUtils.getWeb3(state);
const payload: $ElementType<State, 'selectedAccount'> = { const payload: $ElementType<State, 'selectedAccount'> = {
@ -81,13 +83,17 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct
dispatch({ dispatch({
type: ACCOUNT.UPDATE_SELECTED_ACCOUNT, type: ACCOUNT.UPDATE_SELECTED_ACCOUNT,
payload, payload,
}) });
} }
if (locationChange) { if (locationChange) {
if (prevState.router.location && prevState.router.location.state.send) { if (prevLocation) {
SessionStorageActions.save(prevState.router.location.pathname, state.sendForm); // save form data to session storage
// TODO: move to state.sendForm on change event
if (prevLocation.state.send) {
SessionStorageActions.save(prevState.router.location.pathname, state.sendForm);
}
} }
dispatch( dispose() ); dispatch( dispose() );

View File

@ -18,8 +18,10 @@ import { initialState } from '../reducers/SendFormReducer';
import { findAccount } from '../reducers/AccountsReducer'; import { findAccount } from '../reducers/AccountsReducer';
import { findToken } from '../reducers/TokensReducer'; import { findToken } from '../reducers/TokensReducer';
import { findDevice } from '../reducers/utils'; import { findDevice } from '../reducers/utils';
import * as stateUtils from '../reducers/utils';
import type { import type {
PendingTx,
Dispatch, Dispatch,
GetState, GetState,
Action, Action,
@ -41,6 +43,8 @@ export type SendTxAction = {
account: Account, account: Account,
selectedCurrency: string, selectedCurrency: string,
amount: string, amount: string,
total: string,
tx: any,
txid: string, txid: string,
txData: any, txData: any,
}; };
@ -156,8 +160,6 @@ export const calculate = (prevProps: Props, props: Props) => {
} = props.selectedAccount; } = props.selectedAccount;
if (!account) return; if (!account) return;
console.warn("CALCULATE!", props)
const prevState = prevProps.sendForm; const prevState = prevProps.sendForm;
const state = props.sendForm; const state = props.sendForm;
const isToken: boolean = state.currency !== state.networkSymbol; const isToken: boolean = state.currency !== state.networkSymbol;
@ -173,18 +175,16 @@ export const calculate = (prevProps: Props, props: Props) => {
if (state.setMax) { if (state.setMax) {
const pendingAmount = pending.reduce((value, p) => { const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency);
//if (p.tx.amount)
console.warn("PENDING AMOUNT!", p, value);
}, 0);
if (isToken) { if (isToken) {
const token: ?Token = findToken(tokens, account.address, state.currency, account.deviceState); const token: ?Token = findToken(tokens, account.address, state.currency, account.deviceState);
if (token) { if (token) {
state.amount = token.balance; state.amount = new BigNumber(token.balance).minus(pendingAmount).toString();
} }
} else { } else {
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit); const b = new BigNumber(account.balance).minus(pendingAmount).toString();
state.amount = calculateMaxAmount(b, state.gasPrice, state.gasLimit);
} }
} }
@ -350,6 +350,7 @@ export const validation = (props: Props): void => {
account, account,
network, network,
tokens, tokens,
pending,
} = props.selectedAccount; } = props.selectedAccount;
if (!account || !network) return; if (!account || !network) return;
@ -389,6 +390,7 @@ export const validation = (props: Props): void => {
} else { } else {
let decimalRegExp: RegExp; let decimalRegExp: RegExp;
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency);
if (state.currency !== state.networkSymbol) { if (state.currency !== state.networkSymbol) {
const token = findToken(tokens, account.address, state.currency, account.deviceState); const token = findToken(tokens, account.address, state.currency, account.deviceState);
@ -405,7 +407,7 @@ export const validation = (props: Props): void => {
errors.amount = `Maximum ${ token.decimals} decimals allowed`; errors.amount = `Maximum ${ token.decimals} decimals allowed`;
} else if (new BigNumber(state.total).greaterThan(account.balance)) { } else if (new BigNumber(state.total).greaterThan(account.balance)) {
errors.amount = `Not enough ${ state.networkSymbol } to cover transaction fee`; errors.amount = `Not enough ${ state.networkSymbol } to cover transaction fee`;
} else if (new BigNumber(state.amount).greaterThan(token.balance)) { } else if (new BigNumber(state.amount).greaterThan( new BigNumber(token.balance).minus(pendingAmount) )) {
errors.amount = 'Not enough funds'; errors.amount = 'Not enough funds';
} else if (new BigNumber(state.amount).lessThanOrEqualTo('0')) { } else if (new BigNumber(state.amount).lessThanOrEqualTo('0')) {
errors.amount = 'Amount is too low'; errors.amount = 'Amount is too low';
@ -416,7 +418,7 @@ export const validation = (props: Props): void => {
decimalRegExp = new RegExp('^(0|0\\.([0-9]{0,18})?|[1-9][0-9]*\\.?([0-9]{0,18})?|\\.[0-9]{0,18})$'); decimalRegExp = new RegExp('^(0|0\\.([0-9]{0,18})?|[1-9][0-9]*\\.?([0-9]{0,18})?|\\.[0-9]{0,18})$');
if (!state.amount.match(decimalRegExp)) { if (!state.amount.match(decimalRegExp)) {
errors.amount = `Maximum 18 decimals allowed`; errors.amount = `Maximum 18 decimals allowed`;
} else if (new BigNumber(state.total).greaterThan(account.balance)) { } else if (new BigNumber(state.total).greaterThan( new BigNumber(account.balance).minus(pendingAmount) )) {
errors.amount = 'Not enough funds'; errors.amount = 'Not enough funds';
} }
} }
@ -916,6 +918,8 @@ export const onSend = (): AsyncAction => {
account: account, account: account,
selectedCurrency: currentState.currency, selectedCurrency: currentState.currency,
amount: currentState.amount, amount: currentState.amount,
total: currentState.total,
tx,
txid, txid,
txData, txData,
}); });

View File

@ -34,7 +34,7 @@ const PendingTransactions = (props: Props) => {
const bgColorFactory = new ColorHash({lightness: 0.7}); const bgColorFactory = new ColorHash({lightness: 0.7});
const textColorFactory = new ColorHash(); const textColorFactory = new ColorHash();
const pendingTxs = pending.map((tx, i) => { const pendingTxs: React$Element<string> = pending.map((tx, i) => {
let iconColor: Style; let iconColor: Style;
let symbol: string; let symbol: string;
@ -80,7 +80,7 @@ const PendingTransactions = (props: Props) => {
<div className="name"> <div className="name">
<a href={ `${props.network.explorer.tx}${tx.id}`} target="_blank" rel="noreferrer noopener">{ name }</a> <a href={ `${props.network.explorer.tx}${tx.id}`} target="_blank" rel="noreferrer noopener">{ name }</a>
</div> </div>
<div className="amount">{ tx.amount } { symbol }</div> <div className="amount">{ tx.total } { symbol }</div>
</div> </div>
) )
}); });

View File

@ -11,6 +11,7 @@ import SelectedAccount from '../SelectedAccount';
import { Notification } from '~/js/components/common/Notification'; import { Notification } from '~/js/components/common/Notification';
import SummaryDetails from './SummaryDetails.js'; import SummaryDetails from './SummaryDetails.js';
import SummaryTokens from './SummaryTokens.js'; import SummaryTokens from './SummaryTokens.js';
import * as stateUtils from '~/js/reducers/utils';
import type { Props } from './index'; import type { Props } from './index';
import type { NetworkToken } from '~/js/reducers/LocalStorageReducer'; import type { NetworkToken } from '~/js/reducers/LocalStorageReducer';
@ -21,6 +22,7 @@ const Summary = (props: Props) => {
account, account,
network, network,
tokens, tokens,
pending
} = props.selectedAccount; } = props.selectedAccount;
// flow // flow
@ -33,6 +35,9 @@ const Summary = (props: Props) => {
); );
const explorerLink: string = `${network.explorer.address}${account.address}`; const explorerLink: string = `${network.explorer.address}${account.address}`;
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol);
const balance: string = new BigNumber(account.balance).minus(pendingAmount).toString();
return ( return (
<div> <div>
<h2 className={ `summary-header ${account.network}` }> <h2 className={ `summary-header ${account.network}` }>
@ -43,7 +48,7 @@ const Summary = (props: Props) => {
<SummaryDetails <SummaryDetails
coin={ network } coin={ network }
summary={ props.summary } summary={ props.summary }
balance={ account.balance } balance={ balance }
network={ network.network } network={ network.network }
fiat={ props.fiat } fiat={ props.fiat }
localStorage={ props.localStorage } localStorage={ props.localStorage }

View File

@ -6,6 +6,7 @@ import { Link, NavLink } from 'react-router-dom';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { findDeviceAccounts } from '~/js/reducers/AccountsReducer'; import { findDeviceAccounts } from '~/js/reducers/AccountsReducer';
import * as stateUtils from '~/js/reducers/utils';
import Loader from '~/js/components/common/LoaderCircle'; import Loader from '~/js/components/common/LoaderCircle';
import Tooltip from 'rc-tooltip'; import Tooltip from 'rc-tooltip';
@ -36,12 +37,16 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
let balance: string = 'Loading...'; let balance: string = 'Loading...';
if (account.balance !== '') { if (account.balance !== '') {
const pending = stateUtils.getAccountPendingTx(props.pending, account);
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, selectedCoin.symbol);
const availableBalance: string = new BigNumber(account.balance).minus(pendingAmount).toString();
if (fiatRate) { if (fiatRate) {
const accountBalance = new BigNumber(account.balance); const accountBalance = new BigNumber(availableBalance);
const fiat = accountBalance.times(fiatRate.value).toFixed(2); const fiat = accountBalance.times(fiatRate.value).toFixed(2);
balance = `${ account.balance } ${ selectedCoin.symbol } / $${ fiat }`; balance = `${ availableBalance } ${ selectedCoin.symbol } / $${ fiat }`;
} else { } else {
balance = `${ account.balance } ${ selectedCoin.symbol }`; balance = `${ availableBalance } ${ selectedCoin.symbol }`;
} }
} }

View File

@ -28,6 +28,7 @@ type StateProps = {
discovery: $ElementType<State, 'discovery'>, discovery: $ElementType<State, 'discovery'>,
wallet: $ElementType<State, 'wallet'>, wallet: $ElementType<State, 'wallet'>,
devices: $ElementType<State, 'devices'>, devices: $ElementType<State, 'devices'>,
pending: $ElementType<State, 'pending'>,
} }
type DispatchProps = { type DispatchProps = {
@ -52,7 +53,8 @@ const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: St
localStorage: state.localStorage, localStorage: state.localStorage,
discovery: state.discovery, discovery: state.discovery,
wallet: state.wallet, wallet: state.wallet,
devices: state.devices devices: state.devices,
pending: state.pending,
}; };
} }

View File

@ -13,6 +13,8 @@ export type PendingTx = {
+network: string; +network: string;
+currency: string; +currency: string;
+amount: string; +amount: string;
+total: string;
+tx: any;
+address: string; +address: string;
} }
@ -27,6 +29,8 @@ const add = (state: State, action: SendTxAction): State => {
network: action.account.network, network: action.account.network,
currency: action.selectedCurrency, currency: action.selectedCurrency,
amount: action.amount, amount: action.amount,
total: action.total,
tx: action.tx,
address: action.account.address, address: action.account.address,
}); });
return newState; return newState;

View File

@ -4,6 +4,7 @@
import * as LogActions from '~/js/actions/LogActions'; import * as LogActions from '~/js/actions/LogActions';
import * as STORAGE from '~/js/actions/constants/localStorage'; import * as STORAGE from '~/js/actions/constants/localStorage';
import * as WALLET from '~/js/actions/constants/wallet'; import * as WALLET from '~/js/actions/constants/wallet';
import BigNumber from 'bignumber.js';
import type { import type {
Middleware, Middleware,
@ -84,15 +85,24 @@ export const getDiscoveryProcess = (state: State): ?Discovery => {
return state.discovery.find(d => d.deviceState === device.state && d.network === locationState.network); return state.discovery.find(d => d.deviceState === device.state && d.network === locationState.network);
} }
export const getAccountPendingTx = (state: State, account: ?Account): Array<PendingTx> => { export const getAccountPendingTx = (pending: Array<PendingTx>, account: ?Account): Array<PendingTx> => {
const a = account; const a = account;
if (!a) return state.selectedAccount.pending.length > 0 ? [] : state.selectedAccount.pending; if (!a) return [];
return state.pending.filter(p => p.network === a.network && p.address === a.address); return pending.filter(p => p.network === a.network && p.address === a.address);
}
export const getPendingAmount = (pending: Array<PendingTx>, currency: string): BigNumber => {
return pending.reduce((value: BigNumber, tx: PendingTx) => {
if (tx.currency === currency) {
return new BigNumber(value).plus(tx.amount);
}
return value;
}, new BigNumber('0'));
} }
export const getAccountTokens = (state: State, account: ?Account): Array<Token> => { export const getAccountTokens = (state: State, account: ?Account): Array<Token> => {
const a = account; const a = account;
if (!a) return state.selectedAccount.tokens.length > 0 ? [] : state.selectedAccount.tokens; if (!a) return [];
return state.tokens.filter(t => t.ethAddress === a.address && t.network === a.network && t.deviceState === a.deviceState); return state.tokens.filter(t => t.ethAddress === a.address && t.network === a.network && t.deviceState === a.deviceState);
} }
@ -100,4 +110,5 @@ export const getWeb3 = (state: State): ?Web3Instance => {
const locationState = state.router.location.state; const locationState = state.router.location.state;
if (!locationState.network) return null; if (!locationState.network) return null;
return state.web3.find(w3 => w3.network === locationState.network); return state.web3.find(w3 => w3.network === locationState.network);
} }