mirror of https://github.com/trezor/trezor-wallet
commit
2cdd32c503
@ -0,0 +1,165 @@
|
||||
/* @flow */
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import type {
|
||||
GetState, Dispatch, ThunkAction, AsyncAction,
|
||||
} from 'flowtype';
|
||||
import { validateAddress } from 'utils/ethUtils';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as SIGN_VERIFY from './constants/signVerify';
|
||||
|
||||
export type SignVerifyAction = {
|
||||
type: typeof SIGN_VERIFY.SIGN_SUCCESS,
|
||||
signSignature: string
|
||||
} | {
|
||||
type: typeof SIGN_VERIFY.CLEAR_SIGN,
|
||||
} | {
|
||||
type: typeof SIGN_VERIFY.CLEAR_VERIFY,
|
||||
} | {
|
||||
type: typeof SIGN_VERIFY.INPUT_CHANGE,
|
||||
inputName: string,
|
||||
value: string
|
||||
} | {
|
||||
type: typeof SIGN_VERIFY.TOUCH,
|
||||
inputName: string,
|
||||
} | {
|
||||
type: typeof SIGN_VERIFY.ERROR,
|
||||
inputName: string,
|
||||
message: ?string
|
||||
} | {
|
||||
type: typeof SIGN_VERIFY.ERROR,
|
||||
inputName: string,
|
||||
message: ?string
|
||||
}
|
||||
|
||||
const sign = (
|
||||
path: Array<number>,
|
||||
message: string,
|
||||
hex: boolean = false,
|
||||
): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
if (!selected) return;
|
||||
|
||||
const response = await TrezorConnect.ethereumSignMessage({
|
||||
device: {
|
||||
path: selected.path,
|
||||
instance: selected.instance,
|
||||
state: selected.state,
|
||||
},
|
||||
path,
|
||||
hex,
|
||||
message,
|
||||
useEmptyPassphrase: selected.useEmptyPassphrase,
|
||||
});
|
||||
|
||||
if (response && response.success) {
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.SIGN_SUCCESS,
|
||||
signSignature: response.payload.signature,
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
type: 'error',
|
||||
title: 'Sign error',
|
||||
message: response.payload.error,
|
||||
cancelable: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const verify = (
|
||||
address: string,
|
||||
message: string,
|
||||
signature: string,
|
||||
hex: boolean = false,
|
||||
): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
if (!selected) return;
|
||||
const hasError = validateAddress(address);
|
||||
|
||||
if (hasError) {
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.ERROR,
|
||||
inputName: 'verifyAddress',
|
||||
message: validateAddress(address),
|
||||
});
|
||||
}
|
||||
|
||||
if (!hasError) {
|
||||
const response = await TrezorConnect.ethereumVerifyMessage({
|
||||
device: {
|
||||
path: selected.path,
|
||||
instance: selected.instance,
|
||||
state: selected.state,
|
||||
},
|
||||
address,
|
||||
message,
|
||||
signature,
|
||||
hex,
|
||||
useEmptyPassphrase: selected.useEmptyPassphrase,
|
||||
});
|
||||
|
||||
if (response && response.success) {
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
type: 'success',
|
||||
title: 'Verify success',
|
||||
message: 'signature is valid',
|
||||
cancelable: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
type: 'error',
|
||||
title: 'Verify error',
|
||||
message: response.payload.error,
|
||||
cancelable: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const inputChange = (inputName: string, value: string): ThunkAction => (dispatch: Dispatch): void => {
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.INPUT_CHANGE,
|
||||
inputName,
|
||||
value,
|
||||
});
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.TOUCH,
|
||||
inputName,
|
||||
});
|
||||
if (inputName === 'verifyAddress' && validateAddress(value) !== null) {
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.ERROR,
|
||||
inputName,
|
||||
message: validateAddress(value),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const clearSign = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.CLEAR_SIGN,
|
||||
});
|
||||
};
|
||||
|
||||
const clearVerify = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
dispatch({
|
||||
type: SIGN_VERIFY.CLEAR_VERIFY,
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
sign,
|
||||
verify,
|
||||
clearSign,
|
||||
clearVerify,
|
||||
inputChange,
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
/* @flow */
|
||||
export const SIGN_SUCCESS: 'sign__verify__sign__success' = 'sign__verify__sign__success';
|
||||
export const INPUT_CHANGE: 'sign__verify__input__change' = 'sign__verify__input__change';
|
||||
export const TOUCH: 'sign__verify__input__touch' = 'sign__verify__input__touch';
|
||||
export const CLEAR_SIGN: 'sign__verify__sign__clear' = 'sign__verify__sign__clear';
|
||||
export const CLEAR_VERIFY: 'sign__verify__verify__clear' = 'sign__verify__verify__clear';
|
||||
export const ERROR: 'sign__verify__error' = 'sign__verify__error';
|
@ -0,0 +1,24 @@
|
||||
/* @flow */
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { H3 } from 'components/Heading';
|
||||
import ICONS from 'config/icons';
|
||||
import Icon from 'components/Icon';
|
||||
|
||||
const Wrapper = styled.div``;
|
||||
|
||||
const Header = styled.div`
|
||||
padding: 48px;
|
||||
`;
|
||||
|
||||
const ConfirmAction = () => (
|
||||
<Wrapper>
|
||||
<Header>
|
||||
<Icon icon={ICONS.T1} size={100} />
|
||||
<H3>Confirm action on your Trezor</H3>
|
||||
</Header>
|
||||
</Wrapper>
|
||||
);
|
||||
|
||||
export default ConfirmAction;
|
@ -0,0 +1,95 @@
|
||||
/* @flow */
|
||||
import type { Action } from 'flowtype';
|
||||
|
||||
import * as ACCOUNT from 'actions/constants/account';
|
||||
import * as ACTION from 'actions/constants/signVerify';
|
||||
|
||||
export type Error = {
|
||||
inputName: string,
|
||||
message: ?string,
|
||||
};
|
||||
|
||||
export type State = {
|
||||
signAddress: string,
|
||||
signMessage: string,
|
||||
signSignature: string,
|
||||
verifyAddress: string,
|
||||
verifyMessage: string,
|
||||
verifySignature: string,
|
||||
touched: Array<string>,
|
||||
errors: Array<Error>
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
signAddress: '',
|
||||
signMessage: '',
|
||||
signSignature: '',
|
||||
verifyAddress: '',
|
||||
verifyMessage: '',
|
||||
verifySignature: '',
|
||||
touched: [],
|
||||
errors: [],
|
||||
};
|
||||
|
||||
export default (state: State = initialState, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case ACTION.SIGN_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
signSignature: action.signSignature,
|
||||
};
|
||||
|
||||
case ACTION.ERROR: {
|
||||
const { inputName } = action;
|
||||
if (!state.errors.some(e => e.inputName === inputName)) {
|
||||
const error = { inputName, message: action.message };
|
||||
return {
|
||||
...state,
|
||||
errors: [...state.errors, error],
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
case ACTION.TOUCH: {
|
||||
const { inputName } = action;
|
||||
if (!state.touched.includes(inputName)) {
|
||||
return {
|
||||
...state,
|
||||
touched: [...state.touched, action.inputName],
|
||||
};
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
errors: state.errors.filter(error => error.inputName !== inputName),
|
||||
};
|
||||
}
|
||||
|
||||
case ACTION.INPUT_CHANGE: {
|
||||
const change = { [action.inputName]: action.value };
|
||||
return { ...state, ...change };
|
||||
}
|
||||
|
||||
case ACCOUNT.DISPOSE:
|
||||
return initialState;
|
||||
|
||||
case ACTION.CLEAR_SIGN:
|
||||
return {
|
||||
...state,
|
||||
signAddress: '',
|
||||
signMessage: '',
|
||||
signSignature: '',
|
||||
};
|
||||
|
||||
case ACTION.CLEAR_VERIFY:
|
||||
return {
|
||||
...state,
|
||||
verifyAddress: '',
|
||||
verifyMessage: '',
|
||||
verifySignature: '',
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import colors from 'config/colors';
|
||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
font-size: ${FONT_SIZE.WALLET_TITLE};
|
||||
font-weight: ${FONT_WEIGHT.BASE};
|
||||
color: ${colors.WALLET_TITLE};
|
||||
padding-bottom: 35px;
|
||||
`;
|
||||
|
||||
const Title = ({
|
||||
children,
|
||||
}) => (
|
||||
<Wrapper>
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
|
||||
Title.propTypes = {
|
||||
children: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Title;
|
@ -0,0 +1,40 @@
|
||||
/* @flow */
|
||||
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import SignVerifyActions from 'actions/SignVerifyActions';
|
||||
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||
import type { State, Dispatch } from 'flowtype';
|
||||
import Component from './index';
|
||||
|
||||
type OwnProps = {}
|
||||
|
||||
export type Error = {
|
||||
inputName: string,
|
||||
message: ?string,
|
||||
};
|
||||
|
||||
export type StateProps = {
|
||||
wallet: $ElementType<State, 'wallet'>,
|
||||
selectedAccount: $ElementType<State, 'selectedAccount'>,
|
||||
signVerify: $ElementType<State, 'signVerify'>,
|
||||
}
|
||||
|
||||
export type DispatchProps = {
|
||||
signVerifyActions: typeof SignVerifyActions,
|
||||
}
|
||||
|
||||
export type Props = StateProps & DispatchProps;
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||
wallet: state.wallet,
|
||||
selectedAccount: state.selectedAccount,
|
||||
signVerify: state.signVerify,
|
||||
});
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
|
||||
signVerifyActions: bindActionCreators(SignVerifyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Component);
|
Loading…
Reference in new issue