Make Wallet first-class citizens (#3990)

* Fixed hint in Address Select + Wallet as first-class-citizen

* Separate Owned and not Owned Wallets

* Fix balance not updating

* Fix MethodDecoding for Contract Deployment

* Fix TypedInput params

* Fix Token Transfer for Wallet

* Small change to contracts

* Fix wallets shown twice

* Fix separation of accounts and wallets in Accounts

* Fix linting

* Execute contract methods from Wallet ✓

* Fixing linting

* Wallet as first-class citizen: Part 1 (Manual) #3784

* Lower level wallet transaction convertion

* Fix linting

* Proper autoFocus on right Signer input

* PR Grumble: don't show Wallets in dApps Permissions

* Add postTransaction and gasEstimate wrapper methods

* Extract Wallet postTx and gasEstimate to utils + PATCH api

* Remove invalid test

It's totally valid for input's length not to be a multiple of 32 bytes. EG. for Wallet Contracts

* Merge master

* Fix linting

* Fix merge issue

* Rename Portal

* Rename Protal => Portal (typo)
This commit is contained in:
Nicolas Gotchac
2016-12-30 12:28:12 +01:00
committed by Gav Wood
parent 88c0329a31
commit fd41a10319
46 changed files with 570 additions and 230 deletions

View File

@@ -26,8 +26,8 @@ import TextFieldUnderline from 'material-ui/TextField/TextFieldUnderline';
import AccountCard from '~/ui/AccountCard';
import InputAddress from '~/ui/Form/InputAddress';
import Portal from '~/ui/Portal';
import { validateAddress } from '~/util/validation';
import { nodeOrStringProptype } from '~/util/proptypes';
import { validateAddress } from '~/util/validation';
import AddressSelectStore from './addressSelectStore';
import styles from './addressSelect.css';
@@ -40,6 +40,7 @@ let currentId = 1;
@observer
class AddressSelect extends Component {
static contextTypes = {
intl: React.PropTypes.object.isRequired,
api: PropTypes.object.isRequired,
muiTheme: PropTypes.object.isRequired
};
@@ -55,7 +56,6 @@ class AddressSelect extends Component {
contacts: PropTypes.object,
contracts: PropTypes.object,
tokens: PropTypes.object,
wallets: PropTypes.object,
// Optional props
allowInput: PropTypes.bool,
@@ -160,6 +160,12 @@ class AddressSelect extends Component {
}
const id = `addressSelect_${++currentId}`;
const ilHint = typeof hint === 'string' || !(hint && hint.props)
? (hint || '')
: this.context.intl.formatMessage(
hint.props,
hint.props.values || {}
);
return (
<Portal
@@ -174,7 +180,7 @@ class AddressSelect extends Component {
<input
id={ id }
className={ styles.input }
placeholder={ hint }
placeholder={ ilHint }
onBlur={ this.handleInputBlur }
onFocus={ this.handleInputFocus }

View File

@@ -78,14 +78,13 @@ export default class AddressSelectStore {
}
@action setValues (props) {
const { accounts = {}, contracts = {}, contacts = {}, wallets = {} } = props;
const { accounts = {}, contracts = {}, contacts = {} } = props;
const accountsN = Object.keys(accounts).length;
const contractsN = Object.keys(contracts).length;
const contactsN = Object.keys(contacts).length;
const walletsN = Object.keys(wallets).length;
if (accountsN + contractsN + contactsN + walletsN === 0) {
if (accountsN + contractsN + contactsN === 0) {
return;
}
@@ -98,10 +97,7 @@ export default class AddressSelectStore {
defaultMessage='accounts'
/>
),
values: [].concat(
Object.values(wallets),
Object.values(accounts)
)
values: Object.values(accounts)
},
{
key: 'contacts',

View File

@@ -51,6 +51,7 @@ export default class Input extends Component {
PropTypes.string,
PropTypes.bool
]),
autoFocus: PropTypes.bool,
children: PropTypes.node,
className: PropTypes.string,
disabled: PropTypes.bool,
@@ -112,7 +113,7 @@ export default class Input extends Component {
render () {
const { value } = this.state;
const { children, className, hideUnderline, disabled, error, focused, label } = this.props;
const { autoFocus, children, className, hideUnderline, disabled, error, focused, label } = this.props;
const { hint, onClick, onFocus, multiLine, rows, type, min, max, style, tabIndex } = this.props;
const readOnly = this.props.readOnly || disabled;
@@ -138,6 +139,7 @@ export default class Input extends Component {
{ this.renderCopyButton() }
<TextField
autoComplete='off'
autoFocus={ autoFocus }
className={ className }
errorText={ error }
floatingLabelFixed

View File

@@ -25,7 +25,6 @@ class InputAddressSelect extends Component {
accounts: PropTypes.object.isRequired,
contacts: PropTypes.object.isRequired,
contracts: PropTypes.object.isRequired,
wallets: PropTypes.object.isRequired,
error: PropTypes.string,
label: PropTypes.string,
hint: PropTypes.string,
@@ -34,7 +33,7 @@ class InputAddressSelect extends Component {
};
render () {
const { accounts, contacts, contracts, wallets, label, hint, error, value, onChange } = this.props;
const { accounts, contacts, contracts, label, hint, error, value, onChange } = this.props;
return (
<AddressSelect
@@ -42,7 +41,6 @@ class InputAddressSelect extends Component {
accounts={ accounts }
contacts={ contacts }
contracts={ contracts }
wallets={ wallets }
error={ error }
label={ label }
hint={ hint }
@@ -53,13 +51,12 @@ class InputAddressSelect extends Component {
}
function mapStateToProps (state) {
const { accounts, contacts, contracts, wallets } = state.personal;
const { accounts, contacts, contracts } = state.personal;
return {
accounts,
contacts,
contracts,
wallets
contracts
};
}

View File

@@ -67,15 +67,7 @@ export default class TypedInput extends Component {
}
render () {
const { param } = this.props;
if (typeof param === 'string') {
const parsedParam = parseAbiType(param);
if (parsedParam) {
return this.renderParam(parsedParam);
}
}
const param = this.getParam();
if (param) {
return this.renderParam(param);
@@ -234,7 +226,8 @@ export default class TypedInput extends Component {
}
renderInteger (value = this.props.value, onChange = this.onChange) {
const { label, error, param, hint, min, max } = this.props;
const { label, error, hint, min, max } = this.props;
const param = this.getParam();
const realValue = value && typeof value.toNumber === 'function'
? value.toNumber()
@@ -263,7 +256,8 @@ export default class TypedInput extends Component {
* @see https://github.com/facebook/react/issues/1549
*/
renderFloat (value = this.props.value, onChange = this.onChange) {
const { label, error, param, hint, min, max } = this.props;
const { label, error, hint, min, max } = this.props;
const param = this.getParam();
const realValue = value && typeof value.toNumber === 'function'
? value.toNumber()
@@ -379,7 +373,9 @@ export default class TypedInput extends Component {
}
onAddField = () => {
const { value, onChange, param } = this.props;
const { value, onChange } = this.props;
const param = this.getParam();
const newValues = [].concat(value, param.subtype.default);
onChange(newValues);
@@ -392,4 +388,14 @@ export default class TypedInput extends Component {
onChange(newValues);
}
getParam = () => {
const { param } = this.props;
if (typeof param === 'string') {
return parseAbiType(param);
}
return param;
}
}

View File

@@ -118,6 +118,15 @@ export default class MethodDecodingStore {
return Promise.resolve(result);
}
try {
const { signature } = this.api.util.decodeCallData(input);
if (signature === CONTRACT_CREATE || transaction.creates) {
result.contract = true;
return Promise.resolve({ ...result, deploy: true });
}
} catch (e) {}
return this
.isContract(contractAddress || transaction.creates)
.then((isContract) => {
@@ -132,7 +141,7 @@ export default class MethodDecodingStore {
result.params = paramdata;
// Contract deployment
if (!signature || signature === CONTRACT_CREATE || transaction.creates) {
if (!signature) {
return Promise.resolve({ ...result, deploy: true });
}
@@ -192,7 +201,7 @@ export default class MethodDecodingStore {
*/
isContract (contractAddress) {
// If zero address, it isn't a contract
if (/^(0x)?0*$/.test(contractAddress)) {
if (!contractAddress || /^(0x)?0*$/.test(contractAddress)) {
return Promise.resolve(false);
}

View File

@@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import Portal from 'react-portal';
import ReactPortal from 'react-portal';
import keycode from 'keycode';
import { CloseIcon } from '~/ui/Icons';
@@ -24,7 +24,7 @@ import ParityBackground from '~/ui/ParityBackground';
import styles from './portal.css';
export default class Protal extends Component {
export default class Portal extends Component {
static propTypes = {
onClose: PropTypes.func.isRequired,
@@ -65,7 +65,7 @@ export default class Protal extends Component {
}
return (
<Portal isOpened onClose={ this.handleClose }>
<ReactPortal isOpened onClose={ this.handleClose }>
<div
className={ classes.join(' ') }
onKeyDown={ this.handleKeyDown }
@@ -75,7 +75,7 @@ export default class Protal extends Component {
{ this.renderCloseIcon() }
{ children }
</div>
</Portal>
</ReactPortal>
);
}

View File

@@ -134,7 +134,7 @@ class TxHash extends Component {
const { api } = this.context;
const { hash } = this.props;
if (error) {
if (error || !hash || /^(0x)?0*$/.test(hash)) {
return;
}