Update with latest dapps
This commit is contained in:
@@ -23,10 +23,9 @@ import { bindActionCreators } from 'redux';
|
||||
|
||||
import * as RequestsActions from '@parity/shared/redux/providers/signerActions';
|
||||
import { Container } from '@parity/ui';
|
||||
import RequestPending from '@parity/ui/Signer/RequestPending';
|
||||
|
||||
import Store from '../store';
|
||||
|
||||
import RequestPending from '../components/RequestPending';
|
||||
import Store from '@parity/shared/mobx/signerStore';
|
||||
|
||||
import styles from './embedded.css';
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.container {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link } from 'react-router';
|
||||
|
||||
import styles from './accountLink.css';
|
||||
|
||||
class AccountLink extends Component {
|
||||
static propTypes = {
|
||||
accountAddresses: PropTypes.array.isRequired,
|
||||
address: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
externalLink: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
state = {
|
||||
link: null
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
const { address, externalLink } = this.props;
|
||||
|
||||
this.updateLink(address, externalLink);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const { address, externalLink } = nextProps;
|
||||
|
||||
this.updateLink(address, externalLink);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { children, address, className, externalLink } = this.props;
|
||||
|
||||
if (externalLink) {
|
||||
return (
|
||||
<a
|
||||
href={ this.state.link }
|
||||
target='_blank'
|
||||
className={ `${styles.container} ${className}` }
|
||||
>
|
||||
{ children || address }
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={ `${styles.container} ${className}` }
|
||||
to={ this.state.link }
|
||||
>
|
||||
{ children || address }
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
updateLink (address, externalLink) {
|
||||
const { accountAddresses } = this.props;
|
||||
const isAccount = accountAddresses.includes(address);
|
||||
|
||||
let link = isAccount
|
||||
? `/accounts/${address}`
|
||||
: `/addresses/${address}`;
|
||||
|
||||
if (externalLink) {
|
||||
const path = externalLink.replace(/\/+$/, '');
|
||||
|
||||
link = `${path}/#${link}`;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
link
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (initState) {
|
||||
const { accounts } = initState.personal;
|
||||
const accountAddresses = Object.keys(accounts);
|
||||
|
||||
return () => {
|
||||
return { accountAddresses };
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(AccountLink);
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './accountLink';
|
||||
@@ -1,50 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.acc {
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.acc > * {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.address {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.acc img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
vertical-align: middle;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.name {
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
text-transform: uppercase;
|
||||
|
||||
span {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { IdentityIcon, IdentityName } from '@parity/ui';
|
||||
|
||||
import AccountLink from './AccountLink';
|
||||
|
||||
import styles from './account.css';
|
||||
|
||||
export default class Account extends Component {
|
||||
static propTypes = {
|
||||
address: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
externalLink: PropTypes.string.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
balance: PropTypes.object // eth BigNumber, not required since it mght take time to fetch
|
||||
};
|
||||
|
||||
state = {
|
||||
balanceDisplay: '?'
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.updateBalanceDisplay(this.props.balance);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.balance === this.props.balance) {
|
||||
return;
|
||||
}
|
||||
this.updateBalanceDisplay(nextProps.balance);
|
||||
}
|
||||
|
||||
updateBalanceDisplay (balance) {
|
||||
this.setState({
|
||||
balanceDisplay: balance ? balance.div(1e18).toFormat(3) : '?'
|
||||
});
|
||||
}
|
||||
|
||||
render () {
|
||||
const { address, className, disabled, externalLink, netVersion } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.acc} ${className}` }>
|
||||
<AccountLink
|
||||
address={ address }
|
||||
externalLink={ externalLink }
|
||||
netVersion={ netVersion }
|
||||
>
|
||||
<IdentityIcon
|
||||
center
|
||||
disabled={ disabled }
|
||||
address={ address }
|
||||
/>
|
||||
</AccountLink>
|
||||
{ this.renderName() }
|
||||
{ this.renderBalance() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderBalance () {
|
||||
const { balanceDisplay } = this.state;
|
||||
|
||||
return (
|
||||
<span> <strong>{ balanceDisplay }</strong> <small>ETH</small></span>
|
||||
);
|
||||
}
|
||||
|
||||
renderName () {
|
||||
const { address, externalLink, netVersion } = this.props;
|
||||
const name = <IdentityName address={ address } empty />;
|
||||
|
||||
if (!name) {
|
||||
return (
|
||||
<AccountLink
|
||||
address={ address }
|
||||
externalLink={ externalLink }
|
||||
netVersion={ netVersion }
|
||||
>
|
||||
[{ this.shortAddress(address) }]
|
||||
</AccountLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AccountLink
|
||||
address={ address }
|
||||
externalLink={ externalLink }
|
||||
netVersion={ netVersion }
|
||||
>
|
||||
<span>
|
||||
<span className={ styles.name }>{ name }</span>
|
||||
<span className={ styles.address }>[{ this.tinyAddress(address) }]</span>
|
||||
</span>
|
||||
</AccountLink>
|
||||
);
|
||||
}
|
||||
|
||||
tinyAddress () {
|
||||
const { address } = this.props;
|
||||
const len = address.length;
|
||||
|
||||
return address.slice(2, 4) + '..' + address.slice(len - 2);
|
||||
}
|
||||
|
||||
shortAddress () {
|
||||
const { address } = this.props;
|
||||
const len = address.length;
|
||||
|
||||
return address.slice(2, 8) + '..' + address.slice(len - 7);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './account';
|
||||
@@ -1,185 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Account from '../Account';
|
||||
import TransactionPendingForm from '../TransactionPendingForm';
|
||||
import RequestOrigin from '../RequestOrigin';
|
||||
|
||||
import styles from '../SignRequest/signRequest.css';
|
||||
|
||||
@observer
|
||||
class DecryptRequest extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
accounts: PropTypes.object.isRequired,
|
||||
address: PropTypes.string.isRequired,
|
||||
data: PropTypes.string.isRequired,
|
||||
id: PropTypes.object.isRequired,
|
||||
isFinished: PropTypes.bool.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
signerStore: PropTypes.object.isRequired,
|
||||
|
||||
className: PropTypes.string,
|
||||
focus: PropTypes.bool,
|
||||
isSending: PropTypes.bool,
|
||||
onConfirm: PropTypes.func,
|
||||
onReject: PropTypes.func,
|
||||
origin: PropTypes.any,
|
||||
status: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
focus: false,
|
||||
origin: {
|
||||
type: 'unknown',
|
||||
details: ''
|
||||
}
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
const { address, signerStore } = this.props;
|
||||
|
||||
signerStore.fetchBalance(address);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
{ this.renderDetails() }
|
||||
{ this.renderActions() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderDetails () {
|
||||
const { api } = this.context;
|
||||
const { address, data, netVersion, origin, signerStore } = this.props;
|
||||
const { balances, externalLink } = signerStore;
|
||||
|
||||
const balance = balances[address];
|
||||
|
||||
if (!balance) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.signDetails }>
|
||||
<div className={ styles.address }>
|
||||
<Account
|
||||
address={ address }
|
||||
balance={ balance }
|
||||
className={ styles.account }
|
||||
externalLink={ externalLink }
|
||||
netVersion={ netVersion }
|
||||
/>
|
||||
<RequestOrigin origin={ origin } />
|
||||
</div>
|
||||
<div className={ styles.info } title={ api.util.sha3(data) }>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='signer.decryptRequest.request'
|
||||
defaultMessage='A request to decrypt data using your account:'
|
||||
/>
|
||||
</p>
|
||||
|
||||
<div className={ styles.signData }>
|
||||
<p>{ data }</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { accounts, address, focus, isFinished, status, data } = this.props;
|
||||
const account = accounts[address];
|
||||
|
||||
if (isFinished) {
|
||||
if (status === 'confirmed') {
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<span className={ styles.isConfirmed }>
|
||||
<FormattedMessage
|
||||
id='signer.decryptRequest.state.confirmed'
|
||||
defaultMessage='Confirmed'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<span className={ styles.isRejected }>
|
||||
<FormattedMessage
|
||||
id='signer.decryptRequest.state.rejected'
|
||||
defaultMessage='Rejected'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TransactionPendingForm
|
||||
account={ account }
|
||||
address={ address }
|
||||
focus={ focus }
|
||||
isSending={ this.props.isSending }
|
||||
netVersion={ this.props.netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ this.onReject }
|
||||
className={ styles.actions }
|
||||
dataToSign={ { decrypt: data } }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
onConfirm = (data) => {
|
||||
const { id } = this.props;
|
||||
const { password, decrypted, wallet } = data;
|
||||
|
||||
this.props.onConfirm({ id, password, decrypted, wallet });
|
||||
}
|
||||
|
||||
onReject = () => {
|
||||
this.props.onReject(this.props.id);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { accounts } = state.personal;
|
||||
|
||||
return {
|
||||
accounts
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(DecryptRequest);
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './decryptRequest';
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './requestOrigin';
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.container {
|
||||
text-align: left;
|
||||
margin: 3em .5em;
|
||||
opacity: 0.6;
|
||||
font-size: 0.8em;
|
||||
|
||||
.unknown {
|
||||
color: #e44;
|
||||
}
|
||||
|
||||
.url {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.hash {
|
||||
margin-left: .5em;
|
||||
}
|
||||
|
||||
.hash, .url {
|
||||
margin-bottom: -.2em;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import IdentityIcon from '@parity/ui/IdentityIcon';
|
||||
|
||||
import styles from './requestOrigin.css';
|
||||
|
||||
export default class RequestOrigin extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
origin: PropTypes.shape({
|
||||
type: PropTypes.oneOf(['unknown', 'dapp', 'rpc', 'ipc', 'signer']),
|
||||
details: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.shape({
|
||||
session: PropTypes.string.isRequired
|
||||
})
|
||||
]).isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { origin } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ styles.container }>
|
||||
Requested { this.renderOrigin(origin) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderOrigin (origin) {
|
||||
if (origin.type === 'unknown') {
|
||||
return (
|
||||
<span className={ styles.unknown }>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.unknownInterface'
|
||||
defaultMessage='via unknown interface'
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (origin.type === 'dapp') {
|
||||
return (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.dapp'
|
||||
defaultMessage='by a dapp at {url}'
|
||||
values={ {
|
||||
url: (
|
||||
<span className={ styles.url }>
|
||||
{
|
||||
origin.details || (
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.unknownUrl'
|
||||
defaultMessage='unknown URL'
|
||||
/>
|
||||
)
|
||||
}
|
||||
</span>
|
||||
)
|
||||
} }
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (origin.type === 'rpc') {
|
||||
return (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.rpc'
|
||||
defaultMessage='via RPC {url}'
|
||||
values={ {
|
||||
url: (
|
||||
<span className={ styles.url }>
|
||||
({
|
||||
origin.details || (
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.unknownRpc'
|
||||
defaultMessage='unidentified'
|
||||
/>
|
||||
)
|
||||
})
|
||||
</span>
|
||||
)
|
||||
} }
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (origin.type === 'ipc') {
|
||||
return (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.ipc'
|
||||
defaultMessage='via IPC session'
|
||||
/>
|
||||
<span
|
||||
className={ styles.hash }
|
||||
title={ origin.details }
|
||||
>
|
||||
<IdentityIcon
|
||||
address={ origin.details }
|
||||
tiny
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (origin.type === 'signer') {
|
||||
const session = origin.details && origin.details.session || origin.details;
|
||||
|
||||
return this.renderSigner(session);
|
||||
}
|
||||
}
|
||||
|
||||
renderSigner (session) {
|
||||
if (session.substr(2) === this.context.api.transport.sessionHash) {
|
||||
return (
|
||||
<span title={ session }>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.signerCurrent'
|
||||
defaultMessage='via current tab'
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.signerUI'
|
||||
defaultMessage='via UI session'
|
||||
/>
|
||||
<span
|
||||
className={ styles.hash }
|
||||
title={ `UI Session id: ${session}` }
|
||||
>
|
||||
<IdentityIcon
|
||||
address={ session }
|
||||
tiny
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import RequestOrigin from './';
|
||||
|
||||
const context = {
|
||||
context: {
|
||||
api: {
|
||||
transport: {
|
||||
sessionHash: '1234'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe('views/Signer/components/RequestOrigin', () => {
|
||||
it('renders unknown', () => {
|
||||
expect(shallow(
|
||||
<RequestOrigin origin={ { type: 'unknown', details: '' } } />,
|
||||
context
|
||||
).find('FormattedMessage').props().id).to.equal('signer.requestOrigin.unknownInterface');
|
||||
});
|
||||
|
||||
it('renders dapps', () => {
|
||||
expect(shallow(
|
||||
<RequestOrigin origin={ { type: 'dapp', details: 'http://parity.io' } } />,
|
||||
context
|
||||
).find('FormattedMessage').props().id).to.equal('signer.requestOrigin.dapp');
|
||||
});
|
||||
|
||||
it('renders rpc', () => {
|
||||
expect(shallow(
|
||||
<RequestOrigin origin={ { type: 'rpc', details: '' } } />,
|
||||
context
|
||||
).find('FormattedMessage').props().id).to.equal('signer.requestOrigin.rpc');
|
||||
});
|
||||
|
||||
it('renders ipc', () => {
|
||||
expect(shallow(
|
||||
<RequestOrigin origin={ { type: 'ipc', details: '0x1234' } } />,
|
||||
context
|
||||
).find('FormattedMessage').props().id).to.equal('signer.requestOrigin.ipc');
|
||||
});
|
||||
|
||||
it('renders signer', () => {
|
||||
expect(shallow(
|
||||
<RequestOrigin origin={ { type: 'signer', details: '0x12345' } } />,
|
||||
context
|
||||
).find('FormattedMessage').props().id).to.equal('signer.requestOrigin.signerUI');
|
||||
|
||||
expect(shallow(
|
||||
<RequestOrigin origin={ { type: 'signer', details: '0x1234' } } />,
|
||||
context
|
||||
).find('FormattedMessage').props().id).to.equal('signer.requestOrigin.signerCurrent');
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './requestPending';
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import DecryptRequest from '../DecryptRequest';
|
||||
import SignRequest from '../SignRequest';
|
||||
import TransactionPending from '../TransactionPending';
|
||||
|
||||
export default class RequestPending extends Component {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
date: PropTypes.instanceOf(Date).isRequired,
|
||||
focus: PropTypes.bool,
|
||||
gasLimit: PropTypes.object.isRequired,
|
||||
id: PropTypes.object.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onReject: PropTypes.func.isRequired,
|
||||
origin: PropTypes.object.isRequired,
|
||||
payload: PropTypes.oneOfType([
|
||||
PropTypes.shape({ decrypt: PropTypes.object.isRequired }),
|
||||
PropTypes.shape({ sendTransaction: PropTypes.object.isRequired }),
|
||||
PropTypes.shape({ sign: PropTypes.object.isRequired }),
|
||||
PropTypes.shape({ signTransaction: PropTypes.object.isRequired })
|
||||
]).isRequired,
|
||||
signerStore: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
focus: false,
|
||||
isSending: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const { className, date, focus, gasLimit, id, isSending, netVersion, onReject, payload, signerStore, origin } = this.props;
|
||||
|
||||
if (payload.sign) {
|
||||
const { sign } = payload;
|
||||
|
||||
return (
|
||||
<SignRequest
|
||||
address={ sign.address }
|
||||
className={ className }
|
||||
focus={ focus }
|
||||
data={ sign.data }
|
||||
id={ id }
|
||||
isFinished={ false }
|
||||
isSending={ isSending }
|
||||
netVersion={ netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ onReject }
|
||||
origin={ origin }
|
||||
signerStore={ signerStore }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (payload.decrypt) {
|
||||
const { decrypt } = payload;
|
||||
|
||||
return (
|
||||
<DecryptRequest
|
||||
address={ decrypt.address }
|
||||
className={ className }
|
||||
focus={ focus }
|
||||
data={ decrypt.msg }
|
||||
id={ id }
|
||||
isFinished={ false }
|
||||
isSending={ isSending }
|
||||
netVersion={ netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ onReject }
|
||||
origin={ origin }
|
||||
signerStore={ signerStore }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const transaction = payload.sendTransaction || payload.signTransaction;
|
||||
|
||||
if (transaction) {
|
||||
return (
|
||||
<TransactionPending
|
||||
className={ className }
|
||||
date={ date }
|
||||
focus={ focus }
|
||||
gasLimit={ gasLimit }
|
||||
id={ id }
|
||||
isSending={ isSending }
|
||||
netVersion={ netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ onReject }
|
||||
origin={ origin }
|
||||
signerStore={ signerStore }
|
||||
transaction={ transaction }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
console.error('RequestPending: Unknown payload', payload);
|
||||
return null;
|
||||
}
|
||||
|
||||
onConfirm = (data) => {
|
||||
const { onConfirm, payload } = this.props;
|
||||
|
||||
data.payload = payload;
|
||||
onConfirm(data);
|
||||
};
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import RequestPending from './';
|
||||
|
||||
const ADDRESS = '0x1234567890123456789012345678901234567890';
|
||||
const TRANSACTION = {
|
||||
from: ADDRESS,
|
||||
gas: new BigNumber(21000),
|
||||
gasPrice: new BigNumber(20000000),
|
||||
value: new BigNumber(1)
|
||||
};
|
||||
const PAYLOAD_SENDTX = {
|
||||
sendTransaction: TRANSACTION
|
||||
};
|
||||
const PAYLOAD_SIGN = {
|
||||
sign: {
|
||||
address: ADDRESS,
|
||||
data: 'testing'
|
||||
}
|
||||
};
|
||||
const PAYLOAD_SIGNTX = {
|
||||
signTransaction: TRANSACTION
|
||||
};
|
||||
const PAYLOAD_DECRYPT = {
|
||||
decrypt: {
|
||||
address: ADDRESS,
|
||||
msg: 'testing'
|
||||
}
|
||||
};
|
||||
|
||||
let component;
|
||||
let onConfirm;
|
||||
let onReject;
|
||||
|
||||
function render (payload) {
|
||||
onConfirm = sinon.stub();
|
||||
onReject = sinon.stub();
|
||||
|
||||
component = shallow(
|
||||
<RequestPending
|
||||
date={ new Date() }
|
||||
gasLimit={ new BigNumber(100000) }
|
||||
id={ new BigNumber(123) }
|
||||
isSending={ false }
|
||||
netVersion='42'
|
||||
onConfirm={ onConfirm }
|
||||
onReject={ onReject }
|
||||
origin={ {} }
|
||||
payload={ payload }
|
||||
store={ {} }
|
||||
/>
|
||||
);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('views/Signer/RequestPending', () => {
|
||||
describe('sendTransaction', () => {
|
||||
beforeEach(() => {
|
||||
render(PAYLOAD_SENDTX);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('renders TransactionPending component', () => {
|
||||
expect(component.find('Connect(TransactionPending)')).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sign', () => {
|
||||
beforeEach(() => {
|
||||
render(PAYLOAD_SIGN);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('renders SignRequest component', () => {
|
||||
expect(component.find('Connect(SignRequest)')).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('signTransaction', () => {
|
||||
beforeEach(() => {
|
||||
render(PAYLOAD_SIGNTX);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('renders TransactionPending component', () => {
|
||||
expect(component.find('Connect(TransactionPending)')).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decrypt', () => {
|
||||
beforeEach(() => {
|
||||
render(PAYLOAD_DECRYPT);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('renders DecryptRequest component', () => {
|
||||
expect(component.find('Connect(DecryptRequest)')).to.have.length(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './signRequest';
|
||||
@@ -1,91 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@import '../../_layout.css';
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
padding: 1.5em 1em 1.5em 0;
|
||||
}
|
||||
|
||||
.actions, .signDetails {
|
||||
vertical-align: middle;
|
||||
min-height: $pendingHeight;
|
||||
}
|
||||
|
||||
.signData {
|
||||
border: 0.25em solid red;
|
||||
margin-left: 2em;
|
||||
padding: 0.5em;
|
||||
overflow: auto;
|
||||
max-height: 6em;
|
||||
max-width: calc(100% - 2em);
|
||||
}
|
||||
|
||||
.signData > p {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.signDetails {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.account img {
|
||||
display: inline-block;
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.address, .info {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.address {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.info {
|
||||
color: #E53935;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.info p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* TODO [todr] copy&paste from transactions */
|
||||
.isConfirmed {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.isRejected {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.txHash {
|
||||
display: block;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: inline-block;
|
||||
min-height: $finishedHeight;
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import HardwareStore from '@parity/shared/mobx/hardwareStore';
|
||||
|
||||
import Account from '../Account';
|
||||
import TransactionPendingForm from '../TransactionPendingForm';
|
||||
import RequestOrigin from '../RequestOrigin';
|
||||
|
||||
import styles from './signRequest.css';
|
||||
|
||||
function isAscii (data) {
|
||||
for (var i = 2; i < data.length; i += 2) {
|
||||
let n = parseInt(data.substr(i, 2), 16);
|
||||
|
||||
if (n < 32 || n >= 128) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@observer
|
||||
class SignRequest extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
accounts: PropTypes.object.isRequired,
|
||||
address: PropTypes.string.isRequired,
|
||||
data: PropTypes.string.isRequired,
|
||||
id: PropTypes.object.isRequired,
|
||||
isFinished: PropTypes.bool.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
signerStore: PropTypes.object.isRequired,
|
||||
|
||||
className: PropTypes.string,
|
||||
focus: PropTypes.bool,
|
||||
isSending: PropTypes.bool,
|
||||
onConfirm: PropTypes.func,
|
||||
onReject: PropTypes.func,
|
||||
origin: PropTypes.any,
|
||||
status: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
focus: false,
|
||||
origin: {
|
||||
type: 'unknown',
|
||||
details: ''
|
||||
}
|
||||
};
|
||||
|
||||
hardwareStore = HardwareStore.get(this.context.api);
|
||||
|
||||
componentWillMount () {
|
||||
const { address, signerStore } = this.props;
|
||||
|
||||
signerStore.fetchBalance(address);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
{ this.renderDetails() }
|
||||
{ this.renderActions() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderAsciiDetails (ascii) {
|
||||
return (
|
||||
<div className={ styles.signData }>
|
||||
<p>{ascii}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderBinaryDetails (data) {
|
||||
return (
|
||||
<div className={ styles.signData }>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='signer.signRequest.unknownBinary'
|
||||
defaultMessage='(Unknown binary data)'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderDetails () {
|
||||
const { api } = this.context;
|
||||
const { address, data, netVersion, origin, signerStore } = this.props;
|
||||
const { balances, externalLink } = signerStore;
|
||||
|
||||
const balance = balances[address];
|
||||
|
||||
if (!balance) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.signDetails }>
|
||||
<div className={ styles.address }>
|
||||
<Account
|
||||
address={ address }
|
||||
balance={ balance }
|
||||
className={ styles.account }
|
||||
externalLink={ externalLink }
|
||||
netVersion={ netVersion }
|
||||
/>
|
||||
<RequestOrigin origin={ origin } />
|
||||
</div>
|
||||
<div className={ styles.info } title={ api.util.sha3(data) }>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='signer.signRequest.request'
|
||||
defaultMessage='A request to sign data using your account:'
|
||||
/>
|
||||
</p>
|
||||
{
|
||||
isAscii(data)
|
||||
? this.renderAsciiDetails(api.util.hexToAscii(data))
|
||||
: this.renderBinaryDetails(data)
|
||||
}
|
||||
<p>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='signer.signRequest.warning'
|
||||
defaultMessage='WARNING: This consequences of doing this may be grave. Confirm the request only if you are sure.'
|
||||
/>
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { accounts, address, focus, isFinished, status, data } = this.props;
|
||||
const account = accounts[address] || {};
|
||||
const disabled = account.hardware && !this.hardwareStore.isConnected(address);
|
||||
|
||||
if (isFinished) {
|
||||
if (status === 'confirmed') {
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<span className={ styles.isConfirmed }>
|
||||
<FormattedMessage
|
||||
id='signer.signRequest.state.confirmed'
|
||||
defaultMessage='Confirmed'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<span className={ styles.isRejected }>
|
||||
<FormattedMessage
|
||||
id='signer.signRequest.state.rejected'
|
||||
defaultMessage='Rejected'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TransactionPendingForm
|
||||
account={ account }
|
||||
address={ address }
|
||||
disabled={ disabled }
|
||||
focus={ focus }
|
||||
isSending={ this.props.isSending }
|
||||
netVersion={ this.props.netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ this.onReject }
|
||||
className={ styles.actions }
|
||||
dataToSign={ { data } }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
onConfirm = (data) => {
|
||||
const { id } = this.props;
|
||||
const { password, dataSigned, wallet } = data;
|
||||
|
||||
this.props.onConfirm({ id, password, dataSigned, wallet });
|
||||
}
|
||||
|
||||
onReject = () => {
|
||||
this.props.onReject(this.props.id);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { accounts } = state.personal;
|
||||
|
||||
return {
|
||||
accounts
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(SignRequest);
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import SignRequest from './';
|
||||
|
||||
let component;
|
||||
let reduxStore;
|
||||
let signerStore;
|
||||
|
||||
function createSignerStore () {
|
||||
return {
|
||||
balances: {},
|
||||
fetchBalance: sinon.stub()
|
||||
};
|
||||
}
|
||||
|
||||
function createReduxStore () {
|
||||
return {
|
||||
dispatch: sinon.stub(),
|
||||
subscribe: sinon.stub(),
|
||||
getState: () => {
|
||||
return {
|
||||
personal: {
|
||||
accounts: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function render () {
|
||||
reduxStore = createReduxStore();
|
||||
signerStore = createSignerStore();
|
||||
|
||||
component = shallow(
|
||||
<SignRequest signerStore={ signerStore } />,
|
||||
{
|
||||
context: {
|
||||
store: reduxStore
|
||||
}
|
||||
}
|
||||
).find('SignRequest').shallow();
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('views/Signer/components/SignRequest', () => {
|
||||
beforeEach(() => {
|
||||
render();
|
||||
});
|
||||
|
||||
it('renders', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './transactionMainDetails';
|
||||
@@ -1,80 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@import '../../_layout.css';
|
||||
|
||||
.account {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contractIcon {
|
||||
background: #eee;
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
padding: 13px;
|
||||
}
|
||||
|
||||
.editButtonRow {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.from {
|
||||
display: inline-block;
|
||||
width: 40%;
|
||||
vertical-align: top;
|
||||
|
||||
.account {
|
||||
img {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.method {
|
||||
display: inline-block;
|
||||
width: 60%;
|
||||
vertical-align: top;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.tx {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin: 0 -75px;
|
||||
width: 150px;
|
||||
top: -20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.total {
|
||||
font-size: 0.6em;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.transaction {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
import { Button, MethodDecoding } from '@parity/ui';
|
||||
import { GasIcon } from '@parity/ui/Icons';
|
||||
|
||||
import * as tUtil from '../util/transaction';
|
||||
import Account from '../Account';
|
||||
import RequestOrigin from '../RequestOrigin';
|
||||
|
||||
import styles from './transactionMainDetails.css';
|
||||
|
||||
export default class TransactionMainDetails extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
disabled: PropTypes.bool,
|
||||
externalLink: PropTypes.string.isRequired,
|
||||
from: PropTypes.string.isRequired,
|
||||
fromBalance: PropTypes.object,
|
||||
gasStore: PropTypes.object,
|
||||
id: PropTypes.object.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
origin: PropTypes.any,
|
||||
totalValue: PropTypes.object.isRequired,
|
||||
transaction: PropTypes.object.isRequired,
|
||||
value: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
origin: {
|
||||
type: 'unknown',
|
||||
details: ''
|
||||
}
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
const { totalValue, value } = this.props;
|
||||
|
||||
this.updateDisplayValues(value, totalValue);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const { totalValue, value } = nextProps;
|
||||
|
||||
this.updateDisplayValues(value, totalValue);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { children, disabled, externalLink, from, fromBalance, gasStore, netVersion, transaction, origin } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ styles.transaction }>
|
||||
<div className={ styles.from }>
|
||||
<div className={ styles.account }>
|
||||
<Account
|
||||
address={ from }
|
||||
balance={ fromBalance }
|
||||
disabled={ disabled }
|
||||
externalLink={ externalLink }
|
||||
netVersion={ netVersion }
|
||||
/>
|
||||
</div>
|
||||
<RequestOrigin origin={ origin } />
|
||||
</div>
|
||||
<div className={ styles.method }>
|
||||
<MethodDecoding
|
||||
address={ from }
|
||||
historic={ false }
|
||||
transaction={
|
||||
gasStore
|
||||
? gasStore.overrideTransaction(transaction)
|
||||
: transaction
|
||||
}
|
||||
/>
|
||||
{ this.renderEditTx() }
|
||||
</div>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderEditTx () {
|
||||
const { gasStore } = this.props;
|
||||
|
||||
if (!gasStore) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.editButtonRow }>
|
||||
<Button
|
||||
icon={ <GasIcon /> }
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='signer.mainDetails.editTx'
|
||||
defaultMessage='Edit conditions/gas/gasPrice'
|
||||
/>
|
||||
}
|
||||
onClick={ this.toggleGasEditor }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderTotalValue () {
|
||||
const { id } = this.props;
|
||||
const { feeEth, totalValueDisplay, totalValueDisplayWei } = this.state;
|
||||
const labelId = `totalValue${id}`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className={ styles.total }
|
||||
data-effect='solid'
|
||||
data-for={ labelId }
|
||||
data-place='bottom'
|
||||
data-tip
|
||||
>
|
||||
{ totalValueDisplay } <small>ETH</small>
|
||||
</div>
|
||||
<ReactTooltip id={ labelId }>
|
||||
<FormattedMessage
|
||||
id='signer.mainDetails.tooltips.total1'
|
||||
defaultMessage='The value of the transaction including the mining fee is {total} {type}.'
|
||||
values={ {
|
||||
total: <strong>{ totalValueDisplayWei }</strong>,
|
||||
type: <small>WEI</small>
|
||||
} }
|
||||
/>
|
||||
<br />
|
||||
<FormattedMessage
|
||||
id='signer.mainDetails.tooltips.total2'
|
||||
defaultMessage='(This includes a mining fee of {fee} {token})'
|
||||
values={ {
|
||||
fee: <strong>{ feeEth }</strong>,
|
||||
token: <small>ETH</small>
|
||||
} }
|
||||
/>
|
||||
</ReactTooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderValue () {
|
||||
const { id } = this.props;
|
||||
const { valueDisplay, valueDisplayWei } = this.state;
|
||||
const labelId = `value${id}`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
data-effect='solid'
|
||||
data-for={ labelId }
|
||||
data-tip
|
||||
>
|
||||
<strong>{ valueDisplay } </strong>
|
||||
<small>ETH</small>
|
||||
</div>
|
||||
<ReactTooltip id={ labelId }>
|
||||
<FormattedMessage
|
||||
id='signer.mainDetails.tooltips.value1'
|
||||
defaultMessage='The value of the transaction.'
|
||||
/>
|
||||
<br />
|
||||
<strong>{ valueDisplayWei }</strong> <small>WEI</small>
|
||||
</ReactTooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
updateDisplayValues (value, totalValue) {
|
||||
this.setState({
|
||||
feeEth: tUtil.calcFeeInEth(totalValue, value),
|
||||
totalValueDisplay: tUtil.getTotalValueDisplay(totalValue),
|
||||
totalValueDisplayWei: tUtil.getTotalValueDisplayWei(totalValue),
|
||||
valueDisplay: tUtil.getValueDisplay(value),
|
||||
valueDisplayWei: tUtil.getValueDisplayWei(value)
|
||||
});
|
||||
}
|
||||
|
||||
toggleGasEditor = () => {
|
||||
this.props.gasStore.setEditing(true);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './transactionPending';
|
||||
@@ -1,27 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@import '../../_layout.css';
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
padding: 1.5em 1em 1.5em 0;
|
||||
|
||||
& > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import HardwareStore from '@parity/shared/mobx/hardwareStore';
|
||||
import { Button, GasPriceEditor } from '@parity/ui';
|
||||
|
||||
import TransactionMainDetails from '../TransactionMainDetails';
|
||||
import TransactionPendingForm from '../TransactionPendingForm';
|
||||
|
||||
import styles from './transactionPending.css';
|
||||
|
||||
import * as tUtil from '../util/transaction';
|
||||
|
||||
@observer
|
||||
class TransactionPending extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
accounts: PropTypes.object.isRequired,
|
||||
className: PropTypes.string,
|
||||
date: PropTypes.instanceOf(Date).isRequired,
|
||||
focus: PropTypes.bool,
|
||||
gasLimit: PropTypes.object,
|
||||
id: PropTypes.object.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
nonce: PropTypes.number,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onReject: PropTypes.func.isRequired,
|
||||
origin: PropTypes.any,
|
||||
signerStore: PropTypes.object.isRequired,
|
||||
transaction: PropTypes.shape({
|
||||
condition: PropTypes.object,
|
||||
data: PropTypes.string,
|
||||
from: PropTypes.string.isRequired,
|
||||
gas: PropTypes.object.isRequired,
|
||||
gasPrice: PropTypes.object.isRequired,
|
||||
to: PropTypes.string,
|
||||
value: PropTypes.object.isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
focus: false,
|
||||
origin: {
|
||||
type: 'unknown',
|
||||
details: ''
|
||||
}
|
||||
};
|
||||
|
||||
gasStore = new GasPriceEditor.Store(this.context.api, {
|
||||
condition: this.props.transaction.condition,
|
||||
gas: this.props.transaction.gas.toFixed(),
|
||||
gasLimit: this.props.gasLimit,
|
||||
gasPrice: this.props.transaction.gasPrice.toFixed()
|
||||
});
|
||||
|
||||
hardwareStore = HardwareStore.get(this.context.api);
|
||||
|
||||
componentWillMount () {
|
||||
const { signerStore, transaction } = this.props;
|
||||
const { from, gas, gasPrice, to, value } = transaction;
|
||||
|
||||
const fee = tUtil.getFee(gas, gasPrice); // BigNumber object
|
||||
const gasPriceEthmDisplay = tUtil.getEthmFromWeiDisplay(gasPrice);
|
||||
const gasToDisplay = tUtil.getGasDisplay(gas);
|
||||
const totalValue = tUtil.getTotalValue(fee, value);
|
||||
|
||||
this.setState({ gasPriceEthmDisplay, totalValue, gasToDisplay });
|
||||
this.gasStore.setEthValue(value);
|
||||
signerStore.fetchBalances([from, to]);
|
||||
}
|
||||
|
||||
render () {
|
||||
return this.gasStore.isEditing
|
||||
? this.renderTxEditor()
|
||||
: this.renderTransaction();
|
||||
}
|
||||
|
||||
renderTransaction () {
|
||||
const transaction = this.gasStore.overrideTransaction(this.props.transaction);
|
||||
|
||||
const { accounts, className, focus, id, isSending, netVersion, origin, signerStore } = this.props;
|
||||
const { totalValue } = this.state;
|
||||
const { balances, externalLink } = signerStore;
|
||||
const { from, value } = transaction;
|
||||
const fromBalance = balances[from];
|
||||
const account = accounts[from] || {};
|
||||
const disabled = account.hardware && !this.hardwareStore.isConnected(from);
|
||||
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
<TransactionMainDetails
|
||||
className={ styles.transactionDetails }
|
||||
disabled={ disabled }
|
||||
externalLink={ externalLink }
|
||||
from={ from }
|
||||
fromBalance={ fromBalance }
|
||||
gasStore={ this.gasStore }
|
||||
id={ id }
|
||||
netVersion={ netVersion }
|
||||
origin={ origin }
|
||||
totalValue={ totalValue }
|
||||
transaction={ transaction }
|
||||
value={ value }
|
||||
/>
|
||||
<TransactionPendingForm
|
||||
account={ account }
|
||||
address={ from }
|
||||
disabled={ disabled }
|
||||
focus={ focus }
|
||||
isSending={ isSending }
|
||||
netVersion={ netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ this.onReject }
|
||||
dataToSign={ { transaction } }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderTxEditor () {
|
||||
const { className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
<GasPriceEditor store={ this.gasStore }>
|
||||
<Button
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='signer.txPending.buttons.viewToggle'
|
||||
defaultMessage='view transaction'
|
||||
/>
|
||||
}
|
||||
onClick={ this.toggleGasEditor }
|
||||
/>
|
||||
</GasPriceEditor>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onConfirm = (data) => {
|
||||
const { id, transaction } = this.props;
|
||||
const { password, txSigned, wallet } = data;
|
||||
const { condition, gas, gasPrice } = this.gasStore.overrideTransaction(transaction);
|
||||
|
||||
const options = {
|
||||
gas,
|
||||
gasPrice,
|
||||
id,
|
||||
password,
|
||||
txSigned,
|
||||
wallet
|
||||
};
|
||||
|
||||
if (condition && (condition.block || condition.time)) {
|
||||
options.condition = condition;
|
||||
}
|
||||
|
||||
this.props.onConfirm(options);
|
||||
}
|
||||
|
||||
onReject = () => {
|
||||
this.props.onReject(this.props.id);
|
||||
}
|
||||
|
||||
toggleGasEditor = () => {
|
||||
this.gasStore.setEditing(false);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { accounts } = state.personal;
|
||||
|
||||
return {
|
||||
accounts
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(TransactionPending);
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './transactionPendingForm';
|
||||
@@ -1,44 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@import '../../_layout.css';
|
||||
|
||||
.container {
|
||||
box-sizing: border-box;
|
||||
padding: 1em 0 0 2em;
|
||||
flex: 0 0 $statusWidth;
|
||||
}
|
||||
|
||||
.rejectToggle {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
color: #00e;
|
||||
opacity: .7;
|
||||
transition: opacity .5s;
|
||||
}
|
||||
|
||||
.rejectToggle:hover {
|
||||
opacity: 1;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.rejectToggle svg {
|
||||
position: relative;
|
||||
width: 18px !important;
|
||||
height: 18px !important;
|
||||
top: 3px;
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { PrevIcon } from '@parity/ui/Icons';
|
||||
|
||||
import TransactionPendingFormConfirm from '../TransactionPendingFormConfirm';
|
||||
import TransactionPendingFormReject from '../TransactionPendingFormReject';
|
||||
|
||||
import styles from './transactionPendingForm.css';
|
||||
|
||||
export default class TransactionPendingForm extends Component {
|
||||
static propTypes = {
|
||||
account: PropTypes.object,
|
||||
address: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
focus: PropTypes.bool,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onReject: PropTypes.func.isRequired,
|
||||
dataToSign: PropTypes.oneOfType([
|
||||
PropTypes.shape({
|
||||
transaction: PropTypes.object.isRequired
|
||||
}),
|
||||
PropTypes.shape({
|
||||
data: PropTypes.string.isRequired
|
||||
}),
|
||||
PropTypes.shape({
|
||||
decrypt: PropTypes.string.isRequired
|
||||
})
|
||||
]).isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
account: {},
|
||||
focus: false
|
||||
};
|
||||
|
||||
state = {
|
||||
isRejectOpen: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const { className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
{ this.renderForm() }
|
||||
{ this.renderRejectToggle() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderForm () {
|
||||
const { account, address, disabled, focus, isSending, netVersion, onConfirm, onReject, dataToSign } = this.props;
|
||||
|
||||
if (this.state.isRejectOpen) {
|
||||
return (
|
||||
<TransactionPendingFormReject onReject={ onReject } />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TransactionPendingFormConfirm
|
||||
address={ address }
|
||||
account={ account }
|
||||
disabled={ disabled }
|
||||
focus={ focus }
|
||||
netVersion={ netVersion }
|
||||
isSending={ isSending }
|
||||
onConfirm={ onConfirm }
|
||||
dataToSign={ dataToSign }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderRejectToggle () {
|
||||
const { isRejectOpen } = this.state;
|
||||
let html;
|
||||
|
||||
if (!isRejectOpen) {
|
||||
html = (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signer.txPendingForm.reject'
|
||||
defaultMessage='reject request'
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
html = (
|
||||
<span>
|
||||
<PrevIcon />
|
||||
<FormattedMessage
|
||||
id='signer.txPendingForm.changedMind'
|
||||
defaultMessage="I've changed my mind"
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
className={ styles.rejectToggle }
|
||||
onClick={ this.onToggleReject }
|
||||
>
|
||||
{ html }
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
onToggleReject = () => {
|
||||
const { isRejectOpen } = this.state;
|
||||
|
||||
this.setState({
|
||||
isRejectOpen: !isRejectOpen
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './transactionPendingFormConfirm';
|
||||
@@ -1,48 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.confirmForm {
|
||||
margin-top: -2em;
|
||||
}
|
||||
|
||||
.confirmButton {
|
||||
display: block !important;
|
||||
margin-bottom: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.signerIcon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.passwordHint {
|
||||
font-size: 0.75em;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
.passwordHint span {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.fileInput input {
|
||||
top: 22px;
|
||||
}
|
||||
|
||||
.qr {
|
||||
margin-bottom: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -1,580 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import keycode from 'keycode';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
import { generateTxQr, generateDecryptQr, generateDataQr } from '@parity/shared/util/qrscan';
|
||||
import { Button, Form, Input, IdentityIcon, QrCode, QrScan } from '@parity/ui';
|
||||
|
||||
import styles from './transactionPendingFormConfirm.css';
|
||||
|
||||
const QR_VISIBLE = 1;
|
||||
const QR_SCAN = 2;
|
||||
const QR_COMPLETED = 3;
|
||||
|
||||
export default class TransactionPendingFormConfirm extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
account: PropTypes.object,
|
||||
address: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
focus: PropTypes.bool,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
dataToSign: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
account: {},
|
||||
focus: false
|
||||
};
|
||||
|
||||
id = Math.random(); // for tooltip
|
||||
|
||||
state = {
|
||||
password: '',
|
||||
qrState: QR_VISIBLE,
|
||||
qr: {},
|
||||
wallet: null,
|
||||
walletError: null
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.readNonce();
|
||||
this.subscribeNonce();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.unsubscribeNonce();
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (!this.props.focus && nextProps.focus) {
|
||||
this.focus(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
focus (props = this.props) {
|
||||
if (props.focus) {
|
||||
const textNode = ReactDOM.findDOMNode(this.refs.input);
|
||||
|
||||
if (!textNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const inputNode = textNode.querySelector('input');
|
||||
|
||||
inputNode && inputNode.focus();
|
||||
}
|
||||
}
|
||||
|
||||
getPasswordHint () {
|
||||
const { account } = this.props;
|
||||
const accountHint = account.meta && account.meta.passwordHint;
|
||||
|
||||
if (accountHint) {
|
||||
return accountHint;
|
||||
}
|
||||
|
||||
const { wallet } = this.state;
|
||||
const walletHint = wallet && wallet.meta && wallet.meta.passwordHint;
|
||||
|
||||
return walletHint || null;
|
||||
}
|
||||
|
||||
// TODO: Now that we have 3 types, it would make sense splitting each into their own
|
||||
// sub-module and having the consistent bits combined (e.g. i18n, layouts)
|
||||
render () {
|
||||
const { account, address, disabled, isSending } = this.props;
|
||||
const { wallet, walletError } = this.state;
|
||||
const isAccount = account.external || account.hardware || account.uuid;
|
||||
const isWalletOk = isAccount || (walletError === null && wallet !== null);
|
||||
const confirmText = this.renderConfirmButton();
|
||||
const confirmButton = confirmText
|
||||
? (
|
||||
<div
|
||||
data-effect='solid'
|
||||
data-for={ `transactionConfirmForm${this.id}` }
|
||||
data-place='bottom'
|
||||
data-tip
|
||||
>
|
||||
<Button
|
||||
className={ styles.confirmButton }
|
||||
disabled={ disabled || isSending || !isWalletOk }
|
||||
fullWidth
|
||||
icon={
|
||||
<IdentityIcon
|
||||
address={ address }
|
||||
button
|
||||
className={ styles.signerIcon }
|
||||
/>
|
||||
}
|
||||
label={ confirmText }
|
||||
onClick={ this.onConfirm }
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className={ styles.confirmForm }>
|
||||
<Form>
|
||||
{ this.renderKeyInput() }
|
||||
{ this.renderQrCode() }
|
||||
{ this.renderQrScanner() }
|
||||
{ this.renderPassword() }
|
||||
{ this.renderHint() }
|
||||
{ confirmButton }
|
||||
{ this.renderTooltip() }
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderConfirmButton () {
|
||||
const { account, isSending } = this.props;
|
||||
const { qrState } = this.state;
|
||||
|
||||
if (account.external) {
|
||||
switch (qrState) {
|
||||
case QR_VISIBLE:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.buttons.scanSigned'
|
||||
defaultMessage='Scan Signed QR'
|
||||
/>
|
||||
);
|
||||
|
||||
case QR_SCAN:
|
||||
case QR_COMPLETED:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return isSending
|
||||
? (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.buttons.confirmBusy'
|
||||
defaultMessage='Confirming...'
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.buttons.confirmRequest'
|
||||
defaultMessage='Confirm Request'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderPassword () {
|
||||
const { account } = this.props;
|
||||
const { password } = this.state;
|
||||
|
||||
if (account.hardware || account.external) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isAccount = account.uuid;
|
||||
|
||||
return (
|
||||
<Input
|
||||
hint={
|
||||
isAccount
|
||||
? (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.password.unlock.hint'
|
||||
defaultMessage='unlock the account'
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.password.decrypt.hint'
|
||||
defaultMessage='decrypt the key'
|
||||
/>
|
||||
)
|
||||
}
|
||||
label={
|
||||
isAccount
|
||||
? (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.password.unlock.label'
|
||||
defaultMessage='Account Password'
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.password.decrypt.label'
|
||||
defaultMessage='Key Password'
|
||||
/>
|
||||
)
|
||||
}
|
||||
onChange={ this.onModifyPassword }
|
||||
onKeyDown={ this.onKeyDown }
|
||||
ref='input'
|
||||
type='password'
|
||||
value={ password }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderHint () {
|
||||
const { account, disabled, isSending } = this.props;
|
||||
const { qrState } = this.state;
|
||||
|
||||
if (account.external) {
|
||||
switch (qrState) {
|
||||
case QR_VISIBLE:
|
||||
return (
|
||||
<div className={ styles.passwordHint }>
|
||||
<FormattedMessage
|
||||
id='signer.sending.external.scanTx'
|
||||
defaultMessage='Please scan the transaction QR on your external device'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
case QR_SCAN:
|
||||
return (
|
||||
<div className={ styles.passwordHint }>
|
||||
<FormattedMessage
|
||||
id='signer.sending.external.scanSigned'
|
||||
defaultMessage='Scan the QR code of the signed transaction from your external device'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
case QR_COMPLETED:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (account.hardware) {
|
||||
if (isSending) {
|
||||
return (
|
||||
<div className={ styles.passwordHint }>
|
||||
<FormattedMessage
|
||||
id='signer.sending.hardware.confirm'
|
||||
defaultMessage='Please confirm the transaction on your attached hardware device'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (disabled) {
|
||||
return (
|
||||
<div className={ styles.passwordHint }>
|
||||
<FormattedMessage
|
||||
id='signer.sending.hardware.connect'
|
||||
defaultMessage='Please attach your hardware device before confirming the transaction'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const passwordHint = this.getPasswordHint();
|
||||
|
||||
if (!passwordHint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.passwordHint }>
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.passwordHint'
|
||||
defaultMessage='(hint) {passwordHint}'
|
||||
values={ {
|
||||
passwordHint
|
||||
} }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Split into sub-scomponent
|
||||
renderQrCode () {
|
||||
const { account } = this.props;
|
||||
const { qrState, qr } = this.state;
|
||||
|
||||
if (!account.external || qrState !== QR_VISIBLE || !qr.value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QrCode
|
||||
className={ styles.qr }
|
||||
value={ qr.value }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Split into sub-scomponent
|
||||
renderQrScanner () {
|
||||
const { account } = this.props;
|
||||
const { qrState } = this.state;
|
||||
|
||||
if (!account.external || qrState !== QR_SCAN) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QrScan
|
||||
className={ styles.camera }
|
||||
onScan={ this.onScan }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderKeyInput () {
|
||||
const { account } = this.props;
|
||||
const { walletError } = this.state;
|
||||
|
||||
if (account.uuid || account.wallet || account.hardware || account.external) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
className={ styles.fileInput }
|
||||
error={ walletError }
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.selectKey.hint'
|
||||
defaultMessage='The keyfile to use for this account'
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.selectKey.label'
|
||||
defaultMessage='Select Local Key'
|
||||
/>
|
||||
}
|
||||
onChange={ this.onKeySelect }
|
||||
type='file'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderTooltip () {
|
||||
const { account } = this.props;
|
||||
|
||||
if (this.state.password.length || account.hardware || account.external) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactTooltip id={ `transactionConfirmForm${this.id}` }>
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.tooltips.password'
|
||||
defaultMessage='Please provide a password for this account'
|
||||
/>
|
||||
</ReactTooltip>
|
||||
);
|
||||
}
|
||||
|
||||
onScan = (signature) => {
|
||||
const { chainId, rlp, tx, data, decrypt } = this.state.qr;
|
||||
|
||||
if (!signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (signature && signature.substr(0, 2) !== '0x') {
|
||||
signature = `0x${signature}`;
|
||||
}
|
||||
|
||||
this.setState({ qrState: QR_COMPLETED });
|
||||
|
||||
if (tx) {
|
||||
this.props.onConfirm({
|
||||
txSigned: {
|
||||
chainId,
|
||||
rlp,
|
||||
signature,
|
||||
tx
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (decrypt) {
|
||||
this.props.onConfirm({
|
||||
decrypted: {
|
||||
decrypt,
|
||||
msg: signature
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onConfirm({
|
||||
dataSigned: {
|
||||
data,
|
||||
signature
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onKeySelect = (event) => {
|
||||
// Check that file have been selected
|
||||
if (event.target.files.length === 0) {
|
||||
return this.setState({
|
||||
wallet: null,
|
||||
walletError: null
|
||||
});
|
||||
}
|
||||
|
||||
const fileReader = new FileReader();
|
||||
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
const wallet = JSON.parse(e.target.result);
|
||||
|
||||
try {
|
||||
if (wallet && typeof wallet.meta === 'string') {
|
||||
wallet.meta = JSON.parse(wallet.meta);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
this.setState({
|
||||
wallet,
|
||||
walletError: null
|
||||
});
|
||||
} catch (error) {
|
||||
this.setState({
|
||||
wallet: null,
|
||||
walletError: (
|
||||
<FormattedMessage
|
||||
id='signer.txPendingConfirm.errors.invalidWallet'
|
||||
defaultMessage='Given wallet file is invalid.'
|
||||
/>
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fileReader.readAsText(event.target.files[0]);
|
||||
}
|
||||
|
||||
onModifyPassword = (event) => {
|
||||
const password = event.target.value;
|
||||
|
||||
this.setState({
|
||||
password
|
||||
});
|
||||
}
|
||||
|
||||
onConfirm = () => {
|
||||
const { account } = this.props;
|
||||
const { password, qrState, wallet } = this.state;
|
||||
|
||||
if (account.external && qrState === QR_VISIBLE) {
|
||||
return this.setState({ qrState: QR_SCAN });
|
||||
}
|
||||
|
||||
this.props.onConfirm({
|
||||
password,
|
||||
wallet
|
||||
});
|
||||
}
|
||||
|
||||
generateQr = () => {
|
||||
const { api } = this.context;
|
||||
const { netVersion, dataToSign } = this.props;
|
||||
const { transaction, data, decrypt } = dataToSign;
|
||||
const setState = qr => {
|
||||
this.setState({ qr });
|
||||
};
|
||||
|
||||
if (transaction) {
|
||||
generateTxQr(api, netVersion, transaction).then(setState);
|
||||
return;
|
||||
}
|
||||
|
||||
if (decrypt) {
|
||||
generateDecryptQr(decrypt).then(setState);
|
||||
return;
|
||||
}
|
||||
|
||||
generateDataQr(data).then(setState);
|
||||
}
|
||||
|
||||
onKeyDown = (event) => {
|
||||
const codeName = keycode(event);
|
||||
|
||||
if (codeName !== 'enter') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onConfirm();
|
||||
}
|
||||
|
||||
// FIXME: Sadly the API subscription channels currently does not allow for specific values,
|
||||
// rather it can only do general queries where parameters are not specified. Hence we are
|
||||
// polling for the nonce here. Since we are moving to node-based subscriptions on the API layer,
|
||||
// this can be optimised when the subscription mechanism is reworked to conform.
|
||||
subscribeNonce () {
|
||||
const nonceTimerId = setInterval(this.readNonce, 1000);
|
||||
|
||||
this.setState({ nonceTimerId });
|
||||
}
|
||||
|
||||
unsubscribeNonce () {
|
||||
const { nonceTimerId } = this.state;
|
||||
|
||||
if (!nonceTimerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval(nonceTimerId);
|
||||
}
|
||||
|
||||
readNonce = () => {
|
||||
const { api } = this.context;
|
||||
const { account, dataToSign } = this.props;
|
||||
const { qr } = this.state;
|
||||
|
||||
if ((dataToSign.data || dataToSign.decrypt) && qr && !qr.value) {
|
||||
this.generateQr();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!account || !account.external || !api.transport.isConnected || !dataToSign.transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
return api.parity
|
||||
.nextNonce(account.address)
|
||||
.then((newNonce) => {
|
||||
const { nonce } = this.state.qr;
|
||||
|
||||
if (!nonce || !newNonce.eq(nonce)) {
|
||||
this.generateQr();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import TransactionPendingFormConfirm from './';
|
||||
|
||||
const ADDR_NORMAL = '0x0123456789012345678901234567890123456789';
|
||||
const ADDR_WALLET = '0x1234567890123456789012345678901234567890';
|
||||
const ADDR_HARDWARE = '0x2345678901234567890123456789012345678901';
|
||||
const ADDR_SIGN = '0x3456789012345678901234567890123456789012';
|
||||
const ACCOUNTS = {
|
||||
[ADDR_NORMAL]: {
|
||||
address: ADDR_NORMAL,
|
||||
uuid: ADDR_NORMAL
|
||||
},
|
||||
[ADDR_WALLET]: {
|
||||
address: ADDR_WALLET,
|
||||
wallet: true
|
||||
},
|
||||
[ADDR_HARDWARE]: {
|
||||
address: ADDR_HARDWARE,
|
||||
hardware: true
|
||||
}
|
||||
};
|
||||
|
||||
let component;
|
||||
let instance;
|
||||
let onConfirm;
|
||||
|
||||
function render (address) {
|
||||
onConfirm = sinon.stub();
|
||||
|
||||
component = shallow(
|
||||
<TransactionPendingFormConfirm
|
||||
account={ ACCOUNTS[address] }
|
||||
address={ address }
|
||||
onConfirm={ onConfirm }
|
||||
isSending={ false }
|
||||
dataToSign={ {} }
|
||||
/>
|
||||
);
|
||||
instance = component.instance();
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('views/Signer/TransactionPendingFormConfirm', () => {
|
||||
describe('normal accounts', () => {
|
||||
beforeEach(() => {
|
||||
render(ADDR_NORMAL);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('does not render the key input', () => {
|
||||
expect(instance.renderKeyInput()).to.be.null;
|
||||
});
|
||||
|
||||
it('renders the password', () => {
|
||||
expect(instance.renderPassword()).not.to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('hardware accounts', () => {
|
||||
beforeEach(() => {
|
||||
render(ADDR_HARDWARE);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('does not render the key input', () => {
|
||||
expect(instance.renderKeyInput()).to.be.null;
|
||||
});
|
||||
|
||||
it('does not render the password', () => {
|
||||
expect(instance.renderPassword()).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('wallet accounts', () => {
|
||||
beforeEach(() => {
|
||||
render(ADDR_WALLET);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('does not render the key input', () => {
|
||||
expect(instance.renderKeyInput()).to.be.null;
|
||||
});
|
||||
|
||||
it('renders the password', () => {
|
||||
expect(instance.renderPassword()).not.to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('signing accounts', () => {
|
||||
beforeEach(() => {
|
||||
render(ADDR_SIGN);
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
it('renders the key input', () => {
|
||||
expect(instance.renderKeyInput()).not.to.be.null;
|
||||
});
|
||||
|
||||
it('renders the password', () => {
|
||||
expect(instance.renderPassword()).not.to.be.null;
|
||||
});
|
||||
|
||||
it('renders the hint', () => {
|
||||
expect(instance.renderHint()).to.be.null;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './transactionPendingFormReject';
|
||||
@@ -1,26 +0,0 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* the rejection button itself, once .reject has been pressed */
|
||||
.rejectButton {
|
||||
display: block !important;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.rejectText {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Button } from '@parity/ui';
|
||||
|
||||
import styles from './transactionPendingFormReject.css';
|
||||
|
||||
export default class TransactionPendingFormReject extends Component {
|
||||
static propTypes = {
|
||||
onReject: PropTypes.func.isRequired,
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
render () {
|
||||
const { onReject } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={ styles.rejectText }>
|
||||
<FormattedMessage
|
||||
id='signer.txPendingReject.info'
|
||||
defaultMessage='Are you sure you want to reject request?'
|
||||
/>
|
||||
<br />
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='signer.txPendingReject.undone'
|
||||
defaultMessage='This cannot be undone'
|
||||
/>
|
||||
</strong>
|
||||
</div>
|
||||
<Button
|
||||
onClick={ onReject }
|
||||
className={ styles.rejectButton }
|
||||
fullWidth
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='signer.txPendingReject.buttons.reject'
|
||||
defaultMessage='Reject Request'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './txHashLink';
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { txLink } from '@parity/etherscan/links';
|
||||
|
||||
export default class TxHashLink extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
txHash: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { children, className, netVersion, txHash } = this.props;
|
||||
|
||||
return (
|
||||
<a
|
||||
className={ className }
|
||||
href={ txLink(txHash, false, netVersion) }
|
||||
target='_blank'
|
||||
>
|
||||
{ children || txHash }
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const isLogging = process.env.LOGGING;
|
||||
|
||||
export default logger();
|
||||
|
||||
function logger () {
|
||||
return isLogging ? devLogger() : prodLogger();
|
||||
}
|
||||
|
||||
function prodLogger () {
|
||||
return {
|
||||
log: noop,
|
||||
info: noop,
|
||||
error: noop,
|
||||
warn: noop
|
||||
};
|
||||
}
|
||||
|
||||
function devLogger () {
|
||||
return console;
|
||||
}
|
||||
|
||||
function noop () {}
|
||||
21
js/src/Signer/components/util/react.js
vendored
21
js/src/Signer/components/util/react.js
vendored
@@ -1,21 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { isValidElement } from 'react';
|
||||
|
||||
export function isReactComponent (componentOrElem) {
|
||||
return isValidElement(componentOrElem) && typeof componentOrElem.type === 'function';
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
const WEI_TO_ETH_MULTIPLIER = 0.000000000000000001;
|
||||
const WEI_TO_SZABU_MULTIPLIER = 0.000000000001;
|
||||
|
||||
export const getShortData = _getShortData;
|
||||
// calculations
|
||||
export const getFee = _getFee;
|
||||
export const calcFeeInEth = _calcFeeInEth;
|
||||
export const getTotalValue = _getTotalValue;
|
||||
// displays
|
||||
export const getSzaboFromWeiDisplay = _getSzaboFromWeiDisplay;
|
||||
export const getValueDisplay = _getValueDisplay;
|
||||
export const getValueDisplayWei = _getValueDisplayWei;
|
||||
export const getTotalValueDisplay = _getTotalValueDisplay;
|
||||
export const getTotalValueDisplayWei = _getTotalValueDisplayWei;
|
||||
export const getEthmFromWeiDisplay = _getEthmFromWeiDisplay;
|
||||
export const getGasDisplay = _getGasDisplay;
|
||||
|
||||
function _getShortData (data) {
|
||||
if (data.length <= 3) {
|
||||
return data;
|
||||
}
|
||||
return data.substr(0, 3) + '...';
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {hex string} gas
|
||||
* @param {wei hex string} gasPrice
|
||||
* @return {BigNumber} fee in wei
|
||||
*/
|
||||
function _getFee (gas, gasPrice) {
|
||||
gas = new BigNumber(gas);
|
||||
gasPrice = new BigNumber(gasPrice);
|
||||
return gasPrice.times(gas);
|
||||
}
|
||||
|
||||
function _calcFeeInEth (totalValue, value) {
|
||||
let fee = new BigNumber(totalValue).sub(new BigNumber(value));
|
||||
|
||||
return fee.times(WEI_TO_ETH_MULTIPLIER).toFormat(7);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {wei BigNumber} fee
|
||||
* @param {wei hex string} value
|
||||
* @return {BigNumber} total value in wei
|
||||
*/
|
||||
function _getTotalValue (fee, value) {
|
||||
value = new BigNumber(value);
|
||||
return fee.plus(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {wei hex string} gasPrice
|
||||
* @return {string} szabo gas price with unit [szabo] i.e. 21,423 [szabo]
|
||||
*/
|
||||
function _getSzaboFromWeiDisplay (gasPrice) {
|
||||
gasPrice = new BigNumber(gasPrice);
|
||||
return gasPrice.times(WEI_TO_SZABU_MULTIPLIER).toPrecision(5);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {wei hex string} value
|
||||
* @return {string} value in WEI nicely formatted
|
||||
*/
|
||||
function _getValueDisplay (value) {
|
||||
value = new BigNumber(value);
|
||||
return value.times(WEI_TO_ETH_MULTIPLIER).toFormat(5);
|
||||
}
|
||||
|
||||
function _getValueDisplayWei (value) {
|
||||
value = new BigNumber(value);
|
||||
return value.toFormat(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {wei hex string} totalValue
|
||||
* @return {string} total value (including fee) with units i.e. 1.32 [eth]
|
||||
*/
|
||||
function _getTotalValueDisplay (totalValue) {
|
||||
totalValue = new BigNumber(totalValue);
|
||||
return totalValue.times(WEI_TO_ETH_MULTIPLIER).toFormat(5);
|
||||
}
|
||||
|
||||
function _getTotalValueDisplayWei (totalValue) {
|
||||
totalValue = new BigNumber(totalValue);
|
||||
return totalValue.toFormat(0);
|
||||
}
|
||||
|
||||
function _getEthmFromWeiDisplay (weiHexString) {
|
||||
const value = new BigNumber(weiHexString);
|
||||
|
||||
return value.times(WEI_TO_ETH_MULTIPLIER).times(1e7).toFixed(5);
|
||||
}
|
||||
|
||||
function _getGasDisplay (gas) {
|
||||
return new BigNumber(gas).times(1e-7).toFormat(4);
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { getShortData, getFee, getTotalValue } from './transaction';
|
||||
|
||||
describe('Signer/components/util/transaction', () => {
|
||||
describe('getEstimatedMiningTime', () => {
|
||||
it('should return estimated mining time', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getShortData', () => {
|
||||
it('should return short data', () => {
|
||||
// given
|
||||
const data = '0xh87dY78';
|
||||
|
||||
// when
|
||||
const res = getShortData(data);
|
||||
|
||||
// then
|
||||
expect(res).to.equal('0xh...');
|
||||
});
|
||||
|
||||
it('should return data as is', () => {
|
||||
// given
|
||||
const data = '0x0';
|
||||
|
||||
// when
|
||||
const shortData = getShortData(data);
|
||||
|
||||
// then
|
||||
expect(shortData).to.equal('0x0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFee', () => {
|
||||
it('should return wei BigNumber object equals to gas * gasPrice', () => {
|
||||
// given
|
||||
const gas = '0x76c0'; // 30400
|
||||
const gasPrice = '0x9184e72a000'; // 10000000000000 wei
|
||||
|
||||
// when
|
||||
const fee = getFee(gas, gasPrice);
|
||||
|
||||
// then
|
||||
expect(fee).to.be.an.instanceOf(BigNumber);
|
||||
expect(fee.toString()).to.be.equal('304000000000000000'); // converting to string due to https://github.com/MikeMcl/bignumber.js/issues/11
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTotalValue', () => {
|
||||
it('should return wei BigNumber totalValue equals to value + fee', () => {
|
||||
// given
|
||||
const fee = new BigNumber(304000000000000000); // wei
|
||||
const value = '0x9184e72a'; // 2441406250 wei
|
||||
|
||||
// when
|
||||
const totalValue = getTotalValue(fee, value);
|
||||
|
||||
// then
|
||||
expect(totalValue).to.be.an.instanceOf(BigNumber);
|
||||
expect(totalValue.toString()).to.be.equal('304000002441406250'); // converting to string due to https://github.com/MikeMcl/bignumber.js/issues/11
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,107 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { isEqual } from 'lodash';
|
||||
import { action, observable } from 'mobx';
|
||||
|
||||
export default class SignerStore {
|
||||
@observable balances = {};
|
||||
@observable localHashes = [];
|
||||
|
||||
externalLink = '';
|
||||
|
||||
constructor (api, withLocalTransactions = false, externalLink = '') {
|
||||
this._api = api;
|
||||
this._timeoutId = 0;
|
||||
this.externalLink = externalLink;
|
||||
|
||||
if (withLocalTransactions) {
|
||||
this.fetchLocalTransactions();
|
||||
}
|
||||
}
|
||||
|
||||
@action setBalance = (address, balance) => {
|
||||
this.setBalances({ [address]: balance });
|
||||
}
|
||||
|
||||
@action setBalances = (balances) => {
|
||||
this.balances = Object.assign({}, this.balances, balances);
|
||||
}
|
||||
|
||||
@action setLocalHashes = (localHashes = []) => {
|
||||
// Use slice to make sure they are both Arrays (MobX uses Objects for Observable Arrays)
|
||||
if (!isEqual(localHashes.slice(), this.localHashes.slice())) {
|
||||
this.localHashes = localHashes;
|
||||
}
|
||||
}
|
||||
|
||||
@action unsubscribe () {
|
||||
if (this._timeoutId) {
|
||||
clearTimeout(this._timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
fetchBalance (address) {
|
||||
this._api.eth
|
||||
.getBalance(address)
|
||||
.then((balance) => {
|
||||
this.setBalance(address, balance);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn('Store:fetchBalance', error);
|
||||
});
|
||||
}
|
||||
|
||||
fetchBalances (_addresses) {
|
||||
const addresses = _addresses.filter((address) => address) || [];
|
||||
|
||||
if (!addresses.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
Promise
|
||||
.all(addresses.map((address) => this._api.eth.getBalance(address)))
|
||||
.then((_balances) => {
|
||||
this.setBalances(
|
||||
addresses.reduce((balances, address, index) => {
|
||||
balances[address] = _balances[index];
|
||||
return balances;
|
||||
}, {})
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn('Store:fetchBalances', error);
|
||||
});
|
||||
}
|
||||
|
||||
fetchLocalTransactions = () => {
|
||||
const nextTimeout = () => {
|
||||
this._timeoutId = setTimeout(this.fetchLocalTransactions, 1500);
|
||||
};
|
||||
|
||||
this._api.parity
|
||||
.localTransactions()
|
||||
.then((localTransactions) => {
|
||||
const keys = Object
|
||||
.keys(localTransactions)
|
||||
.filter((key) => localTransactions[key].status !== 'canceled');
|
||||
|
||||
this.setLocalHashes(keys);
|
||||
})
|
||||
.then(() => nextTimeout())
|
||||
.catch(() => nextTimeout());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user