mirror of
https://github.com/trezor/trezor-wallet
synced 2025-03-03 09:46:06 +00:00
commit
cf76e8cf68
@ -69,7 +69,7 @@
|
|||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
"styled-components": "^4.1.2",
|
"styled-components": "^4.1.2",
|
||||||
"styled-normalize": "^8.0.4",
|
"styled-normalize": "^8.0.4",
|
||||||
"trezor-connect": "6.0.3-beta.4",
|
"trezor-connect": "6.0.3-beta.5",
|
||||||
"web3": "1.0.0-beta.35",
|
"web3": "1.0.0-beta.35",
|
||||||
"webpack": "^4.16.3",
|
"webpack": "^4.16.3",
|
||||||
"webpack-build-notifier": "^0.1.29",
|
"webpack-build-notifier": "^0.1.29",
|
||||||
|
@ -1,17 +1,5 @@
|
|||||||
{
|
{
|
||||||
"networks": [
|
"networks": [
|
||||||
{
|
|
||||||
"type": "ripple",
|
|
||||||
"name": "Ripple Testnet",
|
|
||||||
"testnet": true,
|
|
||||||
"symbol": "XRP",
|
|
||||||
"shortcut": "xrp",
|
|
||||||
"bip44": "m/44'/144'/a'/0/0",
|
|
||||||
"explorer": {
|
|
||||||
"tx": "https://sisyfos.trezor.io/ripple-testnet-explorer/tx/",
|
|
||||||
"address": "https://sisyfos.trezor.io/ripple-testnet-explorer/address/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "ethereum",
|
"type": "ethereum",
|
||||||
"name": "Ethereum",
|
"name": "Ethereum",
|
||||||
@ -22,6 +10,7 @@
|
|||||||
"defaultGasPrice": 64,
|
"defaultGasPrice": 64,
|
||||||
"defaultGasLimit": 21000,
|
"defaultGasLimit": 21000,
|
||||||
"defaultGasLimitTokens": 200000,
|
"defaultGasLimitTokens": 200000,
|
||||||
|
"decimals": 18,
|
||||||
"tokens": "./data/ethereumTokens.json",
|
"tokens": "./data/ethereumTokens.json",
|
||||||
"web3": [
|
"web3": [
|
||||||
"wss://eth2.trezor.io/geth"
|
"wss://eth2.trezor.io/geth"
|
||||||
@ -41,6 +30,7 @@
|
|||||||
"defaultGasPrice": 64,
|
"defaultGasPrice": 64,
|
||||||
"defaultGasLimit": 21000,
|
"defaultGasLimit": 21000,
|
||||||
"defaultGasLimitTokens": 200000,
|
"defaultGasLimitTokens": 200000,
|
||||||
|
"decimals": 18,
|
||||||
"tokens": "./data/ethereumClassicTokens.json",
|
"tokens": "./data/ethereumClassicTokens.json",
|
||||||
"web3": [
|
"web3": [
|
||||||
"wss://etc2.trezor.io/geth"
|
"wss://etc2.trezor.io/geth"
|
||||||
@ -61,6 +51,7 @@
|
|||||||
"defaultGasPrice": 64,
|
"defaultGasPrice": 64,
|
||||||
"defaultGasLimit": 21000,
|
"defaultGasLimit": 21000,
|
||||||
"defaultGasLimitTokens": 200000,
|
"defaultGasLimitTokens": 200000,
|
||||||
|
"decimals": 18,
|
||||||
"tokens": "./data/ropstenTokens.json",
|
"tokens": "./data/ropstenTokens.json",
|
||||||
"web3": [
|
"web3": [
|
||||||
"wss://ropsten1.trezor.io/geth"
|
"wss://ropsten1.trezor.io/geth"
|
||||||
@ -69,6 +60,31 @@
|
|||||||
"tx": "https://ropsten.etherscan.io/tx/",
|
"tx": "https://ropsten.etherscan.io/tx/",
|
||||||
"address": "https://ropsten.etherscan.io/address/"
|
"address": "https://ropsten.etherscan.io/address/"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ripple",
|
||||||
|
"name": "Ripple",
|
||||||
|
"symbol": "XRP",
|
||||||
|
"shortcut": "xrp",
|
||||||
|
"bip44": "m/44'/144'/a'/0/0",
|
||||||
|
"decimals": 6,
|
||||||
|
"explorer": {
|
||||||
|
"tx": "https://xrpcharts.ripple.com/#/transactions/",
|
||||||
|
"address": "https://xrpcharts.ripple.com/#/graph/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ripple",
|
||||||
|
"name": "Ripple Testnet",
|
||||||
|
"testnet": true,
|
||||||
|
"symbol": "tXRP",
|
||||||
|
"shortcut": "txrp",
|
||||||
|
"bip44": "m/44'/144'/a'/0/0",
|
||||||
|
"decimals": 6,
|
||||||
|
"explorer": {
|
||||||
|
"tx": "https://sisyfos.trezor.io/ripple-testnet-explorer/tx/",
|
||||||
|
"address": "https://sisyfos.trezor.io/ripple-testnet-explorer/address/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ export const onNotification = (payload: $ElementType<BlockchainNotification, 'pa
|
|||||||
switch (network.type) {
|
switch (network.type) {
|
||||||
case 'ethereum':
|
case 'ethereum':
|
||||||
// this is not working until blockchain-link will start support blockbook backends
|
// this is not working until blockchain-link will start support blockbook backends
|
||||||
await dispatch(EthereumBlockchainActions.onNotification());
|
await dispatch(EthereumBlockchainActions.onNotification(payload));
|
||||||
break;
|
break;
|
||||||
case 'ripple':
|
case 'ripple':
|
||||||
await dispatch(RippleBlockchainActions.onNotification(payload));
|
await dispatch(RippleBlockchainActions.onNotification(payload));
|
||||||
|
@ -15,7 +15,6 @@ import * as storageUtils from 'utils/storage';
|
|||||||
import { findAccountTokens } from 'reducers/TokensReducer';
|
import { findAccountTokens } from 'reducers/TokensReducer';
|
||||||
import type { Account } from 'reducers/AccountsReducer';
|
import type { Account } from 'reducers/AccountsReducer';
|
||||||
import type { Token } from 'reducers/TokensReducer';
|
import type { Token } from 'reducers/TokensReducer';
|
||||||
import type { PendingTx } from 'reducers/PendingTxReducer';
|
|
||||||
import type { Discovery } from 'reducers/DiscoveryReducer';
|
import type { Discovery } from 'reducers/DiscoveryReducer';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@ -24,6 +23,7 @@ import type {
|
|||||||
AsyncAction,
|
AsyncAction,
|
||||||
GetState,
|
GetState,
|
||||||
Dispatch,
|
Dispatch,
|
||||||
|
Transaction,
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
import type { Config, Network, TokensCollection } from 'reducers/LocalStorageReducer';
|
import type { Config, Network, TokensCollection } from 'reducers/LocalStorageReducer';
|
||||||
|
|
||||||
@ -61,15 +61,15 @@ const findAccounts = (devices: Array<TrezorDevice>, accounts: Array<Account>): A
|
|||||||
|
|
||||||
const findTokens = (accounts: Array<Account>, tokens: Array<Token>): Array<Token> => accounts.reduce((arr, account) => arr.concat(findAccountTokens(tokens, account)), []);
|
const findTokens = (accounts: Array<Account>, tokens: Array<Token>): Array<Token> => accounts.reduce((arr, account) => arr.concat(findAccountTokens(tokens, account)), []);
|
||||||
|
|
||||||
const findDiscovery = (devices: Array<TrezorDevice>, discovery: Array<Discovery>): Array<Discovery> => devices.reduce((arr, dev) => arr.concat(discovery.filter(a => a.deviceState === dev.state && a.publicKey.length > 0)), []);
|
const findDiscovery = (devices: Array<TrezorDevice>, discovery: Array<Discovery>): Array<Discovery> => devices.reduce((arr, dev) => arr.concat(discovery.filter(d => d.deviceState === dev.state && d.completed)), []);
|
||||||
|
|
||||||
const findPendingTxs = (accounts: Array<Account>, pending: Array<PendingTx>): Array<PendingTx> => accounts.reduce((result, account) => result.concat(pending.filter(p => p.address === account.address && p.network === account.network)), []);
|
const findPendingTxs = (accounts: Array<Account>, pending: Array<Transaction>): Array<Transaction> => accounts.reduce((result, account) => result.concat(pending.filter(p => p.address === account.address && p.network === account.network)), []);
|
||||||
|
|
||||||
export const save = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
export const save = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const devices: Array<TrezorDevice> = getState().devices.filter(d => d.features && d.remember === true);
|
const devices: Array<TrezorDevice> = getState().devices.filter(d => d.features && d.remember === true);
|
||||||
const accounts: Array<Account> = findAccounts(devices, getState().accounts);
|
const accounts: Array<Account> = findAccounts(devices, getState().accounts);
|
||||||
const tokens: Array<Token> = findTokens(accounts, getState().tokens);
|
const tokens: Array<Token> = findTokens(accounts, getState().tokens);
|
||||||
const pending: Array<PendingTx> = findPendingTxs(accounts, getState().pending);
|
const pending: Array<Transaction> = findPendingTxs(accounts, getState().pending);
|
||||||
const discovery: Array<Discovery> = findDiscovery(devices, getState().discovery);
|
const discovery: Array<Discovery> = findDiscovery(devices, getState().discovery);
|
||||||
|
|
||||||
// save devices
|
// save devices
|
||||||
|
@ -3,14 +3,15 @@
|
|||||||
|
|
||||||
import * as PENDING from 'actions/constants/pendingTx';
|
import * as PENDING from 'actions/constants/pendingTx';
|
||||||
|
|
||||||
import type { State, PendingTx } from 'reducers/PendingTxReducer';
|
import type { Transaction } from 'flowtype';
|
||||||
|
import type { State } from 'reducers/PendingTxReducer';
|
||||||
|
|
||||||
export type PendingTxAction = {
|
export type PendingTxAction = {
|
||||||
type: typeof PENDING.FROM_STORAGE,
|
type: typeof PENDING.FROM_STORAGE,
|
||||||
payload: State
|
payload: State
|
||||||
} | {
|
} | {
|
||||||
type: typeof PENDING.ADD,
|
type: typeof PENDING.ADD,
|
||||||
payload: PendingTx
|
payload: Transaction
|
||||||
} | {
|
} | {
|
||||||
type: typeof PENDING.TX_RESOLVED,
|
type: typeof PENDING.TX_RESOLVED,
|
||||||
hash: string,
|
hash: string,
|
||||||
|
@ -289,9 +289,7 @@ export const estimateGasLimit = (network: string, $options: EstimateGasOptions):
|
|||||||
return limit.toString();
|
return limit.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const disconnect = (coinInfo: any): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
export const disconnect = (network: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||||
// incoming "coinInfo" from TrezorConnect is CoinInfo | EthereumNetwork type
|
|
||||||
const network: string = coinInfo.shortcut.toLowerCase();
|
|
||||||
// check if Web3 was already initialized
|
// check if Web3 was already initialized
|
||||||
const instance = getState().web3.find(w3 => w3.network === network);
|
const instance = getState().web3.find(w3 => w3.network === network);
|
||||||
if (instance) {
|
if (instance) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import TrezorConnect from 'trezor-connect';
|
import TrezorConnect from 'trezor-connect';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
import * as PENDING from 'actions/constants/pendingTx';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
TrezorDevice,
|
TrezorDevice,
|
||||||
@ -9,7 +10,7 @@ import type {
|
|||||||
GetState,
|
GetState,
|
||||||
PromiseAction,
|
PromiseAction,
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
import type { EthereumAccount } from 'trezor-connect';
|
import type { EthereumAccount, BlockchainNotification } from 'trezor-connect';
|
||||||
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 Web3Actions from 'actions/Web3Actions';
|
import * as Web3Actions from 'actions/Web3Actions';
|
||||||
@ -85,10 +86,11 @@ export const estimateGasLimit = (network: string, data: string, value: string, g
|
|||||||
|
|
||||||
export const subscribe = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
export const subscribe = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const accounts: Array<string> = getState().accounts.filter(a => a.network === network).map(a => a.address); // eslint-disable-line no-unused-vars
|
const accounts: Array<string> = getState().accounts.filter(a => a.network === network).map(a => a.address); // eslint-disable-line no-unused-vars
|
||||||
await TrezorConnect.blockchainSubscribe({
|
const response = await TrezorConnect.blockchainSubscribe({
|
||||||
accounts,
|
accounts,
|
||||||
coin: network,
|
coin: network,
|
||||||
});
|
});
|
||||||
|
if (!response.success) return;
|
||||||
// init web3 instance if not exists
|
// init web3 instance if not exists
|
||||||
await dispatch(Web3Actions.initWeb3(network));
|
await dispatch(Web3Actions.initWeb3(network));
|
||||||
};
|
};
|
||||||
@ -125,45 +127,21 @@ export const onBlockMined = (network: string): PromiseAction<void> => async (dis
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onNotification = (/*network: string*/): PromiseAction<void> => async (): Promise<void> => {
|
export const onNotification = (payload: $ElementType<BlockchainNotification, 'payload'>): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
// todo: get transaction history here
|
const { notification } = payload;
|
||||||
// console.warn("OnBlAccount", account);
|
const account = getState().accounts.find(a => a.address === notification.address);
|
||||||
// this event can be triggered multiple times
|
if (!account) return;
|
||||||
// // 1. check if pair [txid + address] is already in reducer
|
|
||||||
// const network: string = payload.coin.shortcut.toLowerCase();
|
|
||||||
// const address: string = EthereumjsUtil.toChecksumAddress(payload.tx.address);
|
|
||||||
// const txInfo = await dispatch(Web3Actions.getPendingInfo(network, payload.tx.txid));
|
|
||||||
|
|
||||||
// // const exists = getState().pending.filter(p => p.id === payload.tx.txid && p.address === address);
|
if (notification.status === 'pending') {
|
||||||
// const exists = getState().pending.filter(p => p.address === address);
|
dispatch({
|
||||||
// if (exists.length < 1) {
|
type: PENDING.ADD,
|
||||||
// if (txInfo) {
|
payload: {
|
||||||
// dispatch({
|
...notification,
|
||||||
// type: PENDING.ADD,
|
deviceState: account.deviceState,
|
||||||
// payload: {
|
network: account.network,
|
||||||
// type: 'send',
|
},
|
||||||
// id: payload.tx.txid,
|
});
|
||||||
// network,
|
}
|
||||||
// currency: 'tETH',
|
|
||||||
// amount: txInfo.value,
|
|
||||||
// total: '0',
|
|
||||||
// tx: {},
|
|
||||||
// nonce: txInfo.nonce,
|
|
||||||
// address,
|
|
||||||
// rejected: false,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// // tx info not found (yet?)
|
|
||||||
// // dispatch({
|
|
||||||
// // type: PENDING.ADD_UNKNOWN,
|
|
||||||
// // payload: {
|
|
||||||
// // network,
|
|
||||||
// // ...payload.tx,
|
|
||||||
// // }
|
|
||||||
// // });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onError = (network: string): PromiseAction<void> => async (dispatch: Dispatch): Promise<void> => {
|
export const onError = (network: string): PromiseAction<void> => async (dispatch: Dispatch): Promise<void> => {
|
||||||
|
@ -6,7 +6,6 @@ import BigNumber from 'bignumber.js';
|
|||||||
import * as ACCOUNT from 'actions/constants/account';
|
import * as ACCOUNT from 'actions/constants/account';
|
||||||
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';
|
||||||
import * as PENDING from 'actions/constants/pendingTx';
|
|
||||||
import * as WEB3 from 'actions/constants/web3';
|
import * as WEB3 from 'actions/constants/web3';
|
||||||
import { initialState } from 'reducers/SendFormEthereumReducer';
|
import { initialState } from 'reducers/SendFormEthereumReducer';
|
||||||
import { findToken } from 'reducers/TokensReducer';
|
import { findToken } from 'reducers/TokensReducer';
|
||||||
@ -525,21 +524,45 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge
|
|||||||
|
|
||||||
dispatch({ type: SEND.TX_COMPLETE });
|
dispatch({ type: SEND.TX_COMPLETE });
|
||||||
|
|
||||||
dispatch({
|
// ugly blockbook workaround:
|
||||||
type: PENDING.ADD,
|
// since blockbook can't emit pending notifications
|
||||||
payload: {
|
// 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',
|
type: 'send',
|
||||||
deviceState: account.deviceState,
|
status: 'pending',
|
||||||
sequence: nonce,
|
confirmations: 0,
|
||||||
hash: txid,
|
|
||||||
network: account.network,
|
|
||||||
address: account.address,
|
address: account.address,
|
||||||
currency: currentState.currency,
|
inputs: [
|
||||||
|
{
|
||||||
|
addresses: [account.address],
|
||||||
amount: currentState.amount,
|
amount: currentState.amount,
|
||||||
|
fee,
|
||||||
total: currentState.total,
|
total: currentState.total,
|
||||||
fee: '0', // TODO: calculate fee
|
|
||||||
},
|
},
|
||||||
});
|
],
|
||||||
|
outputs: [
|
||||||
|
{
|
||||||
|
addresses: [currentState.address],
|
||||||
|
amount: currentState.amount,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hash: txid,
|
||||||
|
amount: currentState.amount,
|
||||||
|
fee,
|
||||||
|
total: currentState.total,
|
||||||
|
|
||||||
|
sequence: nonce,
|
||||||
|
currency: isToken ? currentState.currency : 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,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
import TrezorConnect from 'trezor-connect';
|
import TrezorConnect from 'trezor-connect';
|
||||||
import * as BLOCKCHAIN from 'actions/constants/blockchain';
|
// import * as BLOCKCHAIN from 'actions/constants/blockchain';
|
||||||
import * as PENDING from 'actions/constants/pendingTx';
|
import * as PENDING from 'actions/constants/pendingTx';
|
||||||
import * as AccountsActions from 'actions/AccountsActions';
|
import * as AccountsActions from 'actions/AccountsActions';
|
||||||
import { toDecimalAmount } from 'utils/formatUtils';
|
import { toDecimalAmount } from 'utils/formatUtils';
|
||||||
@ -13,6 +13,7 @@ import type {
|
|||||||
PromiseAction,
|
PromiseAction,
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
|
|
||||||
|
const DECIMALS: number = 6;
|
||||||
|
|
||||||
export const subscribe = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
export const subscribe = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const accounts: Array<string> = getState().accounts.filter(a => a.network === network).map(a => a.address);
|
const accounts: Array<string> = getState().accounts.filter(a => a.network === network).map(a => a.address);
|
||||||
@ -22,22 +23,47 @@ export const subscribe = (network: string): PromiseAction<void> => async (dispat
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const onBlockMined = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
export const onBlockMined = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const fee = await TrezorConnect.blockchainGetFee({
|
|
||||||
coin: network,
|
|
||||||
});
|
|
||||||
if (!fee.success) return;
|
|
||||||
|
|
||||||
const blockchain = getState().blockchain.find(b => b.shortcut === network);
|
const blockchain = getState().blockchain.find(b => b.shortcut === network);
|
||||||
if (!blockchain) return;
|
if (!blockchain) return;
|
||||||
|
|
||||||
if (fee.payload !== blockchain.fee) {
|
// const fee = await TrezorConnect.blockchainGetFee({
|
||||||
dispatch({
|
// coin: network,
|
||||||
type: BLOCKCHAIN.UPDATE_FEE,
|
// });
|
||||||
shortcut: network,
|
// if (!fee.success) return;
|
||||||
fee: fee.payload,
|
|
||||||
});
|
// if (fee.payload !== blockchain.fee) {
|
||||||
|
// dispatch({
|
||||||
|
// type: BLOCKCHAIN.UPDATE_FEE,
|
||||||
|
// shortcut: network,
|
||||||
|
// fee: fee.payload,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
const accounts: Array<any> = getState().accounts.filter(a => a.network === network);
|
||||||
|
// console.warn('ACCOUNTS', accounts);
|
||||||
|
if (accounts.length > 0) {
|
||||||
|
// const response = await TrezorConnect.rippleGetAccountInfo({
|
||||||
|
// bundle: accounts,
|
||||||
|
// level: 'transactions',
|
||||||
|
// coin: network,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.warn('APDEJT RESP', response);
|
||||||
|
// if (!response.success) return;
|
||||||
|
|
||||||
|
// response.payload.forEach((a, i) => {
|
||||||
|
// if (a.transactions.length > 0) {
|
||||||
|
// console.warn('APDEJTED!', a, i);
|
||||||
|
// dispatch(AccountsActions.update({
|
||||||
|
// ...accounts[i],
|
||||||
|
// balance: toDecimalAmount(a.balance, DECIMALS),
|
||||||
|
// availableBalance: toDecimalAmount(a.availableBalance, DECIMALS),
|
||||||
|
// block: a.block,
|
||||||
|
// sequence: a.sequence,
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,16 +76,13 @@ export const onNotification = (payload: $ElementType<BlockchainNotification, 'pa
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: PENDING.ADD,
|
type: PENDING.ADD,
|
||||||
payload: {
|
payload: {
|
||||||
type: notification.type,
|
...notification,
|
||||||
deviceState: account.deviceState,
|
deviceState: account.deviceState,
|
||||||
sequence: account.sequence,
|
|
||||||
hash: notification.hash,
|
|
||||||
network: account.network,
|
network: account.network,
|
||||||
address: account.address,
|
|
||||||
currency: account.network,
|
amount: toDecimalAmount(notification.amount, DECIMALS),
|
||||||
amount: notification.amount,
|
total: notification.type === 'send' ? toDecimalAmount(notification.total, DECIMALS) : toDecimalAmount(notification.amount, DECIMALS),
|
||||||
total: notification.amount,
|
fee: toDecimalAmount(notification.fee, DECIMALS),
|
||||||
fee: notification.fee,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -74,16 +97,17 @@ export const onNotification = (payload: $ElementType<BlockchainNotification, 'pa
|
|||||||
const updatedAccount = await TrezorConnect.rippleGetAccountInfo({
|
const updatedAccount = await TrezorConnect.rippleGetAccountInfo({
|
||||||
account: {
|
account: {
|
||||||
address: account.address,
|
address: account.address,
|
||||||
block: account.block,
|
from: account.block,
|
||||||
history: false,
|
history: false,
|
||||||
},
|
},
|
||||||
|
coin: account.network,
|
||||||
});
|
});
|
||||||
if (!updatedAccount.success) return;
|
if (!updatedAccount.success) return;
|
||||||
|
|
||||||
dispatch(AccountsActions.update({
|
dispatch(AccountsActions.update({
|
||||||
...account,
|
...account,
|
||||||
balance: toDecimalAmount(updatedAccount.payload.balance, 6),
|
balance: toDecimalAmount(updatedAccount.payload.balance, DECIMALS),
|
||||||
availableDevice: toDecimalAmount(updatedAccount.payload.availableBalance, 6),
|
availableBalance: toDecimalAmount(updatedAccount.payload.availableBalance, DECIMALS),
|
||||||
block: updatedAccount.payload.block,
|
block: updatedAccount.payload.block,
|
||||||
sequence: updatedAccount.payload.sequence,
|
sequence: updatedAccount.payload.sequence,
|
||||||
}));
|
}));
|
||||||
|
@ -48,6 +48,7 @@ export const discoverAccount = (device: TrezorDevice, discoveryProcess: Discover
|
|||||||
},
|
},
|
||||||
keepSession: true, // acquire and hold session
|
keepSession: true, // acquire and hold session
|
||||||
useEmptyPassphrase: device.useEmptyPassphrase,
|
useEmptyPassphrase: device.useEmptyPassphrase,
|
||||||
|
coin: network.shortcut,
|
||||||
});
|
});
|
||||||
|
|
||||||
// handle TREZOR response error
|
// handle TREZOR response error
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
import React from 'react';
|
|
||||||
import Link from 'components/Link';
|
|
||||||
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';
|
||||||
@ -250,7 +248,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge
|
|||||||
payload: {
|
payload: {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Transaction success',
|
title: 'Transaction success',
|
||||||
message: <Link href={`${network.explorer.tx}${txid}`} isGreen>See transaction detail</Link>,
|
message: txid,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
actions: [],
|
actions: [],
|
||||||
},
|
},
|
||||||
|
104
src/components/Transaction/index.js
Normal file
104
src/components/Transaction/index.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/* @flow */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import colors from 'config/colors';
|
||||||
|
import Link from 'components/Link';
|
||||||
|
|
||||||
|
import type { Transaction, Network } from 'flowtype';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tx: Transaction,
|
||||||
|
network: Network,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
border-bottom: 1px solid ${colors.DIVIDER};
|
||||||
|
padding: 14px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Addresses = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Address = styled.div`
|
||||||
|
word-break: break-all;
|
||||||
|
padding: 2px 0px;
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Date = styled(Link)`
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
padding-right: 8px;
|
||||||
|
border-bottom: 0px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Value = styled.div`
|
||||||
|
padding-left: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
color: ${colors.GREEN_SECONDARY};
|
||||||
|
|
||||||
|
&.send {
|
||||||
|
color: ${colors.ERROR_PRIMARY};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Amount = styled.div`
|
||||||
|
border: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Fee = styled.div`
|
||||||
|
border: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TransactionItem = ({
|
||||||
|
tx,
|
||||||
|
network,
|
||||||
|
}: Props) => {
|
||||||
|
const url = `${network.explorer.tx}${tx.hash}`;
|
||||||
|
const date = typeof tx.timestamp === 'string' && tx.confirmations > 0 ? tx.timestamp : undefined; // TODO: format date
|
||||||
|
const addresses = (tx.type === 'send' ? tx.outputs : tx.inputs).reduce((arr, item) => arr.concat(item.addresses), []);
|
||||||
|
|
||||||
|
const currency = tx.currency || tx.network;
|
||||||
|
const isToken = currency !== tx.network;
|
||||||
|
const amount = isToken ? `${tx.amount} ${currency}` : `${tx.total} ${network.symbol}`;
|
||||||
|
const fee = isToken && tx.type === 'send' ? `${tx.fee} ${network.symbol}` : undefined;
|
||||||
|
const operation = tx.type === 'send' ? '-' : '+';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{ date && (<Date href={url} isGray>{ date }</Date>)}
|
||||||
|
<Addresses>
|
||||||
|
{ addresses.map(addr => (<Address key={addr}>{addr}</Address>)) }
|
||||||
|
{ tx.confirmations <= 0 && (
|
||||||
|
<Date href={url} isGray>Transaction hash: {tx.hash}</Date>
|
||||||
|
)}
|
||||||
|
</Addresses>
|
||||||
|
<Value className={tx.type}>
|
||||||
|
<Amount>{operation}{amount}</Amount>
|
||||||
|
{ fee && (<Fee>{operation}{fee}</Fee>) }
|
||||||
|
</Value>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionItem.propTypes = {
|
||||||
|
tx: PropTypes.object.isRequired,
|
||||||
|
network: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TransactionItem;
|
BIN
src/components/images/CoinLogo/images/txrp.png
Normal file
BIN
src/components/images/CoinLogo/images/txrp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
@ -44,6 +44,7 @@ import type {
|
|||||||
TransportMessageType,
|
TransportMessageType,
|
||||||
UiMessageType,
|
UiMessageType,
|
||||||
BlockchainEvent,
|
BlockchainEvent,
|
||||||
|
BlockchainLinkTransaction,
|
||||||
} from 'trezor-connect';
|
} from 'trezor-connect';
|
||||||
|
|
||||||
import type { RouterAction, LocationState } from 'react-router-redux';
|
import type { RouterAction, LocationState } from 'react-router-redux';
|
||||||
@ -84,11 +85,17 @@ export type UnknownDevice = $Exact<{
|
|||||||
instanceLabel: string;
|
instanceLabel: string;
|
||||||
instanceName: ?string;
|
instanceName: ?string;
|
||||||
ts: number;
|
ts: number;
|
||||||
}>
|
}>;
|
||||||
|
|
||||||
export type { Device } from 'trezor-connect';
|
export type { Device } from 'trezor-connect';
|
||||||
export type TrezorDevice = AcquiredDevice | UnknownDevice;
|
export type TrezorDevice = AcquiredDevice | UnknownDevice;
|
||||||
|
|
||||||
|
export type Transaction = BlockchainLinkTransaction & {
|
||||||
|
deviceState: string,
|
||||||
|
network: string,
|
||||||
|
rejected?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
export type RouterLocationState = LocationState;
|
export type RouterLocationState = LocationState;
|
||||||
|
|
||||||
// Cast event from TrezorConnect event listener to react Action
|
// Cast event from TrezorConnect event listener to react Action
|
||||||
@ -152,7 +159,6 @@ export type { Account } from 'reducers/AccountsReducer';
|
|||||||
export type { Discovery } from 'reducers/DiscoveryReducer';
|
export type { Discovery } from 'reducers/DiscoveryReducer';
|
||||||
export type { Token } from 'reducers/TokensReducer';
|
export type { Token } from 'reducers/TokensReducer';
|
||||||
export type { Web3Instance } from 'reducers/Web3Reducer';
|
export type { Web3Instance } from 'reducers/Web3Reducer';
|
||||||
export type { PendingTx } from 'reducers/PendingTxReducer';
|
|
||||||
|
|
||||||
export type Accounts = $ElementType<State, 'accounts'>;
|
export type Accounts = $ElementType<State, 'accounts'>;
|
||||||
export type LocalStorage = $ElementType<State, 'localStorage'>;
|
export type LocalStorage = $ElementType<State, 'localStorage'>;
|
||||||
|
@ -9,8 +9,9 @@ import type { BlockchainConnect, BlockchainError, BlockchainBlock } from 'trezor
|
|||||||
export type BlockchainNetwork = {
|
export type BlockchainNetwork = {
|
||||||
+shortcut: string,
|
+shortcut: string,
|
||||||
connected: boolean,
|
connected: boolean,
|
||||||
fee: string,
|
|
||||||
block: number,
|
block: number,
|
||||||
|
reserved: string, // xrp specific
|
||||||
|
fee: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type State = Array<BlockchainNetwork>;
|
export type State = Array<BlockchainNetwork>;
|
||||||
@ -34,8 +35,9 @@ const onConnect = (state: State, action: BlockchainConnect): State => {
|
|||||||
return state.concat([{
|
return state.concat([{
|
||||||
shortcut,
|
shortcut,
|
||||||
connected: true,
|
connected: true,
|
||||||
fee: info.fee,
|
|
||||||
block: info.block,
|
block: info.block,
|
||||||
|
fee: info.fee,
|
||||||
|
reserved: info.reserved || '0',
|
||||||
}]);
|
}]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,7 +52,13 @@ const onError = (state: State, action: BlockchainError): State => {
|
|||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state.concat([{
|
||||||
|
shortcut,
|
||||||
|
connected: false,
|
||||||
|
block: 0,
|
||||||
|
fee: '0',
|
||||||
|
reserved: '0',
|
||||||
|
}]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBlock = (state: State, action: BlockchainBlock): State => {
|
const onBlock = (state: State, action: BlockchainBlock): State => {
|
||||||
|
@ -195,6 +195,9 @@ export default function discovery(state: State = initialState, action: Action):
|
|||||||
return notSupported(state, action);
|
return notSupported(state, action);
|
||||||
case DISCOVERY.FROM_STORAGE:
|
case DISCOVERY.FROM_STORAGE:
|
||||||
return action.payload.map((d) => {
|
return action.payload.map((d) => {
|
||||||
|
if (d.publicKey.length < 1) return d;
|
||||||
|
// recreate ethereum discovery HDKey
|
||||||
|
// deprecated: will be removed after switching to blockbook
|
||||||
const hdKey: HDKey = new HDKey();
|
const hdKey: HDKey = new HDKey();
|
||||||
hdKey.publicKey = Buffer.from(d.publicKey, 'hex');
|
hdKey.publicKey = Buffer.from(d.publicKey, 'hex');
|
||||||
hdKey.chainCode = Buffer.from(d.chainCode, 'hex');
|
hdKey.chainCode = Buffer.from(d.chainCode, 'hex');
|
||||||
|
@ -21,6 +21,7 @@ export type Network = {
|
|||||||
address: string;
|
address: string;
|
||||||
};
|
};
|
||||||
tokens: string;
|
tokens: string;
|
||||||
|
decimals: number,
|
||||||
backends: Array<{
|
backends: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
urls: Array<string>;
|
urls: Array<string>;
|
||||||
|
@ -2,27 +2,13 @@
|
|||||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||||
import * as PENDING from 'actions/constants/pendingTx';
|
import * as PENDING from 'actions/constants/pendingTx';
|
||||||
|
|
||||||
import type { Action } from 'flowtype';
|
import type { Action, Transaction } from 'flowtype';
|
||||||
|
|
||||||
export type PendingTx = {
|
export type State = Array<Transaction>;
|
||||||
+type: 'send' | 'recv',
|
|
||||||
+deviceState: string,
|
|
||||||
+sequence: number,
|
|
||||||
+hash: string,
|
|
||||||
+network: string,
|
|
||||||
+address: string,
|
|
||||||
+currency: string,
|
|
||||||
+amount: string,
|
|
||||||
+total: string,
|
|
||||||
+fee: string,
|
|
||||||
rejected?: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type State = Array<PendingTx>;
|
|
||||||
|
|
||||||
const initialState: State = [];
|
const initialState: State = [];
|
||||||
|
|
||||||
const add = (state: State, payload: PendingTx): State => {
|
const add = (state: State, payload: Transaction): State => {
|
||||||
const newState = [...state];
|
const newState = [...state];
|
||||||
newState.push(payload);
|
newState.push(payload);
|
||||||
return newState;
|
return newState;
|
||||||
|
@ -6,7 +6,7 @@ import type {
|
|||||||
Account,
|
Account,
|
||||||
Network,
|
Network,
|
||||||
Token,
|
Token,
|
||||||
PendingTx,
|
Transaction,
|
||||||
Discovery,
|
Discovery,
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export type State = {
|
|||||||
account: ?Account,
|
account: ?Account,
|
||||||
network: ?Network,
|
network: ?Network,
|
||||||
tokens: Array<Token>,
|
tokens: Array<Token>,
|
||||||
pending: Array<PendingTx>,
|
pending: Array<Transaction>,
|
||||||
discovery: ?Discovery,
|
discovery: ?Discovery,
|
||||||
loader: ?Loader,
|
loader: ?Loader,
|
||||||
notification: ?Notification,
|
notification: ?Notification,
|
||||||
|
@ -9,7 +9,7 @@ import type {
|
|||||||
Network,
|
Network,
|
||||||
Discovery,
|
Discovery,
|
||||||
Token,
|
Token,
|
||||||
PendingTx,
|
Transaction,
|
||||||
Web3Instance,
|
Web3Instance,
|
||||||
} from 'flowtype';
|
} from 'flowtype';
|
||||||
|
|
||||||
@ -83,18 +83,18 @@ 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 = (pending: Array<PendingTx>, account: ?Account): Array<PendingTx> => {
|
export const getAccountPendingTx = (pending: Array<Transaction>, account: ?Account): Array<Transaction> => {
|
||||||
const a = account;
|
const a = account;
|
||||||
if (!a) return [];
|
if (!a) return [];
|
||||||
return 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 getPendingSequence = (pending: Array<PendingTx>): number => pending.reduce((value: number, tx: PendingTx) => {
|
export const getPendingSequence = (pending: Array<Transaction>): number => pending.reduce((value: number, tx: Transaction) => {
|
||||||
if (tx.rejected) return value;
|
if (tx.rejected) return value;
|
||||||
return Math.max(value, tx.sequence + 1);
|
return Math.max(value, tx.sequence + 1);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
export const getPendingAmount = (pending: Array<PendingTx>, currency: string, token: boolean = false): BigNumber => pending.reduce((value: BigNumber, tx: PendingTx) => {
|
export const getPendingAmount = (pending: Array<Transaction>, currency: string, token: boolean = false): BigNumber => pending.reduce((value: BigNumber, tx: Transaction) => {
|
||||||
if (tx.currency === currency && !tx.rejected) {
|
if (tx.currency === currency && !tx.rejected) {
|
||||||
return new BigNumber(value).plus(token ? tx.amount : tx.total);
|
return new BigNumber(value).plus(token ? tx.amount : tx.total);
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
import React, { PureComponent } from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
import ColorHash from 'color-hash';
|
|
||||||
import { H2 } from 'components/Heading';
|
import { H2 } from 'components/Heading';
|
||||||
import Link from 'components/Link';
|
import Transaction from 'components/Transaction';
|
||||||
import ScaleText from 'react-scale-text';
|
|
||||||
|
|
||||||
import type { Network } from 'reducers/LocalStorageReducer';
|
import type { Network } from 'reducers/LocalStorageReducer';
|
||||||
import type { Token } from 'reducers/TokensReducer';
|
|
||||||
import type { BaseProps } from '../../index';
|
import type { BaseProps } from '../../index';
|
||||||
|
// import testData from './test.data';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pending: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'pending'>,
|
pending: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'pending'>,
|
||||||
tokens: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'tokens'>,
|
|
||||||
network: Network
|
network: Network
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,153 +20,18 @@ const Wrapper = styled.div`
|
|||||||
border-top: 1px solid ${colors.DIVIDER};
|
border-top: 1px solid ${colors.DIVIDER};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const PendingTransactions = (props: Props) => {
|
||||||
text-decoration: none;
|
// const pending = props.pending.filter(tx => !tx.rejected).concat(testData);
|
||||||
`;
|
const pending = props.pending.filter(tx => !tx.rejected);
|
||||||
|
|
||||||
const TransactionWrapper = styled.div`
|
|
||||||
border-bottom: 1px solid ${colors.DIVIDER};
|
|
||||||
padding: 14px 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TransactionIcon = styled.div`
|
|
||||||
padding: 6px;
|
|
||||||
margin-right: 10px;
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius: 50%;
|
|
||||||
line-height: 25px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
user-select: none;
|
|
||||||
text-align: center;
|
|
||||||
color: ${props => props.textColor};
|
|
||||||
background: ${props => props.background};
|
|
||||||
border-color: ${props => props.borderColor};
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: ${props => props.color};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const P = styled.p``;
|
|
||||||
|
|
||||||
const TransactionName = styled.div`
|
|
||||||
flex: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TransactionAmount = styled.div`
|
|
||||||
color: colors.TEXT_SECONDARY;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class PendingTransactions extends PureComponent<Props> {
|
|
||||||
getPendingTransactions() {
|
|
||||||
return this.props.pending.filter(tx => !tx.rejected);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionIconColors(tx: any) {
|
|
||||||
let iconColors = {
|
|
||||||
textColor: '#fff',
|
|
||||||
background: '#000',
|
|
||||||
borderColor: '#000',
|
|
||||||
};
|
|
||||||
const bgColorFactory = new ColorHash({ lightness: 0.7 });
|
|
||||||
const textColorFactory = new ColorHash();
|
|
||||||
|
|
||||||
const isSmartContractTx = tx.currency !== this.props.network.symbol;
|
|
||||||
|
|
||||||
if (isSmartContractTx) {
|
|
||||||
const token: ?Token = this.findTransactionToken(tx.currency);
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
iconColors = {
|
|
||||||
textColor: '#ffffff',
|
|
||||||
background: '#000000',
|
|
||||||
borderColor: '#000000',
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const bgColor: string = bgColorFactory.hex(token.name);
|
|
||||||
iconColors = {
|
|
||||||
textColor: textColorFactory.hex(token.name),
|
|
||||||
background: bgColor,
|
|
||||||
borderColor: bgColor,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
iconColors = {
|
|
||||||
textColor: textColorFactory.hex(tx.network),
|
|
||||||
background: bgColorFactory.hex(tx.network),
|
|
||||||
borderColor: bgColorFactory.hex(tx.network),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return iconColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionSymbol(tx: any) {
|
|
||||||
let { symbol } = this.props.network;
|
|
||||||
const isSmartContractTx = tx.currency !== this.props.network.symbol;
|
|
||||||
if (isSmartContractTx) {
|
|
||||||
const token: ?Token = this.findTransactionToken(tx.currency);
|
|
||||||
symbol = token ? token.symbol.toUpperCase() : 'Unknown';
|
|
||||||
}
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionName(tx: any) {
|
|
||||||
let { name } = this.props.network;
|
|
||||||
const isSmartContractTx = tx.currency !== this.props.network.symbol;
|
|
||||||
if (isSmartContractTx) {
|
|
||||||
const token: ?Token = this.findTransactionToken(tx.currency);
|
|
||||||
name = token ? token.symbol.toUpperCase() : 'Unknown';
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
findTransactionToken(transactionCurrency: string) {
|
|
||||||
return this.props.tokens.find(t => t.symbol === transactionCurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<H2>Pending transactions</H2>
|
<H2>Pending transactions</H2>
|
||||||
{this.getPendingTransactions().map(tx => (
|
{pending.map(tx => (
|
||||||
<TransactionWrapper
|
<Transaction key={tx.hash} network={props.network} tx={tx} />
|
||||||
key={tx.hash}
|
|
||||||
>
|
|
||||||
<TransactionIcon
|
|
||||||
textColor={() => this.getTransactionIconColors(tx).textColor}
|
|
||||||
background={() => this.getTransactionIconColors(tx).background}
|
|
||||||
borderColor={() => this.getTransactionIconColors(tx).borderColor}
|
|
||||||
>
|
|
||||||
<ScaleText widthOnly>
|
|
||||||
<P>{this.getTransactionSymbol(tx)}</P>
|
|
||||||
</ScaleText>
|
|
||||||
</TransactionIcon>
|
|
||||||
|
|
||||||
<TransactionName>
|
|
||||||
<StyledLink
|
|
||||||
href={`${this.props.network.explorer.tx}${tx.hash}`}
|
|
||||||
isGray
|
|
||||||
>
|
|
||||||
{this.getTransactionName(tx)}
|
|
||||||
</StyledLink>
|
|
||||||
</TransactionName>
|
|
||||||
|
|
||||||
<TransactionAmount>
|
|
||||||
{tx.currency !== this.props.network.symbol ? tx.amount : tx.total} {this.getTransactionSymbol(tx)}
|
|
||||||
</TransactionAmount>
|
|
||||||
</TransactionWrapper>
|
|
||||||
))}
|
))}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default PendingTransactions;
|
export default PendingTransactions;
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
type: 'recv',
|
||||||
|
timestamp: '16:20',
|
||||||
|
address: 'a',
|
||||||
|
deviceState: 'a',
|
||||||
|
status: 'pending',
|
||||||
|
confirmations: 0,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
addresses: ['in1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: ['in2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{
|
||||||
|
addresses: ['out1', 'out2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sequence: 1,
|
||||||
|
hash: '1234',
|
||||||
|
network: 'eth',
|
||||||
|
currency: 'eth',
|
||||||
|
amount: '0.001',
|
||||||
|
total: '0.001001',
|
||||||
|
fee: '0.000001',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
type: 'send',
|
||||||
|
address: 'a',
|
||||||
|
deviceState: 'a',
|
||||||
|
confirmations: 0,
|
||||||
|
status: 'pending',
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
addresses: ['in1', 'in2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{
|
||||||
|
addresses: ['out1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sequence: 1,
|
||||||
|
hash: '12345',
|
||||||
|
network: 'eth',
|
||||||
|
currency: 'T01',
|
||||||
|
amount: '0.001',
|
||||||
|
total: '0.001001',
|
||||||
|
fee: '0.000001',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
address: '0x73d0385F4d8E00C5e6504C6030F47BF6212736A8',
|
||||||
|
amount: '1',
|
||||||
|
confirmations: 0,
|
||||||
|
currency: 'T01',
|
||||||
|
deviceState: '4058d01c7c964787b7d06f0f32ce229088e123a042bf95aad658f1b1b99c73fc',
|
||||||
|
fee: '0.0002',
|
||||||
|
hash: '0xbf6ac83bdf29abacbca91cd4100ddd5cd8de16e72911ea7d1daec17ccbfc6099',
|
||||||
|
inputs: [{
|
||||||
|
addresses: ['0x73d0385F4d8E00C5e6504C6030F47BF6212736A8'],
|
||||||
|
}],
|
||||||
|
network: 'trop',
|
||||||
|
outputs: [{
|
||||||
|
addresses: ['0xFA01a39f8Abaeb660c3137f14A310d0b414b2A15'],
|
||||||
|
}],
|
||||||
|
sequence: 249,
|
||||||
|
status: 'pending',
|
||||||
|
timestamp: '',
|
||||||
|
total: '0.0002',
|
||||||
|
type: 'send',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
address: '0x73d0385F4d8E00C5e6504C6030F47BF6212736A8',
|
||||||
|
amount: '1',
|
||||||
|
confirmations: 0,
|
||||||
|
currency: 'trop',
|
||||||
|
deviceState: '4058d01c7c964787b7d06f0f32ce229088e123a042bf95aad658f1b1b99c73fc',
|
||||||
|
fee: '0.0002',
|
||||||
|
hash: '0xbf6ac83bdf29abacbca91cd4100ddd5cd8de16e72911ea7d1daec17ccbfc6099',
|
||||||
|
inputs: [{
|
||||||
|
addresses: ['0x73d0385F4d8E00C5e6504C6030F47BF6212736A8'],
|
||||||
|
}],
|
||||||
|
network: 'trop',
|
||||||
|
outputs: [{
|
||||||
|
addresses: ['0xFA01a39f8Abaeb660c3137f14A310d0b414b2A15'],
|
||||||
|
}],
|
||||||
|
sequence: 249,
|
||||||
|
status: 'pending',
|
||||||
|
timestamp: '',
|
||||||
|
total: '0.0002',
|
||||||
|
type: 'send',
|
||||||
|
},
|
||||||
|
];
|
@ -132,6 +132,7 @@ const ToggleAdvancedSettingsButton = styled(Button)`
|
|||||||
|
|
||||||
const SendButton = styled(Button)`
|
const SendButton = styled(Button)`
|
||||||
min-width: ${props => (props.isAdvancedSettingsHidden ? '50%' : '100%')};
|
min-width: ${props => (props.isAdvancedSettingsHidden ? '50%' : '100%')};
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
@media screen and (max-width: ${SmallScreenWidth}) {
|
@media screen and (max-width: ${SmallScreenWidth}) {
|
||||||
margin-top: ${props => (props.isAdvancedSettingsHidden ? '10px' : 0)};
|
margin-top: ${props => (props.isAdvancedSettingsHidden ? '10px' : 0)};
|
||||||
|
@ -82,6 +82,7 @@ const ToggleAdvancedSettingsWrapper = styled.div`
|
|||||||
|
|
||||||
const SendButton = styled(Button)`
|
const SendButton = styled(Button)`
|
||||||
min-width: ${props => (props.isAdvancedSettingsHidden ? '50%' : '100%')};
|
min-width: ${props => (props.isAdvancedSettingsHidden ? '50%' : '100%')};
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
@media screen and (max-width: ${SmallScreenWidth}) {
|
@media screen and (max-width: ${SmallScreenWidth}) {
|
||||||
margin-top: ${props => (props.isAdvancedSettingsHidden ? '10px' : 0)};
|
margin-top: ${props => (props.isAdvancedSettingsHidden ? '10px' : 0)};
|
||||||
|
@ -50,7 +50,7 @@ module.exports = {
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js?$/,
|
test: /\.js?$/,
|
||||||
exclude: [/node_modules/, /trezor-blockchain-link\/build\/workers/],
|
exclude: [/node_modules/, /blockchain-link\/build\/workers/],
|
||||||
use: ['babel-loader'],
|
use: ['babel-loader'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user