Support external eth_sign (#5481)
* Display a QR for eth_sign requests. * Support raw confirmation of eth_sign * Fix ethkey issue on nightly. * Fixing test. * Fixing test.
This commit is contained in:
@@ -87,14 +87,20 @@ export default class SignerMiddleware {
|
||||
return this._hwstore.signLedger(transaction);
|
||||
})
|
||||
.then((rawTx) => {
|
||||
return this.confirmRawTransaction(store, id, rawTx);
|
||||
return this.confirmRawRequest(store, id, rawTx);
|
||||
});
|
||||
}
|
||||
|
||||
confirmRawTransaction (store, id, rawTx) {
|
||||
confirmRawRequest (store, id, rawData) {
|
||||
const handlePromise = this._createConfirmPromiseHandler(store, id);
|
||||
|
||||
return handlePromise(this._api.signer.confirmRequestRaw(id, rawTx));
|
||||
return handlePromise(this._api.signer.confirmRequestRaw(id, rawData));
|
||||
}
|
||||
|
||||
confirmSignedData (store, id, dataSigned) {
|
||||
const { signature } = dataSigned;
|
||||
|
||||
return this.confirmRawRequest(store, id, signature);
|
||||
}
|
||||
|
||||
confirmSignedTransaction (store, id, txSigned) {
|
||||
@@ -102,7 +108,7 @@ export default class SignerMiddleware {
|
||||
const { signature, tx } = txSigned;
|
||||
const { rlp } = createSignedTx(netVersion, signature, tx);
|
||||
|
||||
return this.confirmRawTransaction(store, id, rlp);
|
||||
return this.confirmRawRequest(store, id, rlp);
|
||||
}
|
||||
|
||||
confirmWalletTransaction (store, id, transaction, wallet, password) {
|
||||
@@ -138,7 +144,7 @@ export default class SignerMiddleware {
|
||||
return signer.signTransaction(txData);
|
||||
})
|
||||
.then((rawTx) => {
|
||||
return this.confirmRawTransaction(store, id, rawTx);
|
||||
return this.confirmRawRequest(store, id, rawTx);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error.message);
|
||||
@@ -147,7 +153,7 @@ export default class SignerMiddleware {
|
||||
}
|
||||
|
||||
onConfirmStart = (store, action) => {
|
||||
const { condition, gas = 0, gasPrice = 0, id, password, payload, txSigned, wallet } = action.payload;
|
||||
const { condition, gas = 0, gasPrice = 0, id, password, payload, txSigned, dataSigned, wallet } = action.payload;
|
||||
const handlePromise = this._createConfirmPromiseHandler(store, id);
|
||||
const transaction = payload.sendTransaction || payload.signTransaction;
|
||||
|
||||
@@ -170,6 +176,11 @@ export default class SignerMiddleware {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [ToDr] Support eth_sign for external wallet (wallet && !transction)
|
||||
if (dataSigned) {
|
||||
return this.confirmSignedData(store, id, dataSigned);
|
||||
}
|
||||
|
||||
return handlePromise(this._api.signer.confirmRequest(id, { gas, gasPrice, condition }, password));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ import Transaction from 'ethereumjs-tx';
|
||||
import { inAddress, inHex, inNumber10 } from '~/api/format/input';
|
||||
import { sha3 } from '~/api/util/sha3';
|
||||
|
||||
export function createUnsignedTx (api, netVersion, gasStore, transaction) {
|
||||
const { data, from, gas, gasPrice, to, value } = gasStore.overrideTransaction(transaction);
|
||||
export function createUnsignedTx (api, netVersion, transaction) {
|
||||
const { data, from, gas, gasPrice, to, value } = transaction;
|
||||
|
||||
return api.parity
|
||||
.nextNonce(from)
|
||||
@@ -111,8 +111,18 @@ export function generateQr (from, tx, hash, rlp) {
|
||||
});
|
||||
}
|
||||
|
||||
export function generateTxQr (api, netVersion, gasStore, transaction) {
|
||||
return createUnsignedTx(api, netVersion, gasStore, transaction)
|
||||
export function generateDataQr (data) {
|
||||
return Promise.resolve({
|
||||
data,
|
||||
value: JSON.stringify({
|
||||
action: 'signData',
|
||||
data
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function generateTxQr (api, netVersion, transaction) {
|
||||
return createUnsignedTx(api, netVersion, transaction)
|
||||
.then((qr) => {
|
||||
qr.value = generateQr(transaction.from, qr.tx, qr.hash, qr.rlp);
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ export default class RequestOrigin extends Component {
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signer.requestOrigin.rpc'
|
||||
defaultMessage='via RPC {rpc}'
|
||||
defaultMessage='via RPC {url}'
|
||||
values={ {
|
||||
url: (
|
||||
<span className={ styles.url }>
|
||||
|
||||
@@ -19,6 +19,8 @@ import React, { Component, PropTypes } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import HardwareStore from '~/mobx/hardwareStore';
|
||||
|
||||
import Account from '../Account';
|
||||
import TransactionPendingForm from '../TransactionPendingForm';
|
||||
import RequestOrigin from '../RequestOrigin';
|
||||
@@ -68,6 +70,8 @@ class SignRequest extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
hardwareStore = HardwareStore.get(this.context.api);
|
||||
|
||||
componentWillMount () {
|
||||
const { address, signerStore } = this.props;
|
||||
|
||||
@@ -155,8 +159,9 @@ class SignRequest extends Component {
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { accounts, address, focus, isFinished, status } = this.props;
|
||||
const account = accounts[address];
|
||||
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') {
|
||||
@@ -188,21 +193,23 @@ class SignRequest extends Component {
|
||||
<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 } = data;
|
||||
const { password, dataSigned, wallet } = data;
|
||||
|
||||
this.props.onConfirm({ id, password });
|
||||
this.props.onConfirm({ id, password, dataSigned, wallet });
|
||||
}
|
||||
|
||||
onReject = () => {
|
||||
|
||||
@@ -98,7 +98,9 @@ class TransactionPending extends Component {
|
||||
}
|
||||
|
||||
renderTransaction () {
|
||||
const { accounts, className, focus, id, isSending, netVersion, origin, signerStore, transaction } = this.props;
|
||||
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;
|
||||
@@ -127,12 +129,11 @@ class TransactionPending extends Component {
|
||||
address={ from }
|
||||
disabled={ disabled }
|
||||
focus={ focus }
|
||||
gasStore={ this.gasStore }
|
||||
isSending={ isSending }
|
||||
netVersion={ netVersion }
|
||||
onConfirm={ this.onConfirm }
|
||||
onReject={ this.onReject }
|
||||
transaction={ transaction }
|
||||
dataToSign={ { transaction } }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -22,7 +22,7 @@ import { FormattedMessage } from 'react-intl';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
import { Form, Input, IdentityIcon, QrCode, QrScan } from '~/ui';
|
||||
import { generateTxQr } from '~/util/qrscan';
|
||||
import { generateTxQr, generateDataQr } from '~/util/qrscan';
|
||||
|
||||
import styles from './transactionPendingFormConfirm.css';
|
||||
|
||||
@@ -40,11 +40,10 @@ export default class TransactionPendingFormConfirm extends Component {
|
||||
address: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
focus: PropTypes.bool,
|
||||
gasStore: PropTypes.object.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
transaction: PropTypes.object.isRequired
|
||||
dataToSign: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@@ -406,7 +405,7 @@ export default class TransactionPendingFormConfirm extends Component {
|
||||
}
|
||||
|
||||
onScanTx = (signature) => {
|
||||
const { chainId, rlp, tx } = this.state.qr;
|
||||
const { chainId, rlp, tx, data } = this.state.qr;
|
||||
|
||||
if (signature && signature.substr(0, 2) !== '0x') {
|
||||
signature = `0x${signature}`;
|
||||
@@ -414,12 +413,22 @@ export default class TransactionPendingFormConfirm extends Component {
|
||||
|
||||
this.setState({ qrState: QR_COMPLETED });
|
||||
|
||||
if (tx) {
|
||||
this.props.onConfirm({
|
||||
txSigned: {
|
||||
chainId,
|
||||
rlp,
|
||||
signature,
|
||||
tx
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onConfirm({
|
||||
txSigned: {
|
||||
chainId,
|
||||
rlp,
|
||||
signature,
|
||||
tx
|
||||
dataSigned: {
|
||||
data,
|
||||
signature
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -487,13 +496,20 @@ export default class TransactionPendingFormConfirm extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
generateTxQr = () => {
|
||||
generateQr = () => {
|
||||
const { api } = this.context;
|
||||
const { netVersion, gasStore, transaction } = this.props;
|
||||
|
||||
generateTxQr(api, netVersion, gasStore, transaction).then((qr) => {
|
||||
const { netVersion, dataToSign } = this.props;
|
||||
const { transaction, data } = dataToSign;
|
||||
const setState = qr => {
|
||||
this.setState({ qr });
|
||||
});
|
||||
};
|
||||
|
||||
if (transaction) {
|
||||
generateTxQr(api, netVersion, transaction).then(setState);
|
||||
return;
|
||||
}
|
||||
|
||||
generateDataQr(data).then(setState);
|
||||
}
|
||||
|
||||
onKeyDown = (event) => {
|
||||
@@ -528,19 +544,25 @@ export default class TransactionPendingFormConfirm extends Component {
|
||||
|
||||
readNonce = () => {
|
||||
const { api } = this.context;
|
||||
const { account } = this.props;
|
||||
const { account, dataToSign } = this.props;
|
||||
const { qr } = this.state;
|
||||
|
||||
if (!account || !account.external || !api.transport.isConnected) {
|
||||
if (dataToSign.data && qr && !qr.value) {
|
||||
this.generateQr();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!account || !account.external || !api.transport.isConnected || !dataToSign.transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
return api.parity
|
||||
.nextNonce(account.address)
|
||||
.then((nonce) => {
|
||||
const { qr } = this.state;
|
||||
.then((newNonce) => {
|
||||
const { nonce } = this.state.qr;
|
||||
|
||||
if (!qr.nonce || !nonce.eq(qr.nonce)) {
|
||||
this.generateTxQr();
|
||||
if (!nonce || !newNonce.eq(nonce)) {
|
||||
this.generateQr();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ function render (address) {
|
||||
address={ address }
|
||||
onConfirm={ onConfirm }
|
||||
isSending={ false }
|
||||
dataToSign={ {} }
|
||||
/>
|
||||
);
|
||||
instance = component.instance();
|
||||
|
||||
@@ -30,12 +30,18 @@ export default class TransactionPendingForm extends Component {
|
||||
className: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
focus: PropTypes.bool,
|
||||
gasStore: PropTypes.object.isRequired,
|
||||
netVersion: PropTypes.string.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onReject: PropTypes.func.isRequired,
|
||||
transaction: PropTypes.object.isRequired
|
||||
dataToSign: PropTypes.oneOfType([
|
||||
PropTypes.shape({
|
||||
transaction: PropTypes.object.isRequired
|
||||
}),
|
||||
PropTypes.shape({
|
||||
data: PropTypes.string.isRequired
|
||||
})
|
||||
]).isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@@ -59,7 +65,7 @@ export default class TransactionPendingForm extends Component {
|
||||
}
|
||||
|
||||
renderForm () {
|
||||
const { account, address, disabled, focus, gasStore, isSending, netVersion, onConfirm, onReject, transaction } = this.props;
|
||||
const { account, address, disabled, focus, isSending, netVersion, onConfirm, onReject, dataToSign } = this.props;
|
||||
|
||||
if (this.state.isRejectOpen) {
|
||||
return (
|
||||
@@ -73,11 +79,10 @@ export default class TransactionPendingForm extends Component {
|
||||
account={ account }
|
||||
disabled={ disabled }
|
||||
focus={ focus }
|
||||
gasStore={ gasStore }
|
||||
netVersion={ netVersion }
|
||||
isSending={ isSending }
|
||||
onConfirm={ onConfirm }
|
||||
transaction={ transaction }
|
||||
dataToSign={ dataToSign }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user