diff --git a/js/src/api/util/format.js b/js/src/api/util/format.js index 61fc9d32ca9..6a4a81d4004 100644 --- a/js/src/api/util/format.js +++ b/js/src/api/util/format.js @@ -75,7 +75,10 @@ export function bytesToAscii (bytes) { } export function asciiToHex (string) { - return '0x' + string.split('').map((s) => s.charCodeAt(0).toString(16)).join(''); + return '0x' + string.split('') + .map(s => s.charCodeAt(0)) + .map(s => s < 0x10 ? '0' + s.toString(16) : s.toString(16)) + .join(''); } export function padRight (input, length) { diff --git a/js/src/api/util/format.spec.js b/js/src/api/util/format.spec.js index c372055694c..ba7a3994e04 100644 --- a/js/src/api/util/format.spec.js +++ b/js/src/api/util/format.spec.js @@ -67,6 +67,7 @@ describe('api/util/format', () => { it('correctly converts a non-empty string', () => { expect(asciiToHex('abc')).to.equal('0x616263'); + expect(asciiToHex('a\nb')).to.equal('0x610a62'); }); }); diff --git a/js/src/api/util/index.js b/js/src/api/util/index.js index cc8fc9b939f..30328856bd5 100644 --- a/js/src/api/util/index.js +++ b/js/src/api/util/index.js @@ -17,7 +17,7 @@ import { isAddress as isAddressValid, toChecksumAddress } from '../../abi/util/address'; import { abiDecode, decodeCallData, decodeMethodInput, methodToAbi } from './decode'; import { abiEncode, abiUnencode, abiSignature, encodeMethodCallAbi } from './encode'; -import { bytesToHex, hexToAscii, asciiToHex, cleanupValue } from './format'; +import { bytesToHex, hexToAscii, hexToBytes, asciiToHex, cleanupValue } from './format'; import { fromWei, toWei } from './wei'; import { sha3 } from './sha3'; import { isArray, isFunction, isHex, isInstanceOf, isString } from './types'; @@ -37,6 +37,7 @@ export default { isString, bytesToHex, hexToAscii, + hexToBytes, asciiToHex, createIdentityImg, decodeCallData, diff --git a/js/src/views/Signer/components/SignRequest/signRequest.js b/js/src/views/Signer/components/SignRequest/signRequest.js index 705b89965fa..2f97f140f5f 100644 --- a/js/src/views/Signer/components/SignRequest/signRequest.js +++ b/js/src/views/Signer/components/SignRequest/signRequest.js @@ -18,6 +18,7 @@ import { observer } from 'mobx-react'; import React, { Component, PropTypes } from 'react'; import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; +import ReactTooltip from 'react-tooltip'; import HardwareStore from '~/mobx/hardwareStore'; @@ -70,6 +71,10 @@ class SignRequest extends Component { } }; + state = { + hashToSign: null + }; + hardwareStore = HardwareStore.get(this.context.api); componentWillMount () { @@ -78,6 +83,25 @@ class SignRequest extends Component { signerStore.fetchBalance(address); } + componentDidMount () { + this.computeHashToSign(this.props.data); + } + + componentWillReceiveProps (nextProps) { + if (this.props.data !== nextProps.data) { + this.computeHashToSign(nextProps.data); + } + } + + computeHashToSign (data) { + const { sha3, hexToBytes, asciiToHex } = this.context.api.util; + const bytes = hexToBytes(data); + const message = hexToBytes(asciiToHex(`\x19Ethereum Signed Message:\n${bytes.length}`)); + const hashToSign = sha3(message.concat(bytes)); + + this.setState({ hashToSign }); + } + render () { const { className } = this.props; @@ -113,6 +137,7 @@ class SignRequest extends Component { renderDetails () { const { api } = this.context; const { address, data, netVersion, origin, signerStore } = this.props; + const { hashToSign } = this.state; const { balances, externalLink } = signerStore; const balance = balances[address]; @@ -121,6 +146,20 @@ class SignRequest extends Component { return
; } + const tooltip = [ + , +
, + + ]; + return (
@@ -133,7 +172,16 @@ class SignRequest extends Component { />
-
+ + { tooltip } + +

, { context: { - store: reduxStore + store: reduxStore, + api: { + util: { + sha3: (x) => x, + hexToBytes: (x) => x, + asciiToHex: (x) => x + } + } } } ).find('SignRequest').shallow(); @@ -61,7 +68,7 @@ function render () { return component; } -describe('views/Signer/components/SignRequest', () => { +describe.only('views/Signer/components/SignRequest', () => { beforeEach(() => { render(); });