mirror of
https://github.com/trezor/trezor-wallet
synced 2025-02-17 02:22:07 +00:00
update SendForm and PendingTx using trezor-connect@8
This commit is contained in:
parent
2231f42b37
commit
11bf91b093
@ -39,7 +39,7 @@ export type SignVerifyAction =
|
|||||||
message: ?string,
|
message: ?string,
|
||||||
};
|
};
|
||||||
|
|
||||||
const sign = (path: Array<number>, message: string, hex: boolean = false): AsyncAction => async (
|
const sign = (path: string, message: string, hex: boolean = false): AsyncAction => async (
|
||||||
dispatch: Dispatch,
|
dispatch: Dispatch,
|
||||||
getState: GetState
|
getState: GetState
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
|
@ -21,7 +21,7 @@ type EthereumTxRequest = {
|
|||||||
data: string,
|
data: string,
|
||||||
gasLimit: string,
|
gasLimit: string,
|
||||||
gasPrice: string,
|
gasPrice: string,
|
||||||
nonce: number,
|
nonce: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const prepareEthereumTx = (
|
export const prepareEthereumTx = (
|
||||||
@ -54,9 +54,6 @@ export const prepareEthereumTx = (
|
|||||||
nonce: toHex(tx.nonce),
|
nonce: toHex(tx.nonce),
|
||||||
gasLimit: toHex(tx.gasLimit),
|
gasLimit: toHex(tx.gasLimit),
|
||||||
gasPrice: toHex(EthereumjsUnits.convert(tx.gasPrice, 'gwei', 'wei')),
|
gasPrice: toHex(EthereumjsUnits.convert(tx.gasPrice, 'gwei', 'wei')),
|
||||||
r: '',
|
|
||||||
s: '',
|
|
||||||
v: '',
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,13 +11,11 @@ import * as ethUtils from 'utils/ethUtils';
|
|||||||
|
|
||||||
import type { Dispatch, GetState, ThunkAction, PromiseAction } from 'flowtype';
|
import type { Dispatch, GetState, ThunkAction, PromiseAction } from 'flowtype';
|
||||||
|
|
||||||
import type { EthereumAccount } from 'trezor-connect';
|
|
||||||
import type { Account } from 'reducers/AccountsReducer';
|
import type { Account } from 'reducers/AccountsReducer';
|
||||||
import type { Web3Instance } from 'reducers/Web3Reducer';
|
import type { Web3Instance } from 'reducers/Web3Reducer';
|
||||||
import type { Token } from 'reducers/TokensReducer';
|
import type { Token } from 'reducers/TokensReducer';
|
||||||
import type { NetworkToken } from 'reducers/LocalStorageReducer';
|
import type { NetworkToken } from 'reducers/LocalStorageReducer';
|
||||||
import * as TokenActions from './TokenActions';
|
import * as TokenActions from './TokenActions';
|
||||||
import * as AccountsActions from './AccountsActions';
|
|
||||||
|
|
||||||
export type Web3UpdateBlockAction = {
|
export type Web3UpdateBlockAction = {
|
||||||
type: typeof WEB3.BLOCK_UPDATED,
|
type: typeof WEB3.BLOCK_UPDATED,
|
||||||
@ -127,22 +125,22 @@ export const initWeb3 = (
|
|||||||
web3.currentProvider.on('error', onEnd);
|
web3.currentProvider.on('error', onEnd);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const discoverAccount = (
|
// not used since connect@8
|
||||||
descriptor: string,
|
// export const discoverAccount = (descriptor: string, network: string): PromiseAction<any> => async (
|
||||||
network: string
|
// dispatch: Dispatch
|
||||||
): PromiseAction<EthereumAccount> => async (dispatch: Dispatch): Promise<EthereumAccount> => {
|
// ): Promise<any> => {
|
||||||
const instance: Web3Instance = await dispatch(initWeb3(network));
|
// const instance: Web3Instance = await dispatch(initWeb3(network));
|
||||||
const balance = await instance.web3.eth.getBalance(descriptor);
|
// const balance = await instance.web3.eth.getBalance(descriptor);
|
||||||
const nonce = await instance.web3.eth.getTransactionCount(descriptor);
|
// const nonce = await instance.web3.eth.getTransactionCount(descriptor);
|
||||||
return {
|
// return {
|
||||||
descriptor,
|
// descriptor,
|
||||||
transactions: 0,
|
// transactions: 0,
|
||||||
block: 0,
|
// block: 0,
|
||||||
balance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
// balance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
||||||
availableBalance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
// availableBalance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
||||||
nonce,
|
// nonce,
|
||||||
};
|
// };
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const resolvePendingTransactions = (network: string): PromiseAction<void> => async (
|
export const resolvePendingTransactions = (network: string): PromiseAction<void> => async (
|
||||||
dispatch: Dispatch,
|
dispatch: Dispatch,
|
||||||
@ -151,24 +149,24 @@ export const resolvePendingTransactions = (network: string): PromiseAction<void>
|
|||||||
const instance: Web3Instance = await dispatch(initWeb3(network));
|
const instance: Web3Instance = await dispatch(initWeb3(network));
|
||||||
const pending = getState().pending.filter(p => p.network === network);
|
const pending = getState().pending.filter(p => p.network === network);
|
||||||
pending.forEach(async tx => {
|
pending.forEach(async tx => {
|
||||||
const status = await instance.web3.eth.getTransaction(tx.hash);
|
const status = await instance.web3.eth.getTransaction(tx.txid);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: PENDING.TX_REJECTED,
|
type: PENDING.TX_REJECTED,
|
||||||
hash: tx.hash,
|
hash: tx.txid,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const receipt = await instance.web3.eth.getTransactionReceipt(tx.hash);
|
const receipt = await instance.web3.eth.getTransactionReceipt(tx.txid);
|
||||||
if (receipt) {
|
if (receipt) {
|
||||||
if (status.gas !== receipt.gasUsed) {
|
if (status.gas !== receipt.gasUsed) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: PENDING.TX_TOKEN_ERROR,
|
type: PENDING.TX_TOKEN_ERROR,
|
||||||
hash: tx.hash,
|
hash: tx.txid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
dispatch({
|
dispatch({
|
||||||
type: PENDING.TX_RESOLVED,
|
type: PENDING.TX_RESOLVED,
|
||||||
hash: tx.hash,
|
hash: tx.txid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,30 +203,31 @@ export const getTxInput = (): PromiseAction<void> => async (dispatch: Dispatch):
|
|||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const updateAccount = (
|
// not used since connect@8
|
||||||
account: Account,
|
// export const updateAccount = (
|
||||||
newAccount: EthereumAccount,
|
// account: Account,
|
||||||
network: string
|
// newAccount: any,
|
||||||
): PromiseAction<void> => async (dispatch: Dispatch): Promise<void> => {
|
// network: string
|
||||||
const instance: Web3Instance = await dispatch(initWeb3(network));
|
// ): PromiseAction<void> => async (dispatch: Dispatch): Promise<void> => {
|
||||||
const balance = await instance.web3.eth.getBalance(account.descriptor);
|
// const instance: Web3Instance = await dispatch(initWeb3(network));
|
||||||
const nonce = await instance.web3.eth.getTransactionCount(account.descriptor);
|
// const balance = await instance.web3.eth.getBalance(account.descriptor);
|
||||||
const empty = nonce <= 0 && balance === '0';
|
// const nonce = await instance.web3.eth.getTransactionCount(account.descriptor);
|
||||||
dispatch(
|
// const empty = nonce <= 0 && balance === '0';
|
||||||
AccountsActions.update({
|
// dispatch(
|
||||||
networkType: 'ethereum',
|
// AccountsActions.update({
|
||||||
...account,
|
// networkType: 'ethereum',
|
||||||
...newAccount,
|
// ...account,
|
||||||
empty,
|
// ...newAccount,
|
||||||
nonce,
|
// empty,
|
||||||
balance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
// nonce,
|
||||||
availableBalance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
// balance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
||||||
})
|
// availableBalance: EthereumjsUnits.convert(balance, 'wei', 'ether'),
|
||||||
);
|
// })
|
||||||
|
// );
|
||||||
|
|
||||||
// update tokens for this account
|
// // update tokens for this account
|
||||||
dispatch(updateAccountTokens(account));
|
// dispatch(updateAccountTokens(account));
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const updateAccountTokens = (account: Account): PromiseAction<void> => async (
|
export const updateAccountTokens = (account: Account): PromiseAction<void> => async (
|
||||||
dispatch: Dispatch,
|
dispatch: Dispatch,
|
||||||
|
@ -486,7 +486,7 @@ export const onGasPriceChange = (gasPrice: string): ThunkAction => (
|
|||||||
): void => {
|
): void => {
|
||||||
const state: State = getState().sendFormEthereum;
|
const state: State = getState().sendFormEthereum;
|
||||||
// switch to custom fee level
|
// switch to custom fee level
|
||||||
let newSelectedFeeLevel = state.selectedFeeLevel;
|
let newSelectedFeeLevel;
|
||||||
if (state.selectedFeeLevel.value !== 'Custom')
|
if (state.selectedFeeLevel.value !== 'Custom')
|
||||||
newSelectedFeeLevel = state.feeLevels.find(f => f.value === 'Custom');
|
newSelectedFeeLevel = state.feeLevels.find(f => f.value === 'Custom');
|
||||||
|
|
||||||
@ -498,7 +498,7 @@ export const onGasPriceChange = (gasPrice: string): ThunkAction => (
|
|||||||
untouched: false,
|
untouched: false,
|
||||||
touched: { ...state.touched, gasPrice: true },
|
touched: { ...state.touched, gasPrice: true },
|
||||||
gasPrice,
|
gasPrice,
|
||||||
selectedFeeLevel: newSelectedFeeLevel,
|
selectedFeeLevel: newSelectedFeeLevel || state.selectedFeeLevel,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -673,9 +673,12 @@ export const onSend = (): AsyncAction => async (
|
|||||||
|
|
||||||
const currentState: State = getState().sendFormEthereum;
|
const currentState: State = getState().sendFormEthereum;
|
||||||
|
|
||||||
const isToken: boolean = currentState.currency !== currentState.networkSymbol;
|
const isToken = currentState.currency !== currentState.networkSymbol;
|
||||||
const pendingNonce: number = reducerUtils.getPendingSequence(pending);
|
const pendingNonce = new BigNumber(reducerUtils.getPendingSequence(pending));
|
||||||
const nonce = pendingNonce > 0 && pendingNonce >= account.nonce ? pendingNonce : account.nonce;
|
const nonce =
|
||||||
|
pendingNonce.gt(0) && pendingNonce.gt(account.nonce)
|
||||||
|
? pendingNonce.toString()
|
||||||
|
: account.nonce;
|
||||||
|
|
||||||
const txData = await dispatch(
|
const txData = await dispatch(
|
||||||
prepareEthereumTx({
|
prepareEthereumTx({
|
||||||
@ -727,12 +730,15 @@ export const onSend = (): AsyncAction => async (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
txData.r = signedTransaction.payload.r;
|
|
||||||
txData.s = signedTransaction.payload.s;
|
|
||||||
txData.v = signedTransaction.payload.v;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const serializedTx: string = await dispatch(serializeEthereumTx(txData));
|
const serializedTx: string = await dispatch(
|
||||||
|
serializeEthereumTx({
|
||||||
|
...txData,
|
||||||
|
r: signedTransaction.payload.r,
|
||||||
|
s: signedTransaction.payload.s,
|
||||||
|
v: signedTransaction.payload.v,
|
||||||
|
})
|
||||||
|
);
|
||||||
const push = await TrezorConnect.pushTransaction({
|
const push = await TrezorConnect.pushTransaction({
|
||||||
tx: serializedTx,
|
tx: serializedTx,
|
||||||
coin: network.shortcut,
|
coin: network.shortcut,
|
||||||
@ -746,58 +752,6 @@ export const onSend = (): AsyncAction => async (
|
|||||||
|
|
||||||
dispatch({ type: SEND.TX_COMPLETE });
|
dispatch({ type: SEND.TX_COMPLETE });
|
||||||
|
|
||||||
// ugly blockbook workaround:
|
|
||||||
// since blockbook can't emit pending notifications
|
|
||||||
// need to trigger this event from here, where we know everything about this transaction
|
|
||||||
// blockchainNotification is 'trezor-connect' BlockchainLinkTransaction type
|
|
||||||
const fee = ValidationActions.calculateFee(currentState.gasLimit, currentState.gasPrice);
|
|
||||||
const blockchainNotification = {
|
|
||||||
type: 'send',
|
|
||||||
descriptor: account.descriptor,
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
addresses: [account.descriptor],
|
|
||||||
amount: currentState.amount,
|
|
||||||
fee,
|
|
||||||
total: currentState.total,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
outputs: [
|
|
||||||
{
|
|
||||||
addresses: [currentState.address],
|
|
||||||
amount: currentState.amount,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
hash: txid,
|
|
||||||
amount: currentState.amount,
|
|
||||||
fee,
|
|
||||||
total: currentState.total,
|
|
||||||
|
|
||||||
sequence: nonce,
|
|
||||||
tokens: isToken
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
name: currentState.currency,
|
|
||||||
shortcut: currentState.currency,
|
|
||||||
value: currentState.amount,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: undefined,
|
|
||||||
|
|
||||||
blockHeight: 0,
|
|
||||||
blockHash: undefined,
|
|
||||||
timestamp: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
BlockchainActions.onNotification({
|
|
||||||
// $FlowIssue: missing coinInfo declaration
|
|
||||||
coin: {},
|
|
||||||
notification: blockchainNotification,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
// workaround end
|
|
||||||
|
|
||||||
// clear session storage
|
// clear session storage
|
||||||
dispatch(SessionStorageActions.clear());
|
dispatch(SessionStorageActions.clear());
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { Link } from 'trezor-ui-components';
|
||||||
import TrezorConnect from 'trezor-connect';
|
import TrezorConnect from 'trezor-connect';
|
||||||
import * as NOTIFICATION from 'actions/constants/notification';
|
import * as NOTIFICATION from 'actions/constants/notification';
|
||||||
import * as SEND from 'actions/constants/send';
|
import * as SEND from 'actions/constants/send';
|
||||||
@ -374,7 +375,7 @@ export const onFeeChange = (fee: string): ThunkAction => (
|
|||||||
const state: State = getState().sendFormRipple;
|
const state: State = getState().sendFormRipple;
|
||||||
|
|
||||||
// switch to custom fee level
|
// switch to custom fee level
|
||||||
let newSelectedFeeLevel = state.selectedFeeLevel;
|
let newSelectedFeeLevel;
|
||||||
if (state.selectedFeeLevel.value !== 'Custom')
|
if (state.selectedFeeLevel.value !== 'Custom')
|
||||||
newSelectedFeeLevel = state.feeLevels.find(f => f.value === 'Custom');
|
newSelectedFeeLevel = state.feeLevels.find(f => f.value === 'Custom');
|
||||||
|
|
||||||
@ -385,7 +386,7 @@ export const onFeeChange = (fee: string): ThunkAction => (
|
|||||||
...state,
|
...state,
|
||||||
untouched: false,
|
untouched: false,
|
||||||
touched: { ...state.touched, fee: true },
|
touched: { ...state.touched, fee: true },
|
||||||
selectedFeeLevel: newSelectedFeeLevel,
|
selectedFeeLevel: newSelectedFeeLevel || state.selectedFeeLevel,
|
||||||
fee,
|
fee,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -501,7 +502,11 @@ export const onSend = (): AsyncAction => async (
|
|||||||
payload: {
|
payload: {
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
title: <FormattedMessage {...l10nMessages.TR_TRANSACTION_SUCCESS} />,
|
title: <FormattedMessage {...l10nMessages.TR_TRANSACTION_SUCCESS} />,
|
||||||
message: txid,
|
message: (
|
||||||
|
<Link href={`${network.explorer.tx}${txid}`} isGreen>
|
||||||
|
<FormattedMessage {...l10nMessages.TR_SEE_TRANSACTION_DETAILS} />
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
actions: [],
|
actions: [],
|
||||||
},
|
},
|
||||||
|
@ -173,16 +173,14 @@ const addressBalanceValidation = ($state: State): PromiseAction<void> => async (
|
|||||||
if (!network) return;
|
if (!network) return;
|
||||||
|
|
||||||
let minAmount: string = '0';
|
let minAmount: string = '0';
|
||||||
const response = await TrezorConnect.rippleGetAccountInfo({
|
const response = await TrezorConnect.getAccountInfo({
|
||||||
account: {
|
descriptor: $state.address,
|
||||||
descriptor: $state.address,
|
|
||||||
},
|
|
||||||
coin: network.shortcut,
|
coin: network.shortcut,
|
||||||
});
|
});
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
const empty = response.payload.sequence <= 0 && response.payload.balance === '0';
|
if (response.payload.empty) {
|
||||||
if (empty) {
|
const reserve = response.payload.misc ? response.payload.misc.reserve : '0';
|
||||||
minAmount = toDecimalAmount(response.payload.reserve, network.decimals);
|
minAmount = toDecimalAmount(reserve || '0', network.decimals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ const Value = styled.div`
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
color: ${colors.GREEN_SECONDARY};
|
color: ${colors.GREEN_SECONDARY};
|
||||||
|
|
||||||
&.send {
|
&.sent {
|
||||||
color: ${colors.ERROR_PRIMARY};
|
color: ${colors.ERROR_PRIMARY};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -77,28 +77,27 @@ const Fee = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const TransactionItem = ({ tx, network }: Props) => {
|
const TransactionItem = ({ tx, network }: Props) => {
|
||||||
const url = `${network.explorer.tx}${tx.hash}`;
|
const url = `${network.explorer.tx}${tx.txid}`;
|
||||||
const date = typeof tx.timestamp === 'string' ? tx.timestamp : undefined; // TODO: format date
|
const date = typeof tx.blockTime === 'number' ? tx.blockTime : undefined; // TODO: format date
|
||||||
const addresses = (tx.type === 'send' ? tx.outputs : tx.inputs).reduce(
|
const addresses = tx.targets.reduce((arr, item) => arr.concat(item.addresses), []);
|
||||||
(arr, item) => arr.concat(item.addresses),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const operation = tx.type === 'send' ? '-' : '+';
|
const operation = tx.type === 'sent' ? '-' : '+';
|
||||||
const amount = tx.tokens ? (
|
const amount =
|
||||||
tx.tokens.map(t => (
|
tx.tokens.length > 0 ? (
|
||||||
<Amount key={t.value}>
|
tx.tokens.map(t => (
|
||||||
|
<Amount key={t.symbol}>
|
||||||
|
{operation}
|
||||||
|
{t.amount} {t.symbol}
|
||||||
|
</Amount>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Amount>
|
||||||
{operation}
|
{operation}
|
||||||
{t.value} {t.shortcut}
|
{tx.amount} {network.symbol}
|
||||||
</Amount>
|
</Amount>
|
||||||
))
|
);
|
||||||
) : (
|
const fee =
|
||||||
<Amount>
|
tx.tokens.length > 0 && tx.type === 'sent' ? `${tx.fee} ${network.symbol}` : undefined;
|
||||||
{operation}
|
|
||||||
{tx.total} {network.symbol}
|
|
||||||
</Amount>
|
|
||||||
);
|
|
||||||
const fee = tx.tokens && tx.type === 'send' ? `${tx.fee} ${network.symbol}` : undefined;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
@ -113,7 +112,7 @@ const TransactionItem = ({ tx, network }: Props) => {
|
|||||||
))}
|
))}
|
||||||
{!tx.blockHeight && (
|
{!tx.blockHeight && (
|
||||||
<TransactionHash href={url} isGray>
|
<TransactionHash href={url} isGray>
|
||||||
Transaction hash: {tx.hash}
|
Transaction hash: {tx.txid}
|
||||||
</TransactionHash>
|
</TransactionHash>
|
||||||
)}
|
)}
|
||||||
</Addresses>
|
</Addresses>
|
||||||
|
@ -17,12 +17,12 @@ const add = (state: State, payload: Transaction): State => {
|
|||||||
const removeByDeviceState = (state: State, deviceState: ?string): State =>
|
const removeByDeviceState = (state: State, deviceState: ?string): State =>
|
||||||
state.filter(tx => tx.deviceState !== deviceState);
|
state.filter(tx => tx.deviceState !== deviceState);
|
||||||
|
|
||||||
const removeByHash = (state: State, hash: string): State => state.filter(tx => tx.hash !== hash);
|
const removeByHash = (state: State, hash: string): State => state.filter(tx => tx.txid !== hash);
|
||||||
|
|
||||||
const reject = (state: State, hash: string): State =>
|
const reject = (state: State, hash: string): State =>
|
||||||
state.map(tx => {
|
state.map(tx => {
|
||||||
if (tx.hash === hash && !tx.rejected) {
|
if (tx.txid === hash && !tx.rejected) {
|
||||||
return { ...tx, rejected: true };
|
return Object.assign({}, { rejected: true }, tx);
|
||||||
}
|
}
|
||||||
return tx;
|
return tx;
|
||||||
});
|
});
|
||||||
|
@ -27,11 +27,7 @@ export const getSelectedDevice = (state: State): ?TrezorDevice => {
|
|||||||
if (d.mode === 'bootloader' && d.path === locationState.device) {
|
if (d.mode === 'bootloader' && d.path === locationState.device) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (d.features && d.id === locationState.device && d.instance === instance) {
|
||||||
d.features &&
|
|
||||||
d.features.device_id === locationState.device &&
|
|
||||||
d.instance === instance
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -46,7 +42,7 @@ export const findDevice = (
|
|||||||
): ?TrezorDevice =>
|
): ?TrezorDevice =>
|
||||||
devices.find(d => {
|
devices.find(d => {
|
||||||
// TODO: && (instance && d.instance === instance)
|
// TODO: && (instance && d.instance === instance)
|
||||||
if (d.features && d.features.device_id === deviceId && d.state === deviceState) {
|
if (d.features && d.id === deviceId && d.state === deviceState) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -60,9 +56,7 @@ export const getDuplicateInstanceNumber = (
|
|||||||
// find device(s) with the same features.device_id
|
// find device(s) with the same features.device_id
|
||||||
// and sort them by instance number
|
// and sort them by instance number
|
||||||
const affectedDevices: Array<TrezorDevice> = devices
|
const affectedDevices: Array<TrezorDevice> = devices
|
||||||
.filter(
|
.filter(d => d.features && device.features && d.id === device.id)
|
||||||
d => d.features && device.features && d.features.device_id === device.features.device_id
|
|
||||||
)
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (!a.instance) {
|
if (!a.instance) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -92,8 +86,7 @@ export const getSelectedAccount = (state: State): ?Account => {
|
|||||||
return state.accounts.find(
|
return state.accounts.find(
|
||||||
a =>
|
a =>
|
||||||
a.imported === isImported &&
|
a.imported === isImported &&
|
||||||
(a.deviceState === device.state ||
|
(a.deviceState === device.state || (a.imported && a.deviceID === device.id)) &&
|
||||||
(a.imported && a.deviceID === (device.features || {}).device_id)) &&
|
|
||||||
a.index === index &&
|
a.index === index &&
|
||||||
a.network === locationState.network
|
a.network === locationState.network
|
||||||
);
|
);
|
||||||
@ -129,8 +122,8 @@ export const getAccountPendingTx = (
|
|||||||
|
|
||||||
export const getPendingSequence = (pending: Array<Transaction>): number =>
|
export const getPendingSequence = (pending: Array<Transaction>): number =>
|
||||||
pending.reduce((value: number, tx: Transaction): number => {
|
pending.reduce((value: number, tx: Transaction): number => {
|
||||||
if (tx.rejected) return value;
|
if (!tx.ethereumSpecific || tx.rejected) return value;
|
||||||
return Math.max(value, tx.sequence + 1);
|
return Math.max(value, tx.ethereumSpecific.nonce + 1);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
export const getPendingAmount = (
|
export const getPendingAmount = (
|
||||||
@ -139,7 +132,7 @@ export const getPendingAmount = (
|
|||||||
token: boolean = false
|
token: boolean = false
|
||||||
): BigNumber =>
|
): BigNumber =>
|
||||||
pending.reduce((value: BigNumber, tx: Transaction): BigNumber => {
|
pending.reduce((value: BigNumber, tx: Transaction): BigNumber => {
|
||||||
if (tx.type !== 'send') return value;
|
if (tx.type !== 'sent') return value;
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// regular transactions
|
// regular transactions
|
||||||
// add fees from token txs and amount from regular txs
|
// add fees from token txs and amount from regular txs
|
||||||
@ -147,9 +140,9 @@ export const getPendingAmount = (
|
|||||||
}
|
}
|
||||||
if (tx.tokens) {
|
if (tx.tokens) {
|
||||||
// token transactions
|
// token transactions
|
||||||
const allTokens = tx.tokens.filter(t => t.shortcut === currency);
|
const allTokens = tx.tokens.filter(t => t.symbol === currency);
|
||||||
const tokensValue: BigNumber = allTokens.reduce(
|
const tokensValue: BigNumber = allTokens.reduce(
|
||||||
(tv, t) => new BigNumber(value).plus(t.value),
|
(tv, t) => new BigNumber(value).plus(t.amount),
|
||||||
new BigNumber('0')
|
new BigNumber('0')
|
||||||
);
|
);
|
||||||
return new BigNumber(value).plus(tokensValue);
|
return new BigNumber(value).plus(tokensValue);
|
||||||
|
114
src/utils/accountUtils.js
Normal file
114
src/utils/accountUtils.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/* @flow */
|
||||||
|
import { toDecimalAmount } from 'utils/formatUtils';
|
||||||
|
import type { AccountInfo, AccountTransaction } from 'trezor-connect';
|
||||||
|
import type { Account, Transaction, Network, TrezorDevice } from 'flowtype';
|
||||||
|
|
||||||
|
// Merge fresh AccountInfo into existing Account
|
||||||
|
export const mergeAccount = (
|
||||||
|
info: AccountInfo,
|
||||||
|
account: Account,
|
||||||
|
network: Network,
|
||||||
|
block: number
|
||||||
|
): Account => {
|
||||||
|
if (account.networkType === 'ethereum') {
|
||||||
|
const nonce = info.misc && info.misc.nonce ? info.misc.nonce : '0';
|
||||||
|
return {
|
||||||
|
networkType: 'ethereum',
|
||||||
|
...account,
|
||||||
|
balance: toDecimalAmount(info.balance, network.decimals),
|
||||||
|
availableBalance: toDecimalAmount(info.availableBalance, network.decimals),
|
||||||
|
block,
|
||||||
|
transactions: info.history.total,
|
||||||
|
empty: account.empty,
|
||||||
|
nonce,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (account.networkType === 'ripple') {
|
||||||
|
const sequence = info.misc && info.misc.sequence ? info.misc.sequence : 0;
|
||||||
|
const reserve = info.misc && info.misc.reserve ? info.misc.reserve : '0';
|
||||||
|
return {
|
||||||
|
...account,
|
||||||
|
balance: toDecimalAmount(info.balance, network.decimals),
|
||||||
|
availableBalance: toDecimalAmount(info.availableBalance, network.decimals),
|
||||||
|
block,
|
||||||
|
empty: info.empty,
|
||||||
|
|
||||||
|
networkType: 'ripple',
|
||||||
|
sequence,
|
||||||
|
reserve: toDecimalAmount(reserve || '0', network.decimals),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return account;
|
||||||
|
};
|
||||||
|
|
||||||
|
type EnhanceAccountOptions = {
|
||||||
|
index: number,
|
||||||
|
network: Network,
|
||||||
|
device: TrezorDevice,
|
||||||
|
imported?: boolean,
|
||||||
|
block?: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create Account from AccountInfo
|
||||||
|
export const enhanceAccount = (account: AccountInfo, options: EnhanceAccountOptions): Account => {
|
||||||
|
if (options.network.type === 'ethereum') {
|
||||||
|
const nonce = account.misc && account.misc.nonce ? account.misc.nonce : '0';
|
||||||
|
return {
|
||||||
|
imported: !!options.imported,
|
||||||
|
index: options.index,
|
||||||
|
network: options.network.shortcut,
|
||||||
|
deviceID: options.device.id || '0',
|
||||||
|
deviceState: options.device.state || '0',
|
||||||
|
accountPath: account.path,
|
||||||
|
descriptor: account.descriptor,
|
||||||
|
|
||||||
|
balance: toDecimalAmount(account.balance, options.network.decimals),
|
||||||
|
availableBalance: toDecimalAmount(account.availableBalance, options.network.decimals),
|
||||||
|
block: options.block || 0,
|
||||||
|
transactions: account.history.total,
|
||||||
|
empty: account.empty,
|
||||||
|
|
||||||
|
networkType: 'ethereum',
|
||||||
|
nonce,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const sequence = account.misc && account.misc.sequence ? account.misc.sequence : 0;
|
||||||
|
const reserve = account.misc && account.misc.reserve ? account.misc.reserve : '0';
|
||||||
|
return {
|
||||||
|
imported: !!options.imported,
|
||||||
|
index: options.index,
|
||||||
|
network: options.network.shortcut,
|
||||||
|
deviceID: options.device.id || '0',
|
||||||
|
deviceState: options.device.state || '0',
|
||||||
|
accountPath: account.path,
|
||||||
|
descriptor: account.descriptor,
|
||||||
|
|
||||||
|
balance: toDecimalAmount(account.balance, options.network.decimals),
|
||||||
|
availableBalance: toDecimalAmount(account.availableBalance, options.network.decimals),
|
||||||
|
block: options.block || 0,
|
||||||
|
transactions: 0,
|
||||||
|
empty: account.empty,
|
||||||
|
|
||||||
|
networkType: 'ripple',
|
||||||
|
sequence,
|
||||||
|
reserve: toDecimalAmount(reserve, options.network.decimals),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enhanceTransaction = (
|
||||||
|
account: Account,
|
||||||
|
tx: AccountTransaction,
|
||||||
|
network: Network
|
||||||
|
): Transaction => {
|
||||||
|
return {
|
||||||
|
...tx,
|
||||||
|
descriptor: account.descriptor,
|
||||||
|
deviceState: account.deviceState,
|
||||||
|
network: account.network,
|
||||||
|
amount: toDecimalAmount(tx.amount, network.decimals),
|
||||||
|
fee: toDecimalAmount(tx.fee, network.decimals),
|
||||||
|
};
|
||||||
|
};
|
@ -31,7 +31,7 @@ const PendingTransactions = (props: Props) => {
|
|||||||
<NoTransactions>There are no pending transactions</NoTransactions>
|
<NoTransactions>There are no pending transactions</NoTransactions>
|
||||||
)}
|
)}
|
||||||
{pending.map(tx => (
|
{pending.map(tx => (
|
||||||
<Transaction key={tx.hash} network={props.network} tx={tx} />
|
<Transaction key={tx.txid} network={props.network} tx={tx} />
|
||||||
))}
|
))}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
@ -521,14 +521,13 @@ const AccountSend = (props: Props) => {
|
|||||||
</AdvancedForm>
|
</AdvancedForm>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{props.selectedAccount.pending.length > 0 ||
|
{props.selectedAccount.pending.length > 0 && (
|
||||||
(account.imported && (
|
<PendingTransactions
|
||||||
<PendingTransactions
|
pending={props.selectedAccount.pending}
|
||||||
pending={props.selectedAccount.pending}
|
tokens={props.selectedAccount.tokens}
|
||||||
tokens={props.selectedAccount.tokens}
|
network={network}
|
||||||
network={network}
|
/>
|
||||||
/>
|
)}
|
||||||
))}
|
|
||||||
</Content>
|
</Content>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user