Fix MethodDecoding for Arrays (#4977)

* Fix TypedInputs

* Remove unused code in inputQueries

* Use TypedInputs in Contract Events

* Linting

* Don't re-render events every second...
This commit is contained in:
Nicolas Gotchac 2017-03-21 17:02:41 +01:00 committed by Jaco Greeff
parent c7e6992239
commit 030d01102c
10 changed files with 64 additions and 108 deletions

View File

@ -28,6 +28,6 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.container { .container > * {
display: flex; display: flex;
} }

View File

@ -25,7 +25,6 @@
color: rgba(255, 255, 255, 0.498039); color: rgba(255, 255, 255, 0.498039);
-webkit-user-select: none; -webkit-user-select: none;
font-size: 12px; font-size: 12px;
top: 11px;
position: relative; position: relative;
} }
} }

View File

@ -24,6 +24,7 @@ import AddIcon from 'material-ui/svg-icons/content/add';
import RemoveIcon from 'material-ui/svg-icons/content/remove'; import RemoveIcon from 'material-ui/svg-icons/content/remove';
import { fromWei, toWei } from '~/api/util/wei'; import { fromWei, toWei } from '~/api/util/wei';
import { bytesToHex } from '~/api/util/format';
import Input from '~/ui/Form/Input'; import Input from '~/ui/Form/Input';
import InputAddressSelect from '~/ui/Form/InputAddressSelect'; import InputAddressSelect from '~/ui/Form/InputAddressSelect';
import Select from '~/ui/Form/Select'; import Select from '~/ui/Form/Select';
@ -68,7 +69,8 @@ export default class TypedInput extends Component {
}; };
componentWillMount () { componentWillMount () {
const { isEth, value } = this.props; const { isEth } = this.props;
const value = this.getValue();
if (typeof isEth === 'boolean' && value) { if (typeof isEth === 'boolean' && value) {
// Remove formatting commas // Remove formatting commas
@ -95,14 +97,15 @@ export default class TypedInput extends Component {
const { type } = param; const { type } = param;
if (type === ABI_TYPES.ARRAY) { if (type === ABI_TYPES.ARRAY) {
const { accounts, className, label, value = param.default } = this.props; const { accounts, className, label } = this.props;
const { subtype, length } = param; const { subtype, length } = param;
const value = this.getValue() || param.default;
const fixedLength = !!length; const fixedLength = !!length;
const inputs = range(length || value.length).map((_, index) => { const inputs = range(length || value.length).map((_, index) => {
const onChange = (inputValue) => { const onChange = (inputValue) => {
const newValues = [].concat(this.props.value); const newValues = [].concat(value);
newValues[index] = inputValue; newValues[index] = inputValue;
this.props.onChange(newValues); this.props.onChange(newValues);
@ -191,7 +194,14 @@ export default class TypedInput extends Component {
} }
if (type === ABI_TYPES.BYTES) { if (type === ABI_TYPES.BYTES) {
return this.renderDefault(); let value = this.getValue();
// Convert to hex if it's an array
if (Array.isArray(value)) {
value = bytesToHex(value);
}
return this.renderDefault(value);
} }
// If the `isEth` prop is present (true or false) // If the `isEth` prop is present (true or false)
@ -260,7 +270,7 @@ export default class TypedInput extends Component {
: bnValue.toFixed(); // we need a string representation, could be >15 digits : bnValue.toFixed(); // we need a string representation, could be >15 digits
} }
renderInteger (value = this.props.value, onChange = this.onChange) { renderInteger (value = this.getValue(), onChange = this.onChange) {
const { allowCopy, className, label, error, hint, min, max, readOnly } = this.props; const { allowCopy, className, label, error, hint, min, max, readOnly } = this.props;
const param = this.getParam(); const param = this.getParam();
@ -268,7 +278,7 @@ export default class TypedInput extends Component {
return ( return (
<Input <Input
allowCopy={ allowCopy } allowCopy={ allowCopy ? value : undefined }
className={ className } className={ className }
label={ label } label={ label }
hint={ hint } hint={ hint }
@ -291,7 +301,7 @@ export default class TypedInput extends Component {
* *
* @see https://github.com/facebook/react/issues/1549 * @see https://github.com/facebook/react/issues/1549
*/ */
renderFloat (value = this.props.value, onChange = this.onChange) { renderFloat (value = this.getValue(), onChange = this.onChange) {
const { allowCopy, className, label, error, hint, min, max, readOnly } = this.props; const { allowCopy, className, label, error, hint, min, max, readOnly } = this.props;
const param = this.getParam(); const param = this.getParam();
@ -299,7 +309,7 @@ export default class TypedInput extends Component {
return ( return (
<Input <Input
allowCopy={ allowCopy } allowCopy={ allowCopy ? value : undefined }
className={ className } className={ className }
label={ label } label={ label }
hint={ hint } hint={ hint }
@ -314,8 +324,8 @@ export default class TypedInput extends Component {
); );
} }
renderDefault () { renderDefault (value = this.getValue()) {
const { allowCopy, className, label, value, error, hint, readOnly } = this.props; const { allowCopy, className, label, error, hint, readOnly } = this.props;
return ( return (
<Input <Input
@ -332,7 +342,8 @@ export default class TypedInput extends Component {
} }
renderAddress () { renderAddress () {
const { accounts, allowCopy, className, label, value, error, hint, readOnly } = this.props; const { accounts, allowCopy, className, label, error, hint, readOnly } = this.props;
const value = this.getValue();
return ( return (
<InputAddressSelect <InputAddressSelect
@ -350,7 +361,8 @@ export default class TypedInput extends Component {
} }
renderBoolean () { renderBoolean () {
const { allowCopy, className, label, value, error, hint, readOnly } = this.props; const { allowCopy, className, label, error, hint, readOnly } = this.props;
const value = this.getValue();
if (readOnly) { if (readOnly) {
return this.renderDefault(); return this.renderDefault();
@ -441,7 +453,7 @@ export default class TypedInput extends Component {
onChange(newValues); onChange(newValues);
} }
getParam = () => { getParam () {
const { param } = this.props; const { param } = this.props;
if (typeof param === 'string') { if (typeof param === 'string') {
@ -450,4 +462,15 @@ export default class TypedInput extends Component {
return param; return param;
} }
/**
* If the value comes from `decodeMethodInput`,
* it can be an object of the shape:
* { value: Object, type: String }
*/
getValue (value = this.props.value) {
return value && value.value
? value.value
: value;
}
} }

View File

@ -560,7 +560,7 @@ class MethodDecoding extends Component {
key={ index } key={ index }
param={ input.type } param={ input.type }
readOnly readOnly
value={ this.renderValue(input.value) } value={ input.value }
/> />
); );
}); });
@ -568,16 +568,6 @@ class MethodDecoding extends Component {
return inputs; return inputs;
} }
renderValue (value) {
const { api } = this.context;
if (api.util.isArray(value)) {
return api.util.bytesToHex(value);
}
return value.toString();
}
renderTokenValue (value) { renderTokenValue (value) {
const { token } = this.props; const { token } = this.props;

View File

@ -101,7 +101,7 @@ export function parseAbiType (type) {
}; };
} }
if (type === 'bytes') { if (type === 'bytes' || type === 'fixedBytes') {
return { return {
type: BYTES_TYPE, type: BYTES_TYPE,
default: '0x' default: '0x'

View File

@ -19,7 +19,7 @@ import moment from 'moment';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { IdentityIcon, IdentityName, Input, InputAddress } from '~/ui'; import { IdentityIcon, IdentityName, TypedInput } from '~/ui';
import ShortenedHash from '~/ui/ShortenedHash'; import ShortenedHash from '~/ui/ShortenedHash';
import { txLink } from '~/3rdparty/etherscan/links'; import { txLink } from '~/3rdparty/etherscan/links';
@ -112,41 +112,16 @@ export default class Event extends Component {
} }
renderParam (name, param) { renderParam (name, param) {
const { api } = this.context; return (
<TypedInput
switch (param.type) { allowCopy
case 'address': className={ styles.input }
return ( label={ name }
<InputAddress param={ param.type }
disabled readOnly
text value={ param.value }
className={ styles.input } />
value={ param.value } );
label={ name }
/>
);
default:
let value;
if (api.util.isInstanceOf(param.value, BigNumber)) {
value = param.value.toFormat(0);
} else if (api.util.isArray(param.value)) {
value = api.util.bytesToHex(param.value);
} else {
value = param.value.toString();
}
return (
<Input
readOnly
allowCopy
className={ styles.input }
value={ value }
label={ name }
/>
);
}
} }
formatBlockTimestamp (block) { formatBlockTimestamp (block) {

View File

@ -46,6 +46,12 @@ export default class Events extends Component {
events: [] events: []
}; };
shouldComponentUpdate (nextProps) {
return (nextProps.events !== this.props.events) ||
(nextProps.netVersion !== this.props.netVersion) ||
(nextProps.isLoading !== this.props.isLoading);
}
render () { render () {
const { events, isLoading, netVersion } = this.props; const { events, isLoading, netVersion } = this.props;

View File

@ -138,10 +138,8 @@ class InputQuery extends Component {
.map((out, index) => ({ .map((out, index) => ({
name: out.name, name: out.name,
type: out.type, type: out.type,
value: results[index], value: results[index]
display: this.renderValue(results[index])
})) }))
.sort((outA, outB) => outA.display.length - outB.display.length)
.map((out, index) => { .map((out, index) => {
const input = ( const input = (
<TypedInput <TypedInput
@ -150,7 +148,7 @@ class InputQuery extends Component {
isEth={ false } isEth={ false }
param={ out.type } param={ out.type }
readOnly readOnly
value={ out.display } value={ out.value }
/> />
); );
@ -195,25 +193,6 @@ class InputQuery extends Component {
); );
} }
renderValue (token) {
const { api } = this.context;
const { type, value } = token;
if (value === null || value === undefined) {
return 'no data';
}
if (type === 'array' || type === 'fixedArray') {
return value.map((tok) => this.renderValue(tok));
}
if (Array.isArray(value)) {
return api.util.bytesToHex(value);
}
return value;
}
onClick = () => { onClick = () => {
const { inputs, values } = this.state; const { inputs, values } = this.state;
const { contract, name, outputs, signature } = this.props; const { contract, name, outputs, signature } = this.props;

View File

@ -139,15 +139,14 @@ export default class Queries extends Component {
); );
} }
renderValue (tokenValue, output, key) { renderValue (value, output, key) {
if (typeof tokenValue === 'undefined') { if (typeof value === 'undefined') {
return null; return null;
} }
const { accountsInfo } = this.props; const { accountsInfo } = this.props;
const { name, type } = output; const { name, type } = output;
const label = `${name ? `${name}: ` : ''}${type}`; const label = `${name ? `${name}: ` : ''}${type}`;
const value = this.getTokenValue(tokenValue);
return ( return (
<TypedInput <TypedInput
@ -163,25 +162,6 @@ export default class Queries extends Component {
); );
} }
getTokenValue (token) {
const { api } = this.context;
const { type, value } = token;
if (value === null || value === undefined) {
return 'no data';
}
if (type === 'array' || type === 'fixedArray') {
return value.map((tok) => this.getTokenValue(tok));
}
if (Array.isArray(value)) {
return api.util.bytesToHex(value);
}
return value;
}
_sortEntries (a, b) { _sortEntries (a, b) {
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
} }

View File

@ -578,6 +578,10 @@ class WriteContract extends Component {
} }
renderContract (contract) { renderContract (contract) {
if (!contract) {
return null;
}
const { bytecode } = contract; const { bytecode } = contract;
const abi = contract.interface; const abi = contract.interface;