pull/200/head
Vladimir Volek 6 years ago
commit 851c7f23cb

@ -43,7 +43,7 @@
"settings": {
"import/resolver": {
"babel-module": {}
},
},
"import/ignore": [
"\\.(scss|less|css)$"
]

@ -41,6 +41,8 @@ build beta:
script:
- yarn install
- yarn run build:beta
only:
- beta
artifacts:
expire_in: 1 week
paths:
@ -52,6 +54,8 @@ build stable:
script:
- yarn install
- yarn run build:stable
only:
- stable
artifacts:
expire_in: 1 week
paths:
@ -64,6 +68,9 @@ deploy review:
GIT_STRATEGY: none
dependencies:
- build development
environment:
name: $CI_BUILD_REF_NAME
url: $BASE_REVIEW_URL/$CI_BUILD_REF_NAME
script:
- echo "Deploy a review app"
- '[ -z "${DEPLOY_BASE_DIR}" ] && echo "Deploy base dir cannot be empty" && exit 255'

@ -0,0 +1,22 @@
# 1.0.2-beta
- Fiat rates from coingecko (https://github.com/trezor/trezor-wallet/pull/242)
- firmware update link to beta-wallet (https://github.com/trezor/trezor-wallet/commit/b9b7d2d076f2d4c59ae2e055dc140cda6aaa5512)
- set default gas limit button
- update list of ETH and ETC tokens
- added 1 click to select value in input (https://github.com/trezor/trezor-wallet/issues/251)
- added account loader (https://github.com/trezor/trezor-wallet/pull/225)
# 1.0.1-beta
__added__
- DigiByte in coin menu
- blocking device with seedless setup
__fixed__
- token input in "Account/Summary" (https://github.com/trezor/trezor-wallet/issues/235)
- "Go to your standard wallet" button in passphrase modal (https://github.com/trezor/trezor-wallet/issues/222)
- Double click on "show passphrase" (https://github.com/trezor/trezor-wallet/issues/221)
- images preloader for offline status (https://github.com/trezor/trezor-wallet/issues/218)
# 1.0.0-beta
- first release

@ -70,7 +70,7 @@
"styled-components": "^3.4.9",
"styled-media-query": "^2.0.2",
"styled-normalize": "^8.0.0",
"trezor-connect": "6.0.0",
"trezor-connect": "6.0.2",
"web3": "1.0.0-beta.35",
"webpack": "^4.16.3",
"webpack-build-notifier": "^0.1.29",

@ -59,11 +59,11 @@
"fiatValueTickers": [
{
"network": "eth",
"url": "https://api.coinmarketcap.com/v1/ticker/ethereum/"
"url": "https://api.coingecko.com/api/v3/coins/ethereum"
},
{
"network": "etc",
"url": "https://api.coinmarketcap.com/v1/ticker/ethereum-classic/"
"url": "https://api.coingecko.com/api/v3/coins/ethereum-classic"
}
],

@ -1,14 +1,14 @@
[
{
"address": "0x6F6DEb5db0C4994A8283A01D6CFeEB27Fc3bBe9C",
"name": "SmartBillions",
"symbol": "Smart",
"decimals": 0
"address": "0x085fb4f24031EAedbC2B611AA528f22343eB52Db",
"decimals": 8,
"name": "BEC",
"symbol": "BEC"
},
{
"address": "0x5ace17f87c7391e5792a7683069a8025b83bbd85",
"name": "SmartBillions Token",
"symbol": "PLAY",
"decimals": 0
"address": "0x6ADa6F48C815689502C43eC1a59F1b5DD3C04E1F",
"decimals": 18,
"name": "UniversalCoin",
"symbol": "UNV"
}
]

File diff suppressed because it is too large Load Diff

@ -38,81 +38,106 @@ export const dispose = (): Action => ({
type: ACCOUNT.DISPOSE,
});
const getAccountStatus = (state: State, selectedAccount: SelectedAccountState): ?AccountStatus => {
const getAccountLoader = (state: State, selectedAccount: SelectedAccountState): ?AccountStatus => {
const device = state.wallet.selectedDevice;
if (!device || !device.state) {
return {
type: 'loader-progress',
title: 'Loading device...',
shouldRender: false,
};
}
const {
account,
discovery,
network,
} = selectedAccount;
// corner case: accountState didn't finish loading state after LOCATION_CHANGE action
if (!network) {
if (!device || !device.state) {
return {
type: 'loader-progress',
title: 'Loading account state...',
type: 'progress',
title: 'Loading device...',
shouldRender: false,
};
}
const blockchain = state.blockchain.find(b => b.shortcut === network.shortcut);
if (blockchain && !blockchain.connected) {
// corner case: accountState didn't finish loading state after LOCATION_CHANGE action
if (!network) {
return {
type: 'backend',
title: `${network.name} backend is not connected`,
type: 'progress',
title: 'Loading account state...',
shouldRender: false,
};
}
if (account) return null;
// account not found (yet). checking why...
if (!account) {
if (!discovery || (discovery.waitingForDevice || discovery.interrupted)) {
if (device.connected) {
// case 1: device is connected but discovery not started yet (probably waiting for auth)
if (device.available) {
return {
type: 'loader-progress',
title: 'Authenticating device...',
shouldRender: false,
};
}
// case 2: device is unavailable (created with different passphrase settings) account cannot be accessed
if (!discovery || (discovery.waitingForDevice || discovery.interrupted)) {
if (device.connected) {
// case 1: device is connected but discovery not started yet (probably waiting for auth)
if (device.available) {
return {
type: 'loader-info',
title: `Device ${device.instanceLabel} is unavailable`,
message: 'Change passphrase settings to use this device',
type: 'progress',
title: 'Authenticating device...',
shouldRender: false,
};
}
// case 3: device is disconnected
// case 2: device is unavailable (created with different passphrase settings) account cannot be accessed
// this is related to device instance in url, it's not used for now (device clones are disabled)
return {
type: 'loader-info',
title: `Device ${device.instanceLabel} is disconnected`,
message: 'Connect device to load accounts',
type: 'info',
title: `Device ${device.instanceLabel} is unavailable`,
message: 'Change passphrase settings to use this device',
shouldRender: false,
};
}
if (discovery.completed) {
// case 4: account not found and discovery is completed
return {
type: 'loader-info',
title: 'Account does not exist',
shouldRender: false,
};
}
// case 3: device is disconnected
return {
type: 'info',
title: `Device ${device.instanceLabel} is disconnected`,
message: 'Connect device to load accounts',
shouldRender: false,
};
}
// Additional status: account does exists and it's visible but shouldn't be active
if (discovery.completed) {
// case 4: account not found and discovery is completed
return {
type: 'info',
title: 'Account does not exist',
shouldRender: false,
};
}
// case default: account information isn't loaded yet
return {
type: 'progress',
title: 'Loading account',
shouldRender: false,
};
};
const getAccountNotification = (state: State, selectedAccount: SelectedAccountState): ?AccountStatus => {
const device = state.wallet.selectedDevice;
const { account, network, discovery } = selectedAccount;
if (!device || !network) return null;
// case 1: backend status
const blockchain = state.blockchain.find(b => b.shortcut === network.shortcut);
if (blockchain && !blockchain.connected) {
return {
type: 'backend',
title: `${network.name} backend is not connected`,
shouldRender: false,
};
}
// case 2: account does exists and it's visible but shouldn't be active
if (account && discovery && !discovery.completed && !discovery.waitingForDevice) {
return {
type: 'info',
title: 'Loading other accounts...',
shouldRender: true,
};
}
// case 3: account does exists and device is disconnected
if (!device.connected) {
return {
type: 'info',
@ -121,6 +146,8 @@ const getAccountStatus = (state: State, selectedAccount: SelectedAccountState):
};
}
// case 4: account does exists and device is unavailable (created with different passphrase settings) account cannot be accessed
// this is related to device instance in url, it's not used for now (device clones are disabled)
if (!device.available) {
return {
type: 'info',
@ -130,6 +157,7 @@ const getAccountStatus = (state: State, selectedAccount: SelectedAccountState):
};
}
// case default
return null;
};
@ -153,13 +181,18 @@ const actions = [
export const observe = (prevState: State, action: Action): PayloadAction<boolean> => (dispatch: Dispatch, getState: GetState): boolean => {
// ignore not listed actions
if (actions.indexOf(action.type) < 0) return false;
const state: State = getState();
const notification = {
type: null,
message: null,
title: null,
};
const loader = {
type: null,
message: null,
title: null,
};
const { location } = state.router;
// displayed route is not an account route
if (!location.state.account) return false;
@ -180,13 +213,18 @@ export const observe = (prevState: State, action: Action): PayloadAction<boolean
tokens,
pending,
notification,
loader,
shouldRender: false,
};
// get "selectedAccount" status from newState
const status = getAccountStatus(state, newState);
newState.notification = status || notification;
newState.shouldRender = status ? status.shouldRender : true;
const statusNotification = getAccountNotification(state, newState);
const statusLoader = getAccountLoader(state, newState);
const shouldRender = (statusNotification && statusLoader) ? (statusNotification.shouldRender || statusLoader.shouldRender) : true;
newState.notification = statusNotification || notification;
newState.shouldRender = shouldRender;
newState.loader = statusLoader || loader;
// check if newState is different than previous state
const stateChanged = reducerUtils.observeChanges(prevState.selectedAccount, newState, {
account: ['balance', 'nonce'],

@ -90,8 +90,20 @@ export const observe = (prevState: ReducersState, action: Action): ThunkAction =
let shouldUpdate: boolean = false;
// check if "selectedAccount" reducer changed
shouldUpdate = reducerUtils.observeChanges(prevState.selectedAccount, currentState.selectedAccount, {
account: ['balance', 'nonce'],
account: ['balance', 'nonce', 'tokens'],
});
if (shouldUpdate && currentState.sendForm.currency !== currentState.sendForm.networkSymbol) {
// make sure that this token is added into account
const { account, tokens } = getState().selectedAccount;
if (!account) return;
const token = findToken(tokens, account.address, currentState.sendForm.currency, account.deviceState);
if (!token) {
// token not found, re-init form
dispatch(init());
return;
}
}
// check if "sendForm" reducer changed
if (!shouldUpdate) {
@ -384,6 +396,26 @@ export const onDataChange = (data: string): ThunkAction => (dispatch: Dispatch,
dispatch(estimateGasPrice());
};
export const setDefaultGasLimit = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
const state: State = getState().sendForm;
const { network } = getState().selectedAccount;
if (!network) return;
const isToken = state.currency !== state.networkSymbol;
const gasLimit = isToken ? network.defaultGasLimitTokens.toString() : network.defaultGasLimit.toString();
dispatch({
type: SEND.CHANGE,
state: {
...state,
calculatingGasLimit: false,
untouched: false,
touched: { ...state.touched, gasLimit: false },
gasLimit,
},
});
};
/*
* Internal method
* Called from "onDataChange" action
@ -548,6 +580,7 @@ export default {
updateFeeLevels,
onGasPriceChange,
onGasLimitChange,
setDefaultGasLimit,
onNonceChange,
onDataChange,
onSend,

@ -1,5 +1,6 @@
/* @flow */
import * as storageUtils from 'utils/storage';
import { findToken } from 'reducers/TokensReducer';
import type { State as SendFormState } from 'reducers/SendFormReducer';
import type {
@ -38,6 +39,16 @@ export const loadDraftTransaction = (): PayloadAction<?SendFormState> => (dispat
storageUtils.remove(TYPE, key);
return null;
}
// check if selected currency is token and make sure that this token is added into account
if (state.currency !== state.networkSymbol) {
const { account, tokens } = getState().selectedAccount;
if (!account) return null;
const token = findToken(tokens, account.address, state.currency, account.deviceState);
if (!token) {
storageUtils.remove(TYPE, key);
return null;
}
}
return state;
};

@ -15,6 +15,7 @@ declare var COMMITHASH: string;
type Props = {
opened: boolean,
isLanding: boolean,
toggle: () => any,
}
@ -25,29 +26,48 @@ const Wrapper = styled.div`
color: ${colors.TEXT_SECONDARY};
padding: 22px 48px;
display: flex;
justify-content: space-between;
border-top: 1px solid ${colors.BACKGROUND};
`;
const StyledLink = styled(Link)`
margin: 0 6px;
margin-right: 20px;
white-space: nowrap;
`;
const Copy = styled.div`
white-space: nowrap;
margin-right: 20px;
`;
const Footer = ({ opened, toggle }: Props) => (
const Left = styled.div`
display: flex;
`;
const Right = styled.div`
white-space: nowrap;
`;
const Footer = ({ opened, toggle, isLanding }: Props) => (
<Wrapper>
<Copy title={COMMITHASH}>&copy; {getYear(new Date())}</Copy>
<StyledLink href="http://satoshilabs.com" isGreen>SatoshiLabs</StyledLink>
<StyledLink href="/assets/tos.pdf" isGreen>Terms</StyledLink>
<StyledLink onClick={toggle} isGreen>{ opened ? 'Hide Log' : 'Show Log' }</StyledLink>
<Left>
<Copy title={COMMITHASH}>&copy; {getYear(new Date())}</Copy>
<StyledLink href="http://satoshilabs.com" isGreen>SatoshiLabs</StyledLink>
<StyledLink href="/assets/tos.pdf" isGreen>Terms</StyledLink>
<StyledLink onClick={toggle} isGreen>{ opened ? 'Hide Log' : 'Show Log' }</StyledLink>
</Left>
{!isLanding && (
<Right>
Exchange rates by<StyledLink href="https://www.coingecko.com" isGreen>Coingecko</StyledLink>
</Right>
)}
</Wrapper>
);
Footer.propTypes = {
opened: PropTypes.bool.isRequired,
isLanding: PropTypes.bool,
toggle: PropTypes.func.isRequired,
};

@ -55,13 +55,10 @@ class Link extends PureComponent {
} else {
LinkComponent = (
<A
className={this.props.className}
href={this.props.href}
target={this.props.target || '_blank'}
rel="noreferrer noopener"
onClick={this.props.onClick}
isGreen={this.props.isGreen}
isGray={this.props.isGray}
{...this.props}
>{this.props.children}
</A>
);
@ -87,4 +84,4 @@ Link.propTypes = {
isGray: PropTypes.bool,
};
export default Link;
export default Link;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@ -185,7 +185,9 @@ class Input extends PureComponent {
autocapitalize={this.props.autocapitalize}
spellCheck={this.props.spellCheck}
value={this.props.value}
readOnly={this.props.readOnly}
onChange={this.props.onChange}
onClick={this.props.autoSelect ? event => event.target.select() : null}
borderColor={this.getColor(this.props.state)}
disabled={this.props.isDisabled}
name={this.props.name}
@ -220,6 +222,8 @@ Input.propTypes = {
icon: PropTypes.node,
spellCheck: PropTypes.string,
value: PropTypes.string,
readOnly: PropTypes.bool,
autoSelect: PropTypes.bool,
onChange: PropTypes.func,
state: PropTypes.string,
bottomText: PropTypes.string,
@ -234,6 +238,7 @@ Input.propTypes = {
Input.defaultProps = {
type: 'text',
autoSelect: false,
};
export default Input;

@ -7,7 +7,7 @@ import type { Props } from '../../index';
// There could be only one account notification
export default (props: Props) => {
const { network, notification } = props.selectedAccount;
if (network && notification.type && notification.title && notification.type !== 'loader-progress' && notification.type !== 'loader-info') {
if (network && notification.type && notification.title) {
if (notification.type === 'backend') {
// special case: backend is down
// TODO: this is a different component with "auto resolve" button

@ -19,6 +19,11 @@ export default [
coinName: 'Dash',
url: '../?coin=dash',
},
{
id: 'dgb',
coinName: 'DigiByte',
url: '../?coin=dgb',
},
{
id: 'doge',
coinName: 'Dogecoin',

@ -32,7 +32,7 @@ import type { TokenAction } from 'actions/TokenActions';
import type { TrezorConnectAction } from 'actions/TrezorConnectActions';
import type { WalletAction } from 'actions/WalletActions';
import type { Web3Action } from 'actions/Web3Actions';
import type { FiatRateAction } from 'services/CoinmarketcapService'; // this service has no action file, all is written inside one file
import type { FiatRateAction } from 'services/CoingeckoService'; // this service has no action file, all is written inside one file
import type {
Device,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 KiB

@ -1,29 +1,26 @@
/* @flow */
import { RATE_UPDATE } from 'services/CoinmarketcapService';
import { RATE_UPDATE } from 'services/CoingeckoService';
import type { Action } from 'flowtype';
import type { FiatRateAction } from 'services/CoinmarketcapService';
import type { FiatRateAction } from 'services/CoingeckoService';
export type Fiat = {
+network: string;
value: string;
}
};
export const initialState: Array<Fiat> = [];
const update = (state: Array<Fiat>, action: FiatRateAction): Array<Fiat> => {
const newState: Array<Fiat> = [...state];
const exists: ?Fiat = newState.find(f => f.network === action.network);
if (exists) {
exists.value = action.rate.price_usd;
} else {
newState.push({
network: action.network,
value: action.rate.price_usd,
});
}
return newState;
const affected = state.find(f => f.network === action.network);
const otherRates = state.filter(d => d !== affected);
const { network, rate } = action;
return otherRates.concat([{
network,
value: rate.toFixed(2),
}]);
};
export default (state: Array<Fiat> = initialState, action: Action): Array<Fiat> => {

@ -22,6 +22,11 @@ export type State = {
title: ?string,
message: ?string,
},
loader: {
type: ?string,
title: ?string,
message: ?string,
},
shouldRender: boolean,
};
@ -37,6 +42,14 @@ export const initialState: State = {
title: null,
message: null,
},
<<<<<<< HEAD
=======
loader: {
type: null,
title: null,
message: null,
},
>>>>>>> master
shouldRender: false,
};

@ -19,7 +19,7 @@ export const RATE_UPDATE: 'rate__update' = 'rate__update';
export type FiatRateAction = {
type: typeof RATE_UPDATE;
network: string;
rate: any;
rate: number;
}
const loadRateAction = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
@ -28,13 +28,12 @@ const loadRateAction = (): AsyncAction => async (dispatch: Dispatch, getState: G
try {
config.fiatValueTickers.forEach(async (ticker) => {
// const rate: ?Array<any> = await JSONRequest(`${ticker.url}?convert=USD`, 'json');
const rate: ?Array<any> = await httpRequest(`${ticker.url}?convert=USD`, 'json');
if (rate) {
const response = await httpRequest(`${ticker.url}?tickers=false&market_data=true&community_data=false&developer_data=false&sparkline=false`, 'json');
if (response) {
dispatch({
type: RATE_UPDATE,
network: ticker.network,
rate: rate[0],
network: response.symbol,
rate: response.market_data.current_price.usd,
});
}
});
@ -48,7 +47,7 @@ const loadRateAction = (): AsyncAction => async (dispatch: Dispatch, getState: G
/**
* Middleware
*/
const CoinmarketcapService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
const CoingeckoService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
next(action);
if (action.type === READY) {
@ -58,4 +57,4 @@ const CoinmarketcapService: Middleware = (api: MiddlewareAPI) => (next: Middlewa
return action;
};
export default CoinmarketcapService;
export default CoingeckoService;

@ -2,7 +2,7 @@ import WalletService from './WalletService';
import LogService from './LogService';
import RouterService from './RouterService';
import LocalStorageService from './LocalStorageService';
import CoinmarketcapService from './CoinmarketcapService';
import CoingeckoService from './CoingeckoService';
import TrezorConnectService from './TrezorConnectService';
export default [
@ -11,5 +11,5 @@ export default [
RouterService,
LocalStorageService,
TrezorConnectService,
CoinmarketcapService,
CoingeckoService,
];

@ -0,0 +1,25 @@
import React, { Component } from 'react';
import styled from 'styled-components';
const Wrapper = styled.div`
display: none;
`;
const Img = styled.img``;
class ImagesPreloader extends Component {
importAll(r) {
return r.keys().map(r);
}
render() {
const images = this.importAll(require.context('../images', false, /\.(png|jpe?g)$/));
return (
<Wrapper>
{images.map(image => <Img key={image} src={image} />)}
</Wrapper>
);
}
}
export default ImagesPreloader;

@ -12,7 +12,7 @@ describe('device utils', () => {
];
types.forEach((type) => {
expect(nUtils.getColor(type)).toMatchSnapshot();
expect(nUtils.getPrimaryColor(type)).toMatchSnapshot();
});
});
it('get icon', () => {

@ -9,7 +9,7 @@ import { H2 } from 'components/Heading';
import { PULSATE } from 'config/animations';
import colors from 'config/colors';
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
import CaseImage from 'images/case.png';
import CaseImage from 'images/macbook.png';
import Link from 'components/Link';
type Props = {

@ -53,7 +53,7 @@ const LandingWrapper = (props: Props) => (
{ props.children }
</LandingContent>
)}
<Footer />
<Footer isLanding />
</React.Fragment>
)}
</Wrapper>

@ -45,10 +45,10 @@ const Content = ({
}) => (
<Wrapper>
{(!isLoading) && children}
{isLoading && (type === 'loader-progress' || type === 'loader-info') && (
{isLoading && (type === 'progress' || type === 'info') && (
<Loading>
<Row>
{type === 'loader-progress' && <Loader size={30} />}
{type === 'progress' && <Loader size={30} />}
<Text>{title || 'Initializing accounts'}</Text>
</Row>
{message && <Message>{message}</Message>}
@ -58,7 +58,7 @@ const Content = ({
);
Content.propTypes = {
children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]),
children: PropTypes.element,
isLoading: PropTypes.bool,
title: PropTypes.string,
message: PropTypes.string,

@ -93,9 +93,9 @@ const AccountReceive = (props: Props) => {
account,
discovery,
shouldRender,
notification,
loader,
} = props.selectedAccount;
const { type, title, message } = notification;
const { type, title, message } = loader;
if (!device || !account || !discovery || !shouldRender) return <Content type={type} title={title} message={message} isLoading />;
const {
@ -120,6 +120,8 @@ const AccountReceive = (props: Props) => {
<Row>
<Input
type="text"
readOnly
autoSelect
value={address}
isPartiallyHidden={isAddressHidden}
trezorAction={isAddressVerifying ? (

@ -9,6 +9,7 @@ import Textarea from 'components/Textarea';
import Tooltip from 'components/Tooltip';
import Icon from 'components/Icon';
import ICONS from 'config/icons';
import { FONT_SIZE } from 'config/variables';
import type { Props as BaseProps } from '../../Container';
@ -28,6 +29,7 @@ const InputRow = styled.div`
const InputLabelWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;
const GreenSpan = styled.span`
@ -110,6 +112,18 @@ const getDataTextareaState = (dataError: string, dataWarning: string): string =>
return state;
};
const Left = styled.div`
display: flex;
align-items: center;
`;
const Right = styled.div`
display: flex;
flex-direction: row;
font-size: ${FONT_SIZE.SMALLER};
cursor: pointer;
`;
// stateless component
const AdvancedForm = (props: Props) => {
const {
@ -124,16 +138,17 @@ const AdvancedForm = (props: Props) => {
errors,
warnings,
infos,
touched,
data,
gasLimit,
gasPrice,
} = props.sendForm;
const {
setDefaultGasLimit,
onGasLimitChange,
onGasPriceChange,
onDataChange,
} = props.sendFormActions;
let gasLimitTooltipCurrency: string;
let gasLimitTooltipValue: string;
if (networkSymbol !== currency) {
@ -144,6 +159,8 @@ const AdvancedForm = (props: Props) => {
gasLimitTooltipValue = network.defaultGasLimit.toString(10);
}
const showDefaultGasLimitButton = data.length === 0 && touched.gasLimit;
return (
<AdvancedSettingsWrapper>
<GasInputRow>
@ -155,29 +172,36 @@ const AdvancedForm = (props: Props) => {
spellCheck="false"
topLabel={(
<InputLabelWrapper>
<Left>
Gas limit
<Tooltip
content={(
<React.Fragment>
<Tooltip
content={(
<React.Fragment>
Gas limit refers to the maximum amount of gas user is willing to spendon a particular transaction.{' '}
<GreenSpan>Transaction fee = gas limit * gas price</GreenSpan>.{' '}Increasing the gas limit will not get the transaction confirmed sooner.
<GreenSpan>Transaction fee = gas limit * gas price</GreenSpan>.{' '}Increasing the gas limit will not get the transaction confirmed sooner.
Default value for sending {gasLimitTooltipCurrency} is <GreenSpan>{gasLimitTooltipValue}</GreenSpan>.
</React.Fragment>
)}
maxWidth={410}
readMoreLink="https://wiki.trezor.io/Ethereum_Wallet#Gas_limit"
placement="top"
>
<Icon
icon={ICONS.HELP}
color={colors.TEXT_SECONDARY}
size={24}
/>
</Tooltip>
</React.Fragment>
)}
maxWidth={410}
readMoreLink="https://wiki.trezor.io/Ethereum_Wallet#Gas_limit"
placement="top"
>
<Icon
icon={ICONS.HELP}
color={colors.TEXT_SECONDARY}
size={24}
/>
</Tooltip>
</Left>
{ showDefaultGasLimitButton && (
<Right onClick={() => setDefaultGasLimit()}>
Set default
</Right>)
}
</InputLabelWrapper>
)}
bottomText={errors.gasLimit || warnings.gasLimit || infos.gasLimit || (calculatingGasLimit ? 'Calculating...' : '')}
value={gasLimit}
bottomText={errors.gasLimit || warnings.gasLimit || infos.gasLimit}
value={calculatingGasLimit ? 'Calculating...' : gasLimit}
isDisabled={networkSymbol === currency && data.length > 0}
onChange={event => onGasLimitChange(event.target.value)}
/>

@ -185,7 +185,11 @@ const AccountSend = (props: Props) => {
discovery,
tokens,
shouldRender,
<<<<<<< HEAD
notification,
=======
loader,
>>>>>>> master
} = props.selectedAccount;
const {
address,
@ -214,7 +218,7 @@ const AccountSend = (props: Props) => {
updateFeeLevels,
onSend,
} = props.sendFormActions;
const { type, title, message } = notification;
const { type, title, message } = loader;
if (!device || !account || !discovery || !network || !shouldRender) return <Content type={type} title={title} message={message} isLoading />;
const isCurrentCurrencyToken = networkSymbol !== currency;

@ -106,8 +106,7 @@ class AccountBalance extends PureComponent<Props, State> {
render() {
const { network } = this.props;
const fiatRate: any = this.props.fiat.find(f => f.network === network.shortcut);
const fiatRate = this.props.fiat.find(f => f.network === network.shortcut);
let accountBalance = '';
let fiatRateValue = '';
let fiat = '';
@ -117,7 +116,6 @@ class AccountBalance extends PureComponent<Props, State> {
fiat = accountBalance.times(fiatRateValue).toFixed(2);
}
return (
<Wrapper>
<HideBalanceIconWrapper

@ -75,11 +75,12 @@ const AccountSummary = (props: Props) => {
network,
tokens,
pending,
notification,
loader,
shouldRender,
} = props.selectedAccount;
const { type, title, message } = notification;
const { type, title, message } = loader;
if (!device || !account || !network || !shouldRender) return <Content type={type} title={title} message={message} isLoading />;
const explorerLink: string = `${network.explorer.address}${account.address}`;
@ -125,9 +126,11 @@ const AccountSummary = (props: Props) => {
loadingMessage={() => 'Loading...'}
noOptionsMessage={() => 'Token not found'}
onChange={(token) => {
const isAdded = tokens.find(t => t.symbol === token.symbol);
if (!isAdded) {
props.addToken(token, account);
if (token.name) {
const isAdded = tokens.find(t => t.symbol === token.symbol);
if (!isAdded) {
props.addToken(token, account);
}
}
}}
loadOptions={input => props.loadTokens(input, account.network)}
@ -142,7 +145,6 @@ const AccountSummary = (props: Props) => {
getOptionValue={option => option.symbol}
/>
</AsyncSelectWrapper>
<AddedTokensWrapper>
{tokens.map(token => (
<AddedToken

@ -41,7 +41,7 @@ const DeviceSettings = () => (
/>
<H2>Device settings is under construction</H2>
<StyledP isSmaller>Please use Bitcoin wallet interface to change your device settings</StyledP>
<Link href="https://wallet.trezor.io/">
<Link href="https://beta-wallet.trezor.io/">
<Button>Take me to the Bitcoin wallet</Button>
</Link>
</Row>

@ -127,9 +127,9 @@ const FirmwareUpdate = (props: Props) => (
</svg>
</Image>
<H1>Its time to update your firmware</H1>
<StyledP>Please use the old wallet to do that.</StyledP>
<Link href="https://wallet.trezor.io">
<Button>Take me to the old wallet</Button>
<StyledP>Please use Bitcoin wallet interface to update your firmware.</StyledP>
<Link href="https://beta-wallet.trezor.io">
<Button>Take me to the Bitcoin wallet</Button>
</Link>
{deviceUtils.isDeviceAccessible(props.device) && (
<StyledNavLink to="/">Ill do that later.</StyledNavLink>

@ -32,7 +32,7 @@ const Initialize = () => (
<Row>
<H2>Your device is in not initialized</H2>
<StyledParagraph>Please use Bitcoin wallet interface to start initialization process</StyledParagraph>
<A href="https://wallet.trezor.io/">
<A href="https://beta-wallet.trezor.io/">
<Button>Take me to the Bitcoin wallet</Button>
</A>
</Row>

@ -6,6 +6,7 @@ import { ConnectedRouter } from 'react-router-redux';
// general
import ErrorBoundary from 'support/ErrorBoundary';
import ImagesPreloader from 'support/ImagesPreloader';
import { getPattern } from 'support/routes';
// landing views
@ -41,6 +42,7 @@ const App = () => (
<Route exact path={getPattern('landing-import')} component={ImportView} />
<Route>
<ErrorBoundary>
<ImagesPreloader />
<WalletContainer>
<Route exact path={getPattern('wallet-settings')} component={WalletSettings} />
<Route exact path={getPattern('wallet-dashboard')} component={WalletDashboard} />

@ -10274,9 +10274,9 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
trezor-connect@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/trezor-connect/-/trezor-connect-6.0.0.tgz#2a45336f29a4a3f2a8ad2d121363b0e7a1b767ef"
trezor-connect@6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/trezor-connect/-/trezor-connect-6.0.2.tgz#a4ca892cc4a167b34b97644e1404a56f6a110379"
dependencies:
babel-runtime "^6.26.0"
events "^1.1.1"

Loading…
Cancel
Save