mirror of
https://github.com/trezor/trezor-wallet
synced 2025-08-01 11:28:30 +00:00
Merge branch 'sign/verify'
This commit is contained in:
commit
2cdd32c503
@ -59,6 +59,7 @@
|
|||||||
"react-router-redux": "next",
|
"react-router-redux": "next",
|
||||||
"react-scale-text": "^1.2.2",
|
"react-scale-text": "^1.2.2",
|
||||||
"react-select": "2.0.0",
|
"react-select": "2.0.0",
|
||||||
|
"react-textarea-autosize": "^7.0.4",
|
||||||
"react-transition-group": "^2.4.0",
|
"react-transition-group": "^2.4.0",
|
||||||
"redbox-react": "^1.6.0",
|
"redbox-react": "^1.6.0",
|
||||||
"redux": "4.0.0",
|
"redux": "4.0.0",
|
||||||
|
165
src/actions/SignVerifyActions.js
Normal file
165
src/actions/SignVerifyActions.js
Normal file
@ -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,
|
||||||
|
};
|
7
src/actions/constants/signVerify.js
Normal file
7
src/actions/constants/signVerify.js
Normal file
@ -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';
|
@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Textarea from 'react-textarea-autosize';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import styled from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
import { FONT_SIZE, FONT_WEIGHT, FONT_FAMILY } from 'config/variables';
|
import { FONT_SIZE, FONT_WEIGHT, FONT_FAMILY } from 'config/variables';
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@ -13,13 +15,12 @@ const Wrapper = styled.div`
|
|||||||
|
|
||||||
const disabledColor = colors.TEXT_PRIMARY;
|
const disabledColor = colors.TEXT_PRIMARY;
|
||||||
|
|
||||||
const StyledTextarea = styled.textarea`
|
const StyledTextarea = styled(Textarea)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 85px;
|
min-height: 85px;
|
||||||
margin-bottom: 10px;
|
padding: 10px 12px;
|
||||||
padding: 6px 12px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 1px solid ${props => (props.borderColor ? props.borderColor : colors.DIVIDER)};
|
border: 1px solid ${props => (props.colorBorder ? props.colorBorder : colors.DIVIDER)};
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
resize: none;
|
resize: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -27,7 +28,7 @@ const StyledTextarea = styled.textarea`
|
|||||||
color: ${colors.TEXT_PRIMARY};
|
color: ${colors.TEXT_PRIMARY};
|
||||||
background: ${colors.WHITE};
|
background: ${colors.WHITE};
|
||||||
font-weight: ${FONT_WEIGHT.BASE};
|
font-weight: ${FONT_WEIGHT.BASE};
|
||||||
font-size: ${FONT_SIZE.BASE};
|
font-size: ${FONT_SIZE.SMALL};
|
||||||
white-space: pre-wrap; /* css-3 */
|
white-space: pre-wrap; /* css-3 */
|
||||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||||
white-space: -pre-wrap; /* Opera 4-6 */
|
white-space: -pre-wrap; /* Opera 4-6 */
|
||||||
@ -81,10 +82,19 @@ const StyledTextarea = styled.textarea`
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
${props => props.trezorAction && css`
|
||||||
|
z-index: 10001; /* bigger than modal container */
|
||||||
|
border-color: ${colors.WHITE};
|
||||||
|
border-width: 2px;
|
||||||
|
transform: translate(-1px, -1px);
|
||||||
|
background: ${colors.DIVIDER};
|
||||||
|
pointer-events: none;
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TopLabel = styled.span`
|
const TopLabel = styled.span`
|
||||||
padding-bottom: 4px;
|
padding-bottom: 8px;
|
||||||
color: ${colors.TEXT_SECONDARY};
|
color: ${colors.TEXT_SECONDARY};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -105,7 +115,34 @@ const getColor = (inputState) => {
|
|||||||
return color;
|
return color;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Textarea = ({
|
const TrezorAction = styled.div`
|
||||||
|
display: ${props => (props.action ? 'flex' : 'none')};
|
||||||
|
align-items: center;
|
||||||
|
margin: 0px 10px;
|
||||||
|
padding: 0 14px 0 5px;
|
||||||
|
position: absolute;
|
||||||
|
background: black;
|
||||||
|
bottom: -25px;
|
||||||
|
color: ${colors.WHITE};
|
||||||
|
border-radius: 5px;
|
||||||
|
line-height: 37px;
|
||||||
|
z-index: 10002;
|
||||||
|
transform: translate(-1px, -1px);
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ArrowUp = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
top: -9px;
|
||||||
|
left: 12px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 9px solid transparent;
|
||||||
|
border-right: 9px solid transparent;
|
||||||
|
border-bottom: 9px solid black;
|
||||||
|
z-index: 10001;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TextArea = ({
|
||||||
className,
|
className,
|
||||||
placeholder = '',
|
placeholder = '',
|
||||||
value,
|
value,
|
||||||
@ -113,28 +150,40 @@ const Textarea = ({
|
|||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
|
name,
|
||||||
onChange,
|
onChange,
|
||||||
topLabel,
|
topLabel,
|
||||||
|
rows,
|
||||||
|
maxRows,
|
||||||
|
autoSelect,
|
||||||
state = '',
|
state = '',
|
||||||
bottomText = '',
|
bottomText = '',
|
||||||
|
trezorAction = null,
|
||||||
}) => (
|
}) => (
|
||||||
<Wrapper
|
<Wrapper className={className}>
|
||||||
className={className}
|
|
||||||
>
|
|
||||||
{topLabel && (
|
{topLabel && (
|
||||||
<TopLabel>{topLabel}</TopLabel>
|
<TopLabel>{topLabel}</TopLabel>
|
||||||
)}
|
)}
|
||||||
<StyledTextarea
|
<StyledTextarea
|
||||||
|
spellCheck="false"
|
||||||
|
autoCorrect="off"
|
||||||
|
autoCapitalize="off"
|
||||||
|
maxRows={maxRows}
|
||||||
|
rows={rows}
|
||||||
className={className}
|
className={className}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
|
name={name}
|
||||||
style={customStyle}
|
style={customStyle}
|
||||||
onFocus={onFocus}
|
onFocus={onFocus}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
value={value}
|
value={value}
|
||||||
|
onClick={autoSelect ? event => event.target.select() : null}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
borderColor={getColor(state)}
|
|
||||||
/>
|
/>
|
||||||
|
<TrezorAction action={trezorAction}>
|
||||||
|
<ArrowUp />{trezorAction}
|
||||||
|
</TrezorAction>
|
||||||
{bottomText && (
|
{bottomText && (
|
||||||
<BottomText
|
<BottomText
|
||||||
color={getColor(state)}
|
color={getColor(state)}
|
||||||
@ -145,7 +194,7 @@ const Textarea = ({
|
|||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
|
||||||
Textarea.propTypes = {
|
TextArea.propTypes = {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
onFocus: PropTypes.func,
|
onFocus: PropTypes.func,
|
||||||
onBlur: PropTypes.func,
|
onBlur: PropTypes.func,
|
||||||
@ -153,10 +202,15 @@ Textarea.propTypes = {
|
|||||||
customStyle: PropTypes.string,
|
customStyle: PropTypes.string,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
|
maxRows: PropTypes.number,
|
||||||
|
rows: PropTypes.number,
|
||||||
|
name: PropTypes.string,
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
topLabel: PropTypes.node,
|
topLabel: PropTypes.node,
|
||||||
state: PropTypes.string,
|
state: PropTypes.string,
|
||||||
|
autoSelect: PropTypes.bool,
|
||||||
bottomText: PropTypes.string,
|
bottomText: PropTypes.string,
|
||||||
|
trezorAction: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Textarea;
|
export default TextArea;
|
||||||
|
@ -29,19 +29,19 @@ const InputIconWrapper = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const TopLabel = styled.span`
|
const TopLabel = styled.span`
|
||||||
padding-bottom: 10px;
|
padding-bottom: 8px;
|
||||||
color: ${colors.TEXT_SECONDARY};
|
color: ${colors.TEXT_SECONDARY};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledInput = styled.input`
|
const StyledInput = styled.input`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: ${props => (props.height ? `${props.height}px` : '40px')};
|
||||||
padding: 5px ${props => (props.hasIcon ? '40px' : '12px')} 6px 12px;
|
padding: 5px ${props => (props.hasIcon ? '40px' : '12px')} 6px 12px;
|
||||||
|
|
||||||
line-height: 1.42857143;
|
line-height: 1.42857143;
|
||||||
font-size: ${FONT_SIZE.SMALL};
|
font-size: ${props => (props.isSmallText ? `${FONT_SIZE.SMALLER}` : `${FONT_SIZE.SMALL}`)};
|
||||||
font-weight: ${FONT_WEIGHT.BASE};
|
font-weight: ${FONT_WEIGHT.BASE};
|
||||||
color: ${props => (props.color ? props.color : colors.TEXT_SECONDARY)};
|
color: ${props => (props.color ? props.color : colors.TEXT)};
|
||||||
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|
||||||
@ -55,6 +55,7 @@ const StyledInput = styled.input`
|
|||||||
|
|
||||||
background-color: ${colors.WHITE};
|
background-color: ${colors.WHITE};
|
||||||
transition: ${TRANSITION.HOVER};
|
transition: ${TRANSITION.HOVER};
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background: ${colors.GRAY_LIGHT};
|
background: ${colors.GRAY_LIGHT};
|
||||||
@ -111,7 +112,7 @@ const TrezorAction = styled.div`
|
|||||||
color: ${colors.WHITE};
|
color: ${colors.WHITE};
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
line-height: 37px;
|
line-height: 37px;
|
||||||
z-index: 10001;
|
z-index: 10002;
|
||||||
transform: translate(-1px, -1px);
|
transform: translate(-1px, -1px);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -171,6 +172,8 @@ class Input extends PureComponent {
|
|||||||
<Overlay isPartiallyHidden={this.props.isPartiallyHidden} />
|
<Overlay isPartiallyHidden={this.props.isPartiallyHidden} />
|
||||||
{this.props.icon}
|
{this.props.icon}
|
||||||
<StyledInput
|
<StyledInput
|
||||||
|
autoComplete="off"
|
||||||
|
height={this.props.height}
|
||||||
trezorAction={this.props.trezorAction}
|
trezorAction={this.props.trezorAction}
|
||||||
hasIcon={this.getIcon(this.props.state).length > 0}
|
hasIcon={this.getIcon(this.props.state).length > 0}
|
||||||
innerRef={this.props.innerRef}
|
innerRef={this.props.innerRef}
|
||||||
@ -178,10 +181,10 @@ class Input extends PureComponent {
|
|||||||
type={this.props.type}
|
type={this.props.type}
|
||||||
color={this.getColor(this.props.state)}
|
color={this.getColor(this.props.state)}
|
||||||
placeholder={this.props.placeholder}
|
placeholder={this.props.placeholder}
|
||||||
autocomplete={this.props.autocomplete}
|
autoCorrect={this.props.autocorrect}
|
||||||
autocorrect={this.props.autocorrect}
|
autoCapitalize={this.props.autocapitalize}
|
||||||
autocapitalize={this.props.autocapitalize}
|
|
||||||
spellCheck={this.props.spellCheck}
|
spellCheck={this.props.spellCheck}
|
||||||
|
isSmallText={this.props.isSmallText}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
readOnly={this.props.readOnly}
|
readOnly={this.props.readOnly}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
@ -214,7 +217,7 @@ Input.propTypes = {
|
|||||||
innerRef: PropTypes.func,
|
innerRef: PropTypes.func,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
autocomplete: PropTypes.string,
|
height: PropTypes.number,
|
||||||
autocorrect: PropTypes.string,
|
autocorrect: PropTypes.string,
|
||||||
autocapitalize: PropTypes.string,
|
autocapitalize: PropTypes.string,
|
||||||
icon: PropTypes.node,
|
icon: PropTypes.node,
|
||||||
@ -230,12 +233,14 @@ Input.propTypes = {
|
|||||||
sideAddons: PropTypes.arrayOf(PropTypes.node),
|
sideAddons: PropTypes.arrayOf(PropTypes.node),
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
|
isSmallText: PropTypes.bool,
|
||||||
isPartiallyHidden: PropTypes.bool,
|
isPartiallyHidden: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
Input.defaultProps = {
|
Input.defaultProps = {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
autoSelect: false,
|
autoSelect: false,
|
||||||
|
height: 40,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Input;
|
export default Input;
|
||||||
|
24
src/components/modals/confirm/Action/index.js
Normal file
24
src/components/modals/confirm/Action/index.js
Normal file
@ -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;
|
@ -7,7 +7,7 @@ import styled from 'styled-components';
|
|||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
import { FONT_SIZE } from 'config/variables';
|
import { FONT_SIZE } from 'config/variables';
|
||||||
|
|
||||||
import H3 from 'components/Heading';
|
import { H3 } from 'components/Heading';
|
||||||
import P from 'components/Paragraph';
|
import P from 'components/Paragraph';
|
||||||
|
|
||||||
import type { Props } from '../../Container';
|
import type { Props } from '../../Container';
|
||||||
|
@ -17,6 +17,7 @@ import InvalidPin from 'components/modals/pin/Invalid';
|
|||||||
import Passphrase from 'components/modals/passphrase/Passphrase';
|
import Passphrase from 'components/modals/passphrase/Passphrase';
|
||||||
import PassphraseType from 'components/modals/passphrase/Type';
|
import PassphraseType from 'components/modals/passphrase/Type';
|
||||||
import ConfirmSignTx from 'components/modals/confirm/SignTx';
|
import ConfirmSignTx from 'components/modals/confirm/SignTx';
|
||||||
|
import ConfirmAction from 'components/modals/confirm/Action';
|
||||||
import ConfirmUnverifiedAddress from 'components/modals/confirm/UnverifiedAddress';
|
import ConfirmUnverifiedAddress from 'components/modals/confirm/UnverifiedAddress';
|
||||||
import ForgetDevice from 'components/modals/device/Forget';
|
import ForgetDevice from 'components/modals/device/Forget';
|
||||||
import RememberDevice from 'components/modals/device/Remember';
|
import RememberDevice from 'components/modals/device/Remember';
|
||||||
@ -90,6 +91,12 @@ const getDeviceContextModal = (props: Props) => {
|
|||||||
case 'ButtonRequest_SignTx':
|
case 'ButtonRequest_SignTx':
|
||||||
return <ConfirmSignTx device={modal.device} sendForm={props.sendForm} />;
|
return <ConfirmSignTx device={modal.device} sendForm={props.sendForm} />;
|
||||||
|
|
||||||
|
case 'ButtonRequest_ProtectCall':
|
||||||
|
return <ConfirmAction />;
|
||||||
|
|
||||||
|
case 'ButtonRequest_Other':
|
||||||
|
return <ConfirmAction />;
|
||||||
|
|
||||||
case RECEIVE.REQUEST_UNVERIFIED:
|
case RECEIVE.REQUEST_UNVERIFIED:
|
||||||
return (
|
return (
|
||||||
<ConfirmUnverifiedAddress
|
<ConfirmUnverifiedAddress
|
||||||
|
@ -3,6 +3,7 @@ export default {
|
|||||||
BACKGROUND: '#EBEBEB',
|
BACKGROUND: '#EBEBEB',
|
||||||
|
|
||||||
TEXT: '#333333',
|
TEXT: '#333333',
|
||||||
|
WALLET_VIEW_TITLE: '#505050',
|
||||||
|
|
||||||
HEADER: '#1A1A1A',
|
HEADER: '#1A1A1A',
|
||||||
BODY: '#E3E3E3',
|
BODY: '#E3E3E3',
|
||||||
|
@ -3,8 +3,8 @@ export const FONT_SIZE = {
|
|||||||
SMALLER: '12px',
|
SMALLER: '12px',
|
||||||
SMALL: '14px',
|
SMALL: '14px',
|
||||||
BASE: '16px',
|
BASE: '16px',
|
||||||
WALLET_TITLE: '18px',
|
|
||||||
TOP_MENU: '17px',
|
TOP_MENU: '17px',
|
||||||
|
WALLET_TITLE: '18px',
|
||||||
BIG: '21px',
|
BIG: '21px',
|
||||||
BIGGER: '32px',
|
BIGGER: '32px',
|
||||||
BIGGEST: '36px',
|
BIGGEST: '36px',
|
||||||
|
@ -25,6 +25,7 @@ import type { ModalAction } from 'actions/ModalActions';
|
|||||||
import type { NotificationAction } from 'actions/NotificationActions';
|
import type { NotificationAction } from 'actions/NotificationActions';
|
||||||
import type { PendingTxAction } from 'actions/PendingTxActions';
|
import type { PendingTxAction } from 'actions/PendingTxActions';
|
||||||
import type { ReceiveAction } from 'actions/ReceiveActions';
|
import type { ReceiveAction } from 'actions/ReceiveActions';
|
||||||
|
import type { SignVerifyAction } from 'actions/SignVerifyActions';
|
||||||
import type { SendFormAction } from 'actions/SendFormActions';
|
import type { SendFormAction } from 'actions/SendFormActions';
|
||||||
import type { SummaryAction } from 'actions/SummaryActions';
|
import type { SummaryAction } from 'actions/SummaryActions';
|
||||||
import type { TokenAction } from 'actions/TokenActions';
|
import type { TokenAction } from 'actions/TokenActions';
|
||||||
@ -135,6 +136,7 @@ export type Action =
|
|||||||
| DiscoveryAction
|
| DiscoveryAction
|
||||||
| StorageAction
|
| StorageAction
|
||||||
| LogAction
|
| LogAction
|
||||||
|
| SignVerifyAction
|
||||||
| ModalAction
|
| ModalAction
|
||||||
| NotificationAction
|
| NotificationAction
|
||||||
| PendingTxAction
|
| PendingTxAction
|
||||||
|
@ -6,7 +6,6 @@ import * as RECEIVE from 'actions/constants/receive';
|
|||||||
import * as ACCOUNT from 'actions/constants/account';
|
import * as ACCOUNT from 'actions/constants/account';
|
||||||
import type { Action } from 'flowtype';
|
import type { Action } from 'flowtype';
|
||||||
|
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
addressVerified: boolean;
|
addressVerified: boolean;
|
||||||
addressUnverified: boolean;
|
addressUnverified: boolean;
|
||||||
|
95
src/reducers/SignVerifyReducer.js
Normal file
95
src/reducers/SignVerifyReducer.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
};
|
@ -20,6 +20,7 @@ import fiat from 'reducers/FiatRateReducer';
|
|||||||
import wallet from 'reducers/WalletReducer';
|
import wallet from 'reducers/WalletReducer';
|
||||||
import devices from 'reducers/DevicesReducer';
|
import devices from 'reducers/DevicesReducer';
|
||||||
import blockchain from 'reducers/BlockchainReducer';
|
import blockchain from 'reducers/BlockchainReducer';
|
||||||
|
import signVerify from 'reducers/SignVerifyReducer';
|
||||||
|
|
||||||
const reducers = {
|
const reducers = {
|
||||||
router: routerReducer,
|
router: routerReducer,
|
||||||
@ -41,6 +42,7 @@ const reducers = {
|
|||||||
wallet,
|
wallet,
|
||||||
devices,
|
devices,
|
||||||
blockchain,
|
blockchain,
|
||||||
|
signVerify,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Reducers = typeof reducers;
|
export type Reducers = typeof reducers;
|
||||||
|
@ -58,7 +58,7 @@ const Content = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
Content.propTypes = {
|
Content.propTypes = {
|
||||||
children: PropTypes.element,
|
children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]),
|
||||||
isLoading: PropTypes.bool,
|
isLoading: PropTypes.bool,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
message: PropTypes.string,
|
message: PropTypes.string,
|
||||||
|
26
src/views/Wallet/components/Title/index.js
Normal file
26
src/views/Wallet/components/Title/index.js
Normal file
@ -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;
|
@ -31,6 +31,7 @@ const StyledNavLink = styled(NavLink)`
|
|||||||
color: ${colors.TEXT_SECONDARY};
|
color: ${colors.TEXT_SECONDARY};
|
||||||
margin: 0px 4px;
|
margin: 0px 4px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
&.active,
|
&.active,
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -64,7 +65,7 @@ class TopNavigationAccount extends React.PureComponent<Props> {
|
|||||||
<StyledNavLink exact to={`${basePath}`}>Summary</StyledNavLink>
|
<StyledNavLink exact to={`${basePath}`}>Summary</StyledNavLink>
|
||||||
<StyledNavLink to={`${basePath}/receive`}>Receive</StyledNavLink>
|
<StyledNavLink to={`${basePath}/receive`}>Receive</StyledNavLink>
|
||||||
<StyledNavLink to={`${basePath}/send`}>Send</StyledNavLink>
|
<StyledNavLink to={`${basePath}/send`}>Send</StyledNavLink>
|
||||||
{/* <StyledNavLink to={`${basePath}/signverify`}>Sign & Verify</StyledNavLink> */}
|
<StyledNavLink to={`${basePath}/signverify`}>Sign & Verify</StyledNavLink>
|
||||||
<Indicator pathname={pathname} wrapper={() => this.wrapper} />
|
<Indicator pathname={pathname} wrapper={() => this.wrapper} />
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
@ -10,8 +10,8 @@ import Link from 'components/Link';
|
|||||||
import ICONS from 'config/icons';
|
import ICONS from 'config/icons';
|
||||||
import { FONT_SIZE, FONT_WEIGHT, TRANSITION } from 'config/variables';
|
import { FONT_SIZE, FONT_WEIGHT, TRANSITION } from 'config/variables';
|
||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
|
import Title from 'views/Wallet/components/Title';
|
||||||
import P from 'components/Paragraph';
|
import P from 'components/Paragraph';
|
||||||
import { H2 } from 'components/Heading';
|
|
||||||
import Content from 'views/Wallet/components/Content';
|
import Content from 'views/Wallet/components/Content';
|
||||||
import type { Token } from 'flowtype';
|
import type { Token } from 'flowtype';
|
||||||
import AdvancedForm from './components/AdvancedForm';
|
import AdvancedForm from './components/AdvancedForm';
|
||||||
@ -34,7 +34,7 @@ const AmountInputLabel = styled.span`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const InputRow = styled.div`
|
const InputRow = styled.div`
|
||||||
margin: 20px 0;
|
padding: 0 0 15px 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SetMaxAmountButton = styled(Button)`
|
const SetMaxAmountButton = styled(Button)`
|
||||||
@ -250,8 +250,7 @@ const AccountSend = (props: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Content>
|
<Content>
|
||||||
<React.Fragment>
|
<Title>Send Ethereum or tokens</Title>
|
||||||
<H2>Send Ethereum or tokens</H2>
|
|
||||||
<InputRow>
|
<InputRow>
|
||||||
<Input
|
<Input
|
||||||
state={getAddressInputState(address, errors.address, warnings.address)}
|
state={getAddressInputState(address, errors.address, warnings.address)}
|
||||||
@ -265,7 +264,6 @@ const AccountSend = (props: Props) => {
|
|||||||
onChange={event => onAddressChange(event.target.value)}
|
onChange={event => onAddressChange(event.target.value)}
|
||||||
/>
|
/>
|
||||||
</InputRow>
|
</InputRow>
|
||||||
|
|
||||||
<InputRow>
|
<InputRow>
|
||||||
<Input
|
<Input
|
||||||
state={getAmountInputState(errors.amount, warnings.amount)}
|
state={getAmountInputState(errors.amount, warnings.amount)}
|
||||||
@ -398,7 +396,6 @@ const AccountSend = (props: Props) => {
|
|||||||
network={network}
|
network={network}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
|
||||||
</Content>
|
</Content>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
40
src/views/Wallet/views/Account/SignVerify/Container.js
Normal file
40
src/views/Wallet/views/Account/SignVerify/Container.js
Normal file
@ -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);
|
@ -1,21 +1,36 @@
|
|||||||
import React from 'react';
|
/* @flow */
|
||||||
|
import React, { Component } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Input from 'components/inputs/Input';
|
import Input from 'components/inputs/Input';
|
||||||
import Textarea from 'components/Textarea';
|
import Textarea from 'components/Textarea';
|
||||||
|
import Title from 'views/Wallet/components/Title';
|
||||||
|
import Button from 'components/Button';
|
||||||
import Content from 'views/Wallet/components/Content';
|
import Content from 'views/Wallet/components/Content';
|
||||||
|
|
||||||
import { H2 } from 'components/Heading';
|
|
||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
|
|
||||||
|
import type { Props } from './Container';
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
margin-top: -5px;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
background: ${colors.WHITE};
|
background: ${colors.WHITE};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledH2 = styled(H2)`
|
const Row = styled.div`
|
||||||
padding-bottom: 10px;
|
padding: 0 0 25px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RowButtons = styled(Row)`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledButton = styled(Button)`
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 110px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Column = styled.div`
|
const Column = styled.div`
|
||||||
@ -30,34 +45,149 @@ const Verify = styled(Column)`
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Label = styled.div`
|
class SignVerify extends Component <Props> {
|
||||||
color: ${colors.LABEL};
|
getError(inputName: string) {
|
||||||
padding: 5px 0px;
|
if (!this.props.signVerify) return null;
|
||||||
`;
|
return this.props.signVerify.errors.find(e => e.inputName === inputName);
|
||||||
|
}
|
||||||
|
|
||||||
const AccountSignVerify = () => (
|
handleInputChange = (event: SyntheticInputEvent<Text>) => {
|
||||||
|
this.props.signVerifyActions.inputChange(event.target.name, event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const device = this.props.wallet.selectedDevice;
|
||||||
|
const {
|
||||||
|
account, discovery, shouldRender, notification,
|
||||||
|
} = this.props.selectedAccount;
|
||||||
|
const { type, title, message } = notification;
|
||||||
|
if (!device || !account || !discovery || !shouldRender) return <Content type={type} title={title} message={message} isLoading />;
|
||||||
|
const {
|
||||||
|
signVerifyActions,
|
||||||
|
signVerify: {
|
||||||
|
signMessage,
|
||||||
|
signSignature,
|
||||||
|
verifyAddress,
|
||||||
|
verifyMessage,
|
||||||
|
verifySignature,
|
||||||
|
errors,
|
||||||
|
},
|
||||||
|
} = this.props;
|
||||||
|
const verifyAddressError = this.getError('verifyAddress');
|
||||||
|
return (
|
||||||
<Content>
|
<Content>
|
||||||
|
<Title>Sign & Verify</Title>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Sign>
|
<Sign>
|
||||||
<StyledH2>Sign message</StyledH2>
|
<Row>
|
||||||
<Label>Message</Label>
|
<Input
|
||||||
<Textarea rows="4" maxLength="255" />
|
topLabel="Address"
|
||||||
<Label>Address</Label>
|
name="signAddress"
|
||||||
<Input type="text" />
|
value={account.address}
|
||||||
<Label>Signature</Label>
|
type="text"
|
||||||
<Textarea rows="4" maxLength="255" readOnly="readonly" />
|
isSmallText
|
||||||
|
autoSelect
|
||||||
|
isDisabled
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Textarea
|
||||||
|
topLabel="Message"
|
||||||
|
name="signMessage"
|
||||||
|
value={signMessage}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
rows={4}
|
||||||
|
maxRows={4}
|
||||||
|
maxLength="255"
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Textarea
|
||||||
|
topLabel="Signature"
|
||||||
|
name="signSignature"
|
||||||
|
value={signSignature}
|
||||||
|
rows={4}
|
||||||
|
autoSelect
|
||||||
|
maxRows={4}
|
||||||
|
maxLength="255"
|
||||||
|
isDisabled
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
<RowButtons>
|
||||||
|
<Button
|
||||||
|
onClick={this.props.signVerifyActions.clearSign}
|
||||||
|
isWhite
|
||||||
|
>Clear
|
||||||
|
</Button>
|
||||||
|
<StyledButton
|
||||||
|
onClick={() => signVerifyActions.sign(account.addressPath, signMessage)}
|
||||||
|
>Sign
|
||||||
|
</StyledButton>
|
||||||
|
</RowButtons>
|
||||||
</Sign>
|
</Sign>
|
||||||
<Verify>
|
<Verify>
|
||||||
<StyledH2>Verify message</StyledH2>
|
<Row>
|
||||||
<Label>Message</Label>
|
<Input
|
||||||
<Textarea rows="4" maxLength="255" />
|
topLabel="Address"
|
||||||
<Label>Address</Label>
|
autoSelect
|
||||||
<Input type="text" />
|
name="verifyAddress"
|
||||||
<Label>Signature</Label>
|
value={verifyAddress}
|
||||||
<Textarea rows="4" maxLength="255" />
|
onChange={this.handleInputChange}
|
||||||
|
type="text"
|
||||||
|
state={verifyAddressError ? 'error' : null}
|
||||||
|
bottomText={verifyAddressError ? verifyAddressError.message : null}
|
||||||
|
isSmallText
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Textarea
|
||||||
|
topLabel="Message"
|
||||||
|
name="verifyMessage"
|
||||||
|
value={verifyMessage}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
rows={4}
|
||||||
|
maxRows={4}
|
||||||
|
maxLength="255"
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Textarea
|
||||||
|
topLabel="Signature"
|
||||||
|
autoSelect
|
||||||
|
name="verifySignature"
|
||||||
|
value={verifySignature}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
rows={4}
|
||||||
|
maxRows={4}
|
||||||
|
maxLength="255"
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
<RowButtons>
|
||||||
|
<Button
|
||||||
|
onClick={signVerifyActions.clearVerify}
|
||||||
|
isWhite
|
||||||
|
>Clear
|
||||||
|
</Button>
|
||||||
|
<StyledButton
|
||||||
|
onClick={
|
||||||
|
() => {
|
||||||
|
if (errors.length <= 0) {
|
||||||
|
signVerifyActions.verify(
|
||||||
|
verifyAddress,
|
||||||
|
verifyMessage,
|
||||||
|
verifySignature,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>Verify
|
||||||
|
</StyledButton>
|
||||||
|
</RowButtons>
|
||||||
</Verify>
|
</Verify>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
</Content>
|
</Content>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default AccountSignVerify;
|
export default SignVerify;
|
@ -57,6 +57,7 @@ const StyledCoinLogo = styled(CoinLogo)`
|
|||||||
const StyledIcon = styled(Icon)`
|
const StyledIcon = styled(Icon)`
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -7px;
|
top: -7px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import WalletContainer from 'views/Wallet';
|
|||||||
import AccountSummary from 'views/Wallet/views/Account/Summary/Container';
|
import AccountSummary from 'views/Wallet/views/Account/Summary/Container';
|
||||||
import AccountSend from 'views/Wallet/views/Account/Send/Container';
|
import AccountSend from 'views/Wallet/views/Account/Send/Container';
|
||||||
import AccountReceive from 'views/Wallet/views/Account/Receive/Container';
|
import AccountReceive from 'views/Wallet/views/Account/Receive/Container';
|
||||||
import AccountSignVerify from 'views/Wallet/views/Account/SignVerify';
|
import AccountSignVerify from 'views/Wallet/views/Account/SignVerify/Container';
|
||||||
|
|
||||||
import WalletDashboard from 'views/Wallet/views/Dashboard';
|
import WalletDashboard from 'views/Wallet/views/Dashboard';
|
||||||
import WalletDeviceSettings from 'views/Wallet/views/DeviceSettings';
|
import WalletDeviceSettings from 'views/Wallet/views/DeviceSettings';
|
||||||
|
@ -8500,9 +8500,15 @@ react-select@2.0.0:
|
|||||||
react-input-autosize "^2.2.1"
|
react-input-autosize "^2.2.1"
|
||||||
react-transition-group "^2.2.1"
|
react-transition-group "^2.2.1"
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
react-textarea-autosize@^7.0.4:
|
||||||
|
version "7.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.0.4.tgz#4e4be649b544a88713e7b5043f76950f35d3d503"
|
||||||
|
=======
|
||||||
react-textarea-autosize@^6.1.0:
|
react-textarea-autosize@^6.1.0:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "http://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz#df91387f8a8f22020b77e3833c09829d706a09a5"
|
resolved "http://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz#df91387f8a8f22020b77e3833c09829d706a09a5"
|
||||||
|
>>>>>>> master
|
||||||
dependencies:
|
dependencies:
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user