merge master into jr-email-verification
This commit is contained in:
commit
eb1429237b
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1271,7 +1271,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/ethcore/js-precompiled.git#a59b62ecec8773715d1db7e070bbbe5443eb7378"
|
source = "git+https://github.com/ethcore/js-precompiled.git#8e8e515f958d2d4a5abec07253a51a052f2b744d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"transform-runtime",
|
"transform-runtime",
|
||||||
"transform-decorators-legacy",
|
"transform-decorators-legacy",
|
||||||
"transform-class-properties",
|
"transform-class-properties",
|
||||||
|
"transform-object-rest-spread",
|
||||||
"lodash"
|
"lodash"
|
||||||
],
|
],
|
||||||
"retainLines": true,
|
"retainLines": true,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parity.js",
|
"name": "parity.js",
|
||||||
"version": "0.2.99",
|
"version": "0.2.103",
|
||||||
"main": "release/index.js",
|
"main": "release/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
"author": "Parity Team <admin@parity.io>",
|
"author": "Parity Team <admin@parity.io>",
|
||||||
@ -48,25 +48,26 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "6.18.0",
|
"babel-cli": "6.18.0",
|
||||||
"babel-core": "6.18.2",
|
"babel-core": "6.20.0",
|
||||||
"babel-eslint": "7.1.1",
|
"babel-eslint": "7.1.1",
|
||||||
"babel-loader": "6.2.8",
|
"babel-loader": "6.2.8",
|
||||||
"babel-plugin-lodash": "3.2.10",
|
"babel-plugin-lodash": "3.2.10",
|
||||||
"babel-plugin-transform-class-properties": "6.19.0",
|
"babel-plugin-transform-class-properties": "6.18.0",
|
||||||
"babel-plugin-transform-decorators-legacy": "1.3.4",
|
"babel-plugin-transform-decorators-legacy": "1.3.4",
|
||||||
|
"babel-plugin-transform-object-rest-spread": "6.20.2",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "0.2.11",
|
"babel-plugin-transform-react-remove-prop-types": "0.2.11",
|
||||||
"babel-plugin-transform-runtime": "6.15.0",
|
"babel-plugin-transform-runtime": "6.15.0",
|
||||||
"babel-polyfill": "6.16.0",
|
"babel-polyfill": "6.20.0",
|
||||||
"babel-preset-es2015": "6.18.0",
|
"babel-preset-es2015": "6.18.0",
|
||||||
"babel-preset-es2015-rollup": "1.2.0",
|
|
||||||
"babel-preset-es2016": "6.16.0",
|
"babel-preset-es2016": "6.16.0",
|
||||||
"babel-preset-es2017": "6.16.0",
|
"babel-preset-es2017": "6.16.0",
|
||||||
"babel-preset-react": "6.16.0",
|
"babel-preset-react": "6.16.0",
|
||||||
"babel-preset-stage-0": "6.16.0",
|
"babel-preset-stage-0": "6.16.0",
|
||||||
"babel-register": "6.18.0",
|
"babel-register": "6.18.0",
|
||||||
"babel-runtime": "6.18.0",
|
"babel-runtime": "6.20.0",
|
||||||
"chai": "3.5.0",
|
"chai": "3.5.0",
|
||||||
"chai-enzyme": "0.6.1",
|
"chai-enzyme": "0.6.1",
|
||||||
|
"circular-dependency-plugin": "2.0.0",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
"copy-webpack-plugin": "4.0.1",
|
||||||
"core-js": "2.4.1",
|
"core-js": "2.4.1",
|
||||||
"coveralls": "2.11.15",
|
"coveralls": "2.11.15",
|
||||||
|
@ -1 +1 @@
|
|||||||
// test script 4
|
// test script 6
|
||||||
|
8
js/src/3rdparty/etherscan/links.js
vendored
8
js/src/3rdparty/etherscan/links.js
vendored
@ -14,10 +14,14 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export const url = (isTestnet = false) => {
|
||||||
|
return `https://${isTestnet ? 'testnet.' : ''}etherscan.io`;
|
||||||
|
};
|
||||||
|
|
||||||
export const txLink = (hash, isTestnet = false) => {
|
export const txLink = (hash, isTestnet = false) => {
|
||||||
return `https://${isTestnet ? 'testnet.' : ''}etherscan.io/tx/${hash}`;
|
return `${url(isTestnet)}/tx/${hash}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addressLink = (address, isTestnet = false) => {
|
export const addressLink = (address, isTestnet = false) => {
|
||||||
return `https://${isTestnet ? 'testnet.' : ''}etherscan.io/address/${address}`;
|
return `${url(isTestnet)}/address/${address}`;
|
||||||
};
|
};
|
||||||
|
@ -262,12 +262,11 @@ export default class Contract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const options = this._getFilterOptions(event, _options);
|
const options = this._getFilterOptions(event, _options);
|
||||||
|
options.fromBlock = 0;
|
||||||
|
options.toBlock = 'latest';
|
||||||
|
|
||||||
return this._api.eth
|
return this._api.eth
|
||||||
.getLogs({
|
.getLogs(options)
|
||||||
fromBlock: 0,
|
|
||||||
toBlock: 'latest',
|
|
||||||
...options
|
|
||||||
})
|
|
||||||
.then((logs) => this.parseEventLogs(logs));
|
.then((logs) => this.parseEventLogs(logs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import babel from 'rollup-plugin-babel';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
entry: 'src/index.js',
|
|
||||||
dest: 'release/index.js',
|
|
||||||
format: 'cjs',
|
|
||||||
plugins: [babel({
|
|
||||||
babelrc: false,
|
|
||||||
presets: ['es2015-rollup', 'stage-0'],
|
|
||||||
runtimeHelpers: true
|
|
||||||
})]
|
|
||||||
};
|
|
@ -19,7 +19,7 @@ import ContentAdd from 'material-ui/svg-icons/content/add';
|
|||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
|
||||||
import { Button, Modal, Form, Input, InputAddress } from '~/ui';
|
import { Button, Modal, Form, Input, InputAddress } from '~/ui';
|
||||||
import { ERRORS, validateAddress, validateName } from '../../util/validation';
|
import { ERRORS, validateAddress, validateName } from '~/util/validation';
|
||||||
|
|
||||||
export default class AddAddress extends Component {
|
export default class AddAddress extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
@ -21,7 +21,7 @@ import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forwa
|
|||||||
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
|
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
|
||||||
|
|
||||||
import { Button, Modal, Form, Input, InputAddress, RadioButtons } from '~/ui';
|
import { Button, Modal, Form, Input, InputAddress, RadioButtons } from '~/ui';
|
||||||
import { ERRORS, validateAbi, validateAddress, validateName } from '../../util/validation';
|
import { ERRORS, validateAbi, validateAddress, validateName } from '~/util/validation';
|
||||||
|
|
||||||
import { eip20, wallet } from '~/contracts/abi';
|
import { eip20, wallet } from '~/contracts/abi';
|
||||||
|
|
||||||
|
@ -16,13 +16,12 @@
|
|||||||
|
|
||||||
import { observable, computed, action, transaction } from 'mobx';
|
import { observable, computed, action, transaction } from 'mobx';
|
||||||
|
|
||||||
import { validateUint, validateAddress, validateName } from '~/util/validation';
|
|
||||||
import { ERROR_CODES } from '~/api/transport/error';
|
|
||||||
|
|
||||||
import Contract from '~/api/contract';
|
import Contract from '~/api/contract';
|
||||||
|
import { ERROR_CODES } from '~/api/transport/error';
|
||||||
import { wallet as walletAbi } from '~/contracts/abi';
|
import { wallet as walletAbi } from '~/contracts/abi';
|
||||||
import { wallet as walletCode } from '~/contracts/code';
|
import { wallet as walletCode } from '~/contracts/code';
|
||||||
|
|
||||||
|
import { validateUint, validateAddress, validateName } from '~/util/validation';
|
||||||
import WalletsUtils from '~/util/wallets';
|
import WalletsUtils from '~/util/wallets';
|
||||||
|
|
||||||
const STEPS = {
|
const STEPS = {
|
||||||
|
@ -18,8 +18,8 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { MenuItem } from 'material-ui';
|
import { MenuItem } from 'material-ui';
|
||||||
|
|
||||||
import { AddressSelect, Form, Input, Select } from '~/ui';
|
import { AddressSelect, Form, Input, Select } from '~/ui';
|
||||||
import { validateAbi } from '../../../util/validation';
|
import { validateAbi } from '~/util/validation';
|
||||||
import { parseAbiType } from '../../../util/abi';
|
import { parseAbiType } from '~/util/abi';
|
||||||
|
|
||||||
export default class DetailsStep extends Component {
|
export default class DetailsStep extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import { Form, TypedInput } from '~/ui';
|
import { Form, TypedInput } from '~/ui';
|
||||||
import { parseAbiType } from '../../../util/abi';
|
import { parseAbiType } from '~/util/abi';
|
||||||
|
|
||||||
import styles from '../deployContract.css';
|
import styles from '../deployContract.css';
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
|||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
|
||||||
import { BusyStep, CompletedStep, CopyToClipboard, Button, IdentityIcon, Modal, TxHash } from '~/ui';
|
import { BusyStep, CompletedStep, CopyToClipboard, Button, IdentityIcon, Modal, TxHash } from '~/ui';
|
||||||
import { ERRORS, validateAbi, validateCode, validateName } from '../../util/validation';
|
import { ERRORS, validateAbi, validateCode, validateName } from '~/util/validation';
|
||||||
|
|
||||||
import DetailsStep from './DetailsStep';
|
import DetailsStep from './DetailsStep';
|
||||||
import ParametersStep from './ParametersStep';
|
import ParametersStep from './ParametersStep';
|
||||||
|
@ -19,7 +19,7 @@ import ContentClear from 'material-ui/svg-icons/content/clear';
|
|||||||
import ContentSave from 'material-ui/svg-icons/content/save';
|
import ContentSave from 'material-ui/svg-icons/content/save';
|
||||||
|
|
||||||
import { Button, Form, Input, InputChip, Modal } from '~/ui';
|
import { Button, Form, Input, InputChip, Modal } from '~/ui';
|
||||||
import { validateName } from '../../util/validation';
|
import { validateName } from '~/util/validation';
|
||||||
|
|
||||||
export default class EditMeta extends Component {
|
export default class EditMeta extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { MenuItem } from 'material-ui';
|
import { MenuItem } from 'material-ui';
|
||||||
|
|
||||||
import { AddressSelect, Form, Input, InputAddressSelect, Select } from '~/ui';
|
import { AddressSelect, Form, Input, Select, TypedInput } from '~/ui';
|
||||||
|
import { parseAbiType } from '~/util/abi';
|
||||||
|
|
||||||
import styles from '../executeContract.css';
|
import styles from '../executeContract.css';
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ export default class DetailsStep extends Component {
|
|||||||
|
|
||||||
const functions = contract.functions
|
const functions = contract.functions
|
||||||
.filter((func) => !func.constant)
|
.filter((func) => !func.constant)
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => (a.name || '').localeCompare(b.name || ''))
|
||||||
.map((func) => {
|
.map((func) => {
|
||||||
const params = (func.abi.inputs || [])
|
const params = (func.abi.inputs || [])
|
||||||
.map((input, index) => {
|
.map((input, index) => {
|
||||||
@ -125,56 +126,22 @@ export default class DetailsStep extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (func.abi.inputs || []).map((input, index) => {
|
return (func.abi.inputs || []).map((input, index) => {
|
||||||
const onChange = (event, value) => onValueChange(event, index, value);
|
const onChange = (value) => onValueChange(null, index, value);
|
||||||
const onSelect = (event, _index, value) => onValueChange(event, index, value);
|
|
||||||
const onSubmit = (value) => onValueChange(null, index, value);
|
|
||||||
const label = `${input.name}: ${input.type}`;
|
const label = `${input.name}: ${input.type}`;
|
||||||
let inputbox;
|
|
||||||
|
|
||||||
switch (input.type) {
|
|
||||||
case 'address':
|
|
||||||
inputbox = (
|
|
||||||
<InputAddressSelect
|
|
||||||
accounts={ accounts }
|
|
||||||
editing
|
|
||||||
label={ label }
|
|
||||||
value={ values[index] }
|
|
||||||
error={ valuesError[index] }
|
|
||||||
onChange={ onChange } />
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'bool':
|
|
||||||
const boolitems = ['false', 'true'].map((bool) => {
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
key={ bool }
|
|
||||||
value={ bool }
|
|
||||||
label={ bool }>{ bool }</MenuItem>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
inputbox = (
|
|
||||||
<Select
|
|
||||||
label={ label }
|
|
||||||
value={ values[index] ? 'true' : 'false' }
|
|
||||||
error={ valuesError[index] }
|
|
||||||
onChange={ onSelect }>{ boolitems }</Select>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
inputbox = (
|
|
||||||
<Input
|
|
||||||
label={ label }
|
|
||||||
value={ values[index] }
|
|
||||||
error={ valuesError[index] }
|
|
||||||
onSubmit={ onSubmit } />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.funcparams } key={ index }>
|
<div
|
||||||
{ inputbox }
|
key={ `${index}_${input.name || ''}` }
|
||||||
|
className={ styles.funcparams }
|
||||||
|
>
|
||||||
|
<TypedInput
|
||||||
|
label={ label }
|
||||||
|
value={ values[index] }
|
||||||
|
error={ valuesError[index] }
|
||||||
|
onChange={ onChange }
|
||||||
|
accounts={ accounts }
|
||||||
|
param={ parseAbiType(input.type) }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -21,8 +21,9 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
|||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
|
||||||
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '~/ui';
|
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '~/ui';
|
||||||
import { MAX_GAS_ESTIMATION } from '../../util/constants';
|
import { MAX_GAS_ESTIMATION } from '~/util/constants';
|
||||||
import { validateAddress, validateUint } from '../../util/validation';
|
import { validateAddress, validateUint } from '~/util/validation';
|
||||||
|
import { parseAbiType } from '~/util/abi';
|
||||||
|
|
||||||
import DetailsStep from './DetailsStep';
|
import DetailsStep from './DetailsStep';
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ class ExecuteContract extends Component {
|
|||||||
const { contract } = this.props;
|
const { contract } = this.props;
|
||||||
const functions = contract.functions
|
const functions = contract.functions
|
||||||
.filter((func) => !func.constant)
|
.filter((func) => !func.constant)
|
||||||
.sort((a, b) => a.name.localeCompare(b.name));
|
.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
|
||||||
|
|
||||||
this.onFuncChange(null, functions[0]);
|
this.onFuncChange(null, functions[0]);
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ class ExecuteContract extends Component {
|
|||||||
<Button
|
<Button
|
||||||
key='postTransaction'
|
key='postTransaction'
|
||||||
label='post transaction'
|
label='post transaction'
|
||||||
disabled={ sending || hasError }
|
disabled={ !!(sending || hasError) }
|
||||||
icon={ <IdentityIcon address={ fromAddress } button /> }
|
icon={ <IdentityIcon address={ fromAddress } button /> }
|
||||||
onClick={ this.postTransaction } />
|
onClick={ this.postTransaction } />
|
||||||
];
|
];
|
||||||
@ -174,23 +175,9 @@ class ExecuteContract extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onFuncChange = (event, func) => {
|
onFuncChange = (event, func) => {
|
||||||
const values = func.inputs.map((input) => {
|
const values = (func.abi.inputs || []).map((input) => {
|
||||||
switch (input.kind.type) {
|
const parsedType = parseAbiType(input.type);
|
||||||
case 'address':
|
return parsedType.default;
|
||||||
return '0x';
|
|
||||||
|
|
||||||
case 'bool':
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case 'bytes':
|
|
||||||
return '0x';
|
|
||||||
|
|
||||||
case 'uint':
|
|
||||||
return '0';
|
|
||||||
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -20,7 +20,7 @@ import SaveIcon from 'material-ui/svg-icons/content/save';
|
|||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
|
||||||
import { Button, Modal, Editor, Form, Input } from '~/ui';
|
import { Button, Modal, Editor, Form, Input } from '~/ui';
|
||||||
import { ERRORS, validateName } from '../../util/validation';
|
import { ERRORS, validateName } from '~/util/validation';
|
||||||
|
|
||||||
import styles from './saveContract.css';
|
import styles from './saveContract.css';
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
|||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
|
||||||
import { Button, IdentityIcon, Modal } from '~/ui';
|
import { Button, IdentityIcon, Modal } from '~/ui';
|
||||||
import initShapeshift from '../../3rdparty/shapeshift';
|
import initShapeshift from '~/3rdparty/shapeshift';
|
||||||
import shapeshiftLogo from '../../../assets/images/shapeshift-logo.png';
|
import shapeshiftLogo from '../../../assets/images/shapeshift-logo.png';
|
||||||
|
|
||||||
import AwaitingDepositStep from './AwaitingDepositStep';
|
import AwaitingDepositStep from './AwaitingDepositStep';
|
||||||
|
@ -16,96 +16,35 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import Form, { Input } from '~/ui/Form';
|
import { GasPriceEditor, Form, Input } from '~/ui';
|
||||||
import GasPriceSelector from '../GasPriceSelector';
|
|
||||||
|
|
||||||
import styles from '../transfer.css';
|
|
||||||
|
|
||||||
export default class Extras extends Component {
|
export default class Extras extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
isEth: PropTypes.bool,
|
isEth: PropTypes.bool,
|
||||||
data: PropTypes.string,
|
data: PropTypes.string,
|
||||||
dataError: PropTypes.string,
|
dataError: PropTypes.string,
|
||||||
gas: PropTypes.string,
|
|
||||||
gasEst: PropTypes.string,
|
|
||||||
gasError: PropTypes.string,
|
|
||||||
gasPrice: PropTypes.oneOfType([
|
|
||||||
PropTypes.string,
|
|
||||||
PropTypes.object
|
|
||||||
]),
|
|
||||||
gasPriceDefault: PropTypes.string,
|
|
||||||
gasPriceError: PropTypes.string,
|
|
||||||
gasPriceHistogram: PropTypes.object,
|
|
||||||
total: PropTypes.string,
|
total: PropTypes.string,
|
||||||
totalError: PropTypes.string,
|
totalError: PropTypes.string,
|
||||||
onChange: PropTypes.func.isRequired
|
onChange: PropTypes.func.isRequired,
|
||||||
|
gasStore: PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { gas, gasPrice, gasError, gasEst, gasPriceDefault, gasPriceError, gasPriceHistogram, total, totalError } = this.props;
|
const { gasStore, onChange, total, totalError } = this.props;
|
||||||
|
|
||||||
const gasLabel = `gas amount (estimated: ${gasEst})`;
|
|
||||||
const priceLabel = `gas price (current: ${gasPriceDefault})`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form>
|
<Form>
|
||||||
|
|
||||||
{ this.renderData() }
|
{ this.renderData() }
|
||||||
|
<GasPriceEditor
|
||||||
<div className={ styles.columns }>
|
store={ gasStore }
|
||||||
<div style={ { flex: 65 } }>
|
onChange={ onChange }>
|
||||||
<GasPriceSelector
|
<Input
|
||||||
gasPriceHistogram={ gasPriceHistogram }
|
disabled
|
||||||
gasPrice={ gasPrice }
|
label='total transaction amount'
|
||||||
onChange={ this.onEditGasPrice }
|
hint='the total amount of the transaction'
|
||||||
/>
|
error={ totalError }
|
||||||
</div>
|
value={ `${total} ETH` } />
|
||||||
|
</GasPriceEditor>
|
||||||
<div
|
|
||||||
className={ styles.row }
|
|
||||||
style={ {
|
|
||||||
flex: 35, paddingLeft: '1rem',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
paddingBottom: 12
|
|
||||||
} }
|
|
||||||
>
|
|
||||||
<div className={ styles.row }>
|
|
||||||
<Input
|
|
||||||
label={ gasLabel }
|
|
||||||
hint='the amount of gas to use for the transaction'
|
|
||||||
error={ gasError }
|
|
||||||
value={ gas }
|
|
||||||
onChange={ this.onEditGas } />
|
|
||||||
|
|
||||||
<Input
|
|
||||||
label={ priceLabel }
|
|
||||||
hint='the price of gas to use for the transaction'
|
|
||||||
error={ gasPriceError }
|
|
||||||
value={ (gasPrice || '').toString() }
|
|
||||||
onChange={ this.onEditGasPrice } />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={ styles.row }>
|
|
||||||
<Input
|
|
||||||
disabled
|
|
||||||
label='total transaction amount'
|
|
||||||
hint='the total amount of the transaction'
|
|
||||||
error={ totalError }
|
|
||||||
value={ `${total} ETH` } />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p className={ styles.gasPriceDesc }>
|
|
||||||
You can choose the gas price based on the
|
|
||||||
distribution of recent included transactions' gas prices.
|
|
||||||
The lower the gas price is, the cheaper the transaction will
|
|
||||||
be. The higher the gas price is, the faster it should
|
|
||||||
get mined by the network.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -129,14 +68,6 @@ export default class Extras extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditGas = (event) => {
|
|
||||||
this.props.onChange('gas', event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onEditGasPrice = (event, value) => {
|
|
||||||
this.props.onChange('gasPrice', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onEditData = (event) => {
|
onEditData = (event) => {
|
||||||
this.props.onChange('data', event.target.value);
|
this.props.onChange('data', event.target.value);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@ import { bytesToHex } from '~/api/util/format';
|
|||||||
import Contract from '~/api/contract';
|
import Contract from '~/api/contract';
|
||||||
import ERRORS from './errors';
|
import ERRORS from './errors';
|
||||||
import { ERROR_CODES } from '~/api/transport/error';
|
import { ERROR_CODES } from '~/api/transport/error';
|
||||||
import { DEFAULT_GAS, DEFAULT_GASPRICE, MAX_GAS_ESTIMATION } from '~/util/constants';
|
import { DEFAULT_GAS, MAX_GAS_ESTIMATION } from '~/util/constants';
|
||||||
|
import GasPriceStore from '~/ui/GasPriceEditor/store';
|
||||||
|
|
||||||
const TITLES = {
|
const TITLES = {
|
||||||
transfer: 'transfer details',
|
transfer: 'transfer details',
|
||||||
@ -48,14 +49,6 @@ export default class TransferStore {
|
|||||||
@observable data = '';
|
@observable data = '';
|
||||||
@observable dataError = null;
|
@observable dataError = null;
|
||||||
|
|
||||||
@observable gas = DEFAULT_GAS;
|
|
||||||
@observable gasError = null;
|
|
||||||
|
|
||||||
@observable gasEst = '0';
|
|
||||||
@observable gasLimitError = null;
|
|
||||||
@observable gasPrice = DEFAULT_GASPRICE;
|
|
||||||
@observable gasPriceError = null;
|
|
||||||
|
|
||||||
@observable recipient = '';
|
@observable recipient = '';
|
||||||
@observable recipientError = ERRORS.requireRecipient;
|
@observable recipientError = ERRORS.requireRecipient;
|
||||||
|
|
||||||
@ -68,11 +61,8 @@ export default class TransferStore {
|
|||||||
@observable value = '0.0';
|
@observable value = '0.0';
|
||||||
@observable valueError = null;
|
@observable valueError = null;
|
||||||
|
|
||||||
gasPriceHistogram = {};
|
|
||||||
|
|
||||||
account = null;
|
account = null;
|
||||||
balance = null;
|
balance = null;
|
||||||
gasLimit = null;
|
|
||||||
onClose = null;
|
onClose = null;
|
||||||
|
|
||||||
senders = null;
|
senders = null;
|
||||||
@ -81,6 +71,8 @@ export default class TransferStore {
|
|||||||
isWallet = false;
|
isWallet = false;
|
||||||
wallet = null;
|
wallet = null;
|
||||||
|
|
||||||
|
gasStore = null;
|
||||||
|
|
||||||
@computed get steps () {
|
@computed get steps () {
|
||||||
const steps = [].concat(this.extras ? STAGES_EXTRA : STAGES_BASIC);
|
const steps = [].concat(this.extras ? STAGES_EXTRA : STAGES_BASIC);
|
||||||
|
|
||||||
@ -93,7 +85,7 @@ export default class TransferStore {
|
|||||||
|
|
||||||
@computed get isValid () {
|
@computed get isValid () {
|
||||||
const detailsValid = !this.recipientError && !this.valueError && !this.totalError && !this.senderError;
|
const detailsValid = !this.recipientError && !this.valueError && !this.totalError && !this.senderError;
|
||||||
const extrasValid = !this.gasError && !this.gasPriceError && !this.totalError;
|
const extrasValid = !this.gasStore.errorGas && !this.gasStore.errorPrice && !this.totalError;
|
||||||
const verifyValid = !this.passwordError;
|
const verifyValid = !this.passwordError;
|
||||||
|
|
||||||
switch (this.stage) {
|
switch (this.stage) {
|
||||||
@ -118,11 +110,12 @@ export default class TransferStore {
|
|||||||
const { account, balance, gasLimit, senders, onClose, newError, sendersBalances } = props;
|
const { account, balance, gasLimit, senders, onClose, newError, sendersBalances } = props;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.balance = balance;
|
this.balance = balance;
|
||||||
this.gasLimit = gasLimit;
|
|
||||||
this.onClose = onClose;
|
this.onClose = onClose;
|
||||||
this.isWallet = account && account.wallet;
|
this.isWallet = account && account.wallet;
|
||||||
this.newError = newError;
|
this.newError = newError;
|
||||||
|
|
||||||
|
this.gasStore = new GasPriceStore(api, gasLimit);
|
||||||
|
|
||||||
if (this.isWallet) {
|
if (this.isWallet) {
|
||||||
this.wallet = props.wallet;
|
this.wallet = props.wallet;
|
||||||
this.walletContract = new Contract(this.api, walletAbi);
|
this.walletContract = new Contract(this.api, walletAbi);
|
||||||
@ -179,26 +172,6 @@ export default class TransferStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action getDefaults = () => {
|
|
||||||
Promise
|
|
||||||
.all([
|
|
||||||
this.api.parity.gasPriceHistogram(),
|
|
||||||
this.api.eth.gasPrice()
|
|
||||||
])
|
|
||||||
.then(([gasPriceHistogram, gasPrice]) => {
|
|
||||||
transaction(() => {
|
|
||||||
this.gasPrice = gasPrice.toString();
|
|
||||||
this.gasPriceDefault = gasPrice.toFormat();
|
|
||||||
this.gasPriceHistogram = gasPriceHistogram;
|
|
||||||
|
|
||||||
this.recalculate();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.warn('getDefaults', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@action onSend = () => {
|
@action onSend = () => {
|
||||||
this.onNext();
|
this.onNext();
|
||||||
this.sending = true;
|
this.sending = true;
|
||||||
@ -281,25 +254,11 @@ export default class TransferStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action _onUpdateGas = (gas) => {
|
@action _onUpdateGas = (gas) => {
|
||||||
const gasError = this._validatePositiveNumber(gas);
|
this.recalculate();
|
||||||
|
|
||||||
transaction(() => {
|
|
||||||
this.gas = gas;
|
|
||||||
this.gasError = gasError;
|
|
||||||
|
|
||||||
this.recalculate();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action _onUpdateGasPrice = (gasPrice) => {
|
@action _onUpdateGasPrice = (gasPrice) => {
|
||||||
const gasPriceError = this._validatePositiveNumber(gasPrice);
|
this.recalculate();
|
||||||
|
|
||||||
transaction(() => {
|
|
||||||
this.gasPrice = gasPrice;
|
|
||||||
this.gasPriceError = gasPriceError;
|
|
||||||
|
|
||||||
this.recalculate();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action _onUpdateRecipient = (recipient) => {
|
@action _onUpdateRecipient = (recipient) => {
|
||||||
@ -362,7 +321,7 @@ export default class TransferStore {
|
|||||||
|
|
||||||
@action recalculateGas = () => {
|
@action recalculateGas = () => {
|
||||||
if (!this.isValid) {
|
if (!this.isValid) {
|
||||||
this.gas = 0;
|
this.gasStore.setGas('0');
|
||||||
return this.recalculate();
|
return this.recalculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,28 +329,20 @@ export default class TransferStore {
|
|||||||
.estimateGas()
|
.estimateGas()
|
||||||
.then((gasEst) => {
|
.then((gasEst) => {
|
||||||
let gas = gasEst;
|
let gas = gasEst;
|
||||||
let gasLimitError = null;
|
|
||||||
|
|
||||||
if (gas.gt(DEFAULT_GAS)) {
|
if (gas.gt(DEFAULT_GAS)) {
|
||||||
gas = gas.mul(1.2);
|
gas = gas.mul(1.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gas.gte(MAX_GAS_ESTIMATION)) {
|
|
||||||
gasLimitError = ERRORS.gasException;
|
|
||||||
} else if (gas.gt(this.gasLimit)) {
|
|
||||||
gasLimitError = ERRORS.gasBlockLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction(() => {
|
transaction(() => {
|
||||||
this.gas = gas.toFixed(0);
|
this.gasStore.setEstimated(gasEst.toFixed(0));
|
||||||
this.gasEst = gasEst.toFormat();
|
this.gasStore.setGas(gas.toFixed(0));
|
||||||
this.gasLimitError = gasLimitError;
|
|
||||||
|
|
||||||
this.recalculate();
|
this.recalculate();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('etimateGas', error);
|
console.warn('etimateGas', error);
|
||||||
this.recalculate();
|
this.recalculate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -411,9 +362,9 @@ export default class TransferStore {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { gas, gasPrice, tag, valueAll, isEth, isWallet } = this;
|
const { tag, valueAll, isEth, isWallet } = this;
|
||||||
|
|
||||||
const gasTotal = new BigNumber(gasPrice || 0).mul(new BigNumber(gas || 0));
|
const gasTotal = new BigNumber(this.gasStore.price || 0).mul(new BigNumber(this.gasStore.gas || 0));
|
||||||
|
|
||||||
const availableEth = new BigNumber(balance.tokens[0].value);
|
const availableEth = new BigNumber(balance.tokens[0].value);
|
||||||
|
|
||||||
@ -453,7 +404,7 @@ export default class TransferStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transaction(() => {
|
transaction(() => {
|
||||||
this.total = this.api.util.fromWei(totalEth).toString();
|
this.total = this.api.util.fromWei(totalEth).toFixed();
|
||||||
this.totalError = totalError;
|
this.totalError = totalError;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.valueError = valueError;
|
this.valueError = valueError;
|
||||||
@ -522,8 +473,8 @@ export default class TransferStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!gas) {
|
if (!gas) {
|
||||||
options.gas = this.gas;
|
options.gas = this.gasStore.gas;
|
||||||
options.gasPrice = this.gasPrice;
|
options.gasPrice = this.gasStore.price;
|
||||||
} else {
|
} else {
|
||||||
options.gas = MAX_GAS_ESTIMATION;
|
options.gas = MAX_GAS_ESTIMATION;
|
||||||
}
|
}
|
||||||
|
@ -144,15 +144,6 @@
|
|||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gasPriceDesc {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
background: #f80;
|
background: #f80;
|
||||||
|
@ -56,10 +56,6 @@ class Transfer extends Component {
|
|||||||
|
|
||||||
store = new TransferStore(this.context.api, this.props);
|
store = new TransferStore(this.context.api, this.props);
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
this.store.getDefaults();
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { stage, extras, steps } = this.store;
|
const { stage, extras, steps } = this.store;
|
||||||
|
|
||||||
@ -186,27 +182,20 @@ class Transfer extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderExtrasPage () {
|
renderExtrasPage () {
|
||||||
if (!this.store.gasPriceHistogram) {
|
if (!this.store.gasStore.histogram) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isEth, data, dataError, gas, gasEst, gasError, gasPrice } = this.store;
|
const { isEth, data, dataError, total, totalError } = this.store;
|
||||||
const { gasPriceDefault, gasPriceError, gasPriceHistogram, total, totalError } = this.store;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Extras
|
<Extras
|
||||||
isEth={ isEth }
|
isEth={ isEth }
|
||||||
data={ data }
|
data={ data }
|
||||||
dataError={ dataError }
|
dataError={ dataError }
|
||||||
gas={ gas }
|
|
||||||
gasEst={ gasEst }
|
|
||||||
gasError={ gasError }
|
|
||||||
gasPrice={ gasPrice }
|
|
||||||
gasPriceDefault={ gasPriceDefault }
|
|
||||||
gasPriceError={ gasPriceError }
|
|
||||||
gasPriceHistogram={ gasPriceHistogram }
|
|
||||||
total={ total }
|
total={ total }
|
||||||
totalError={ totalError }
|
totalError={ totalError }
|
||||||
|
gasStore={ this.store.gasStore }
|
||||||
onChange={ this.store.onUpdateDetails } />
|
onChange={ this.store.onUpdateDetails } />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -263,15 +252,15 @@ class Transfer extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderWarning () {
|
renderWarning () {
|
||||||
const { gasLimitError } = this.store;
|
const { errorEstimated } = this.store.gasStore;
|
||||||
|
|
||||||
if (!gasLimitError) {
|
if (!errorEstimated) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.warning }>
|
<div className={ styles.warning }>
|
||||||
{ gasLimitError }
|
{ errorEstimated }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,8 @@ import { sha3 } from '~/api/util/sha3';
|
|||||||
import Contract from '~/api/contract';
|
import Contract from '~/api/contract';
|
||||||
import Contracts from '~/contracts';
|
import Contracts from '~/contracts';
|
||||||
|
|
||||||
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '~/contracts/verification';
|
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '~/contracts/sms-verification';
|
||||||
import checkIfTxFailed from '../../util/check-if-tx-failed';
|
import { checkIfTxFailed, waitForConfirmations } from '~/util/tx';
|
||||||
import waitForConfirmations from '../../util/wait-for-block-confirmations';
|
|
||||||
|
|
||||||
export const LOADING = 'fetching-contract';
|
export const LOADING = 'fetching-contract';
|
||||||
export const QUERY_DATA = 'query-data';
|
export const QUERY_DATA = 'query-data';
|
||||||
|
@ -92,7 +92,7 @@ function findImports (path) {
|
|||||||
return { error: 'File not found' };
|
return { error: 'File not found' };
|
||||||
}
|
}
|
||||||
|
|
||||||
function compile (data) {
|
function compile (data, optimized = 1) {
|
||||||
const { sourcecode, build } = data;
|
const { sourcecode, build } = data;
|
||||||
const { longVersion } = build;
|
const { longVersion } = build;
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ function compile (data) {
|
|||||||
'': sourcecode
|
'': sourcecode
|
||||||
};
|
};
|
||||||
|
|
||||||
const compiled = compiler.compile({ sources: input }, 0, findImports);
|
const compiled = compiler.compile({ sources: input }, optimized, findImports);
|
||||||
|
|
||||||
self.lastCompile = {
|
self.lastCompile = {
|
||||||
version: longVersion, result: compiled,
|
version: longVersion, result: compiled,
|
||||||
|
@ -17,12 +17,10 @@
|
|||||||
import { isEqual, uniq } from 'lodash';
|
import { isEqual, uniq } from 'lodash';
|
||||||
|
|
||||||
import Contract from '~/api/contract';
|
import Contract from '~/api/contract';
|
||||||
import { wallet as WALLET_ABI } from '~/contracts/abi';
|
|
||||||
import { bytesToHex, toHex } from '~/api/util/format';
|
import { bytesToHex, toHex } from '~/api/util/format';
|
||||||
|
|
||||||
import { ERROR_CODES } from '~/api/transport/error';
|
import { ERROR_CODES } from '~/api/transport/error';
|
||||||
import { MAX_GAS_ESTIMATION } from '../../util/constants';
|
import { wallet as WALLET_ABI } from '~/contracts/abi';
|
||||||
|
import { MAX_GAS_ESTIMATION } from '~/util/constants';
|
||||||
import WalletsUtils from '~/util/wallets';
|
import WalletsUtils from '~/util/wallets';
|
||||||
|
|
||||||
import { newError } from '~/ui/Errors/actions';
|
import { newError } from '~/ui/Errors/actions';
|
||||||
@ -58,7 +56,7 @@ function modifyOperation (method, address, owner, operation) {
|
|||||||
contract.instance[method]
|
contract.instance[method]
|
||||||
.estimateGas(options, values)
|
.estimateGas(options, values)
|
||||||
.then((gas) => {
|
.then((gas) => {
|
||||||
options.gas = gas;
|
options.gas = gas.mul(1.2);
|
||||||
return contract.instance[method].postTransaction(options, values);
|
return contract.instance[method].postTransaction(options, values);
|
||||||
})
|
})
|
||||||
.then((requestId) => {
|
.then((requestId) => {
|
||||||
|
@ -22,12 +22,11 @@ import IconButton from 'material-ui/IconButton';
|
|||||||
import AddIcon from 'material-ui/svg-icons/content/add';
|
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 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';
|
||||||
|
|
||||||
import { ABI_TYPES } from '~/util/abi';
|
import { ABI_TYPES } from '~/util/abi';
|
||||||
import { fromWei, toWei } from '~/api/util/wei';
|
|
||||||
|
|
||||||
import styles from './typedInput.css';
|
import styles from './typedInput.css';
|
||||||
|
|
||||||
|
@ -15,3 +15,13 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.columns {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: relative;
|
||||||
|
}
|
@ -29,10 +29,7 @@ import {
|
|||||||
import Slider from 'material-ui/Slider';
|
import Slider from 'material-ui/Slider';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import componentStyles from './gasPriceSelector.css';
|
import styles from './gasPriceSelector.css';
|
||||||
import mainStyles from '../transfer.css';
|
|
||||||
|
|
||||||
const styles = Object.assign({}, mainStyles, componentStyles);
|
|
||||||
|
|
||||||
const COLORS = {
|
const COLORS = {
|
||||||
default: 'rgba(255, 99, 132, 0.2)',
|
default: 'rgba(255, 99, 132, 0.2)',
|
||||||
@ -194,10 +191,7 @@ class CustomizedShape extends Component {
|
|||||||
|
|
||||||
class CustomTooltip extends Component {
|
class CustomTooltip extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
gasPriceHistogram: PropTypes.shape({
|
gasPriceHistogram: PropTypes.object.isRequired,
|
||||||
bucketBounds: PropTypes.array.isRequired,
|
|
||||||
counts: PropTypes.array.isRequired
|
|
||||||
}).isRequired,
|
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
payload: PropTypes.array,
|
payload: PropTypes.array,
|
||||||
label: PropTypes.number,
|
label: PropTypes.number,
|
||||||
@ -231,12 +225,16 @@ class CustomTooltip extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TOOL_STYLE = {
|
||||||
|
color: 'rgba(255,255,255,0.5)',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
|
padding: '0 0.5em',
|
||||||
|
fontSize: '0.75em'
|
||||||
|
};
|
||||||
|
|
||||||
export default class GasPriceSelector extends Component {
|
export default class GasPriceSelector extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
gasPriceHistogram: PropTypes.shape({
|
gasPriceHistogram: PropTypes.object.isRequired,
|
||||||
bucketBounds: PropTypes.array.isRequired,
|
|
||||||
counts: PropTypes.array.isRequired
|
|
||||||
}).isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
|
|
||||||
gasPrice: PropTypes.oneOfType([
|
gasPrice: PropTypes.oneOfType([
|
||||||
@ -287,21 +285,23 @@ export default class GasPriceSelector extends Component {
|
|||||||
renderSlider () {
|
renderSlider () {
|
||||||
const { sliderValue } = this.state;
|
const { sliderValue } = this.state;
|
||||||
|
|
||||||
return (<div className={ styles.columns }>
|
return (
|
||||||
<Slider
|
<div className={ styles.columns }>
|
||||||
min={ 0 }
|
<Slider
|
||||||
max={ 1 }
|
min={ 0 }
|
||||||
value={ sliderValue }
|
max={ 1 }
|
||||||
onChange={ this.onEditGasPriceSlider }
|
value={ sliderValue }
|
||||||
style={ {
|
onChange={ this.onEditGasPriceSlider }
|
||||||
flex: 1,
|
style={ {
|
||||||
padding: '0 0.3em'
|
flex: 1,
|
||||||
} }
|
padding: '0 0.3em'
|
||||||
sliderStyle={ {
|
} }
|
||||||
marginBottom: 12
|
sliderStyle={ {
|
||||||
} }
|
marginBottom: 12
|
||||||
/>
|
} }
|
||||||
</div>);
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderChart () {
|
renderChart () {
|
||||||
@ -316,85 +316,83 @@ export default class GasPriceSelector extends Component {
|
|||||||
const countIndex = Math.max(0, Math.min(selectedIndex, gasPriceHistogram.counts.length - 1));
|
const countIndex = Math.max(0, Math.min(selectedIndex, gasPriceHistogram.counts.length - 1));
|
||||||
const selectedCount = countModifier(gasPriceHistogram.counts[countIndex]);
|
const selectedCount = countModifier(gasPriceHistogram.counts[countIndex]);
|
||||||
|
|
||||||
return (<div className={ styles.columns }>
|
return (
|
||||||
<div style={ { flex: 1, height } }>
|
<div className={ styles.columns }>
|
||||||
<div className={ styles.chart }>
|
<div style={ { flex: 1, height } }>
|
||||||
<ResponsiveContainer
|
<div className={ styles.chart }>
|
||||||
height={ height }
|
<ResponsiveContainer
|
||||||
>
|
height={ height }
|
||||||
<ScatterChart
|
|
||||||
margin={ { top: 0, right: 0, left: 0, bottom: 0 } }
|
|
||||||
>
|
>
|
||||||
<Scatter
|
<ScatterChart
|
||||||
data={ [
|
margin={ { top: 0, right: 0, left: 0, bottom: 0 } }
|
||||||
{ x: sliderValue, y: 0 },
|
>
|
||||||
{ x: sliderValue, y: selectedCount },
|
<Scatter
|
||||||
{ x: sliderValue, y: chartData.yDomain[1] }
|
data={ [
|
||||||
] }
|
{ x: sliderValue, y: 0 },
|
||||||
shape={ <CustomizedShape showValue={ selectedCount } /> }
|
{ x: sliderValue, y: selectedCount },
|
||||||
line
|
{ x: sliderValue, y: chartData.yDomain[1] }
|
||||||
isAnimationActive={ false }
|
] }
|
||||||
/>
|
shape={ <CustomizedShape showValue={ selectedCount } /> }
|
||||||
|
line
|
||||||
|
isAnimationActive={ false }
|
||||||
|
/>
|
||||||
|
|
||||||
<XAxis
|
<XAxis
|
||||||
hide
|
hide
|
||||||
height={ 0 }
|
height={ 0 }
|
||||||
dataKey='x'
|
dataKey='x'
|
||||||
domain={ [0, 1] }
|
domain={ [0, 1] }
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
hide
|
hide
|
||||||
width={ 0 }
|
width={ 0 }
|
||||||
dataKey='y'
|
dataKey='y'
|
||||||
domain={ chartData.yDomain }
|
domain={ chartData.yDomain }
|
||||||
/>
|
/>
|
||||||
</ScatterChart>
|
</ScatterChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={ styles.chart }>
|
<div className={ styles.chart }>
|
||||||
<ResponsiveContainer
|
<ResponsiveContainer
|
||||||
height={ height }
|
height={ height }
|
||||||
>
|
|
||||||
<BarChart
|
|
||||||
data={ chartData.values }
|
|
||||||
margin={ { top: 0, right: 0, left: 0, bottom: 0 } }
|
|
||||||
barCategoryGap={ 1 }
|
|
||||||
ref='barChart'
|
|
||||||
>
|
>
|
||||||
<Bar
|
<BarChart
|
||||||
dataKey='value'
|
data={ chartData.values }
|
||||||
stroke={ COLORS.line }
|
margin={ { top: 0, right: 0, left: 0, bottom: 0 } }
|
||||||
onClick={ this.onClickGasPrice }
|
barCategoryGap={ 1 }
|
||||||
shape={ <CustomBar selected={ selectedIndex } onClick={ this.onClickGasPrice } /> }
|
ref='barChart'
|
||||||
/>
|
>
|
||||||
|
<Bar
|
||||||
|
dataKey='value'
|
||||||
|
stroke={ COLORS.line }
|
||||||
|
onClick={ this.onClickGasPrice }
|
||||||
|
shape={ <CustomBar selected={ selectedIndex } onClick={ this.onClickGasPrice } /> }
|
||||||
|
/>
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
wrapperStyle={ {
|
wrapperStyle={ TOOL_STYLE }
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
cursor={ this.renderCustomCursor() }
|
||||||
padding: '0 0.5em',
|
content={ <CustomTooltip gasPriceHistogram={ gasPriceHistogram } /> }
|
||||||
fontSize: '0.9em'
|
/>
|
||||||
} }
|
|
||||||
cursor={ this.renderCustomCursor() }
|
|
||||||
content={ <CustomTooltip gasPriceHistogram={ gasPriceHistogram } /> }
|
|
||||||
/>
|
|
||||||
|
|
||||||
<XAxis
|
<XAxis
|
||||||
hide
|
hide
|
||||||
dataKey='index'
|
dataKey='index'
|
||||||
type='category'
|
type='category'
|
||||||
domain={ chartData.xDomain }
|
domain={ chartData.xDomain }
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
hide
|
hide
|
||||||
type='number'
|
type='number'
|
||||||
domain={ chartData.yDomain }
|
domain={ chartData.yDomain }
|
||||||
/>
|
/>
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCustomCursor = () => {
|
renderCustomCursor = () => {
|
@ -14,11 +14,36 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.signer {
|
|
||||||
|
.columns {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.graphColumn {
|
||||||
|
flex: 65;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mainContainer {
|
.editColumn {
|
||||||
|
flex: 35;
|
||||||
|
padding-left: 1em;
|
||||||
|
justify-ontent: space-around;
|
||||||
|
padding-bottom: 12;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gasPriceDesc {
|
||||||
|
font-size: 0.75em;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
98
js/src/ui/GasPriceEditor/gasPriceEditor.js
Normal file
98
js/src/ui/GasPriceEditor/gasPriceEditor.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 React, { Component, PropTypes } from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import Input from '../Form/Input';
|
||||||
|
import GasPriceSelector from './GasPriceSelector';
|
||||||
|
import Store from './store';
|
||||||
|
|
||||||
|
import styles from './gasPriceEditor.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class GasPriceEditor extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
store: PropTypes.object.isRequired,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
static Store = Store;
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { children, store } = this.props;
|
||||||
|
const { estimated, priceDefault, price, gas, histogram, errorGas, errorPrice } = store;
|
||||||
|
|
||||||
|
const gasLabel = `gas (estimated: ${new BigNumber(estimated).toFormat()})`;
|
||||||
|
const priceLabel = `price (current: ${new BigNumber(priceDefault).toFormat()})`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.columns }>
|
||||||
|
<div className={ styles.graphColumn }>
|
||||||
|
<GasPriceSelector
|
||||||
|
gasPriceHistogram={ histogram }
|
||||||
|
gasPrice={ price }
|
||||||
|
onChange={ this.onEditGasPrice } />
|
||||||
|
<div className={ styles.gasPriceDesc }>
|
||||||
|
You can choose the gas price based on the
|
||||||
|
distribution of recent included transaction gas prices.
|
||||||
|
The lower the gas price is, the cheaper the transaction will
|
||||||
|
be. The higher the gas price is, the faster it should
|
||||||
|
get mined by the network.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={ styles.editColumn }>
|
||||||
|
<div className={ styles.row }>
|
||||||
|
<Input
|
||||||
|
label={ gasLabel }
|
||||||
|
hint='the amount of gas to use for the transaction'
|
||||||
|
error={ errorGas }
|
||||||
|
value={ gas }
|
||||||
|
onChange={ this.onEditGas } />
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={ priceLabel }
|
||||||
|
hint='the price of gas to use for the transaction'
|
||||||
|
error={ errorPrice }
|
||||||
|
value={ price }
|
||||||
|
onChange={ this.onEditGasPrice } />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={ styles.row }>
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditGas = (event, gas) => {
|
||||||
|
const { store, onChange } = this.props;
|
||||||
|
|
||||||
|
store.setGas(gas);
|
||||||
|
onChange && onChange('gas', gas);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditGasPrice = (event, price) => {
|
||||||
|
const { store, onChange } = this.props;
|
||||||
|
|
||||||
|
store.setPrice(price);
|
||||||
|
onChange && onChange('gasPrice', price);
|
||||||
|
}
|
||||||
|
}
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './Animated';
|
export default from './gasPriceEditor';
|
105
js/src/ui/GasPriceEditor/store.js
Normal file
105
js/src/ui/GasPriceEditor/store.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 { action, observable, transaction } from 'mobx';
|
||||||
|
|
||||||
|
import { ERRORS, validatePositiveNumber } from '~/util/validation';
|
||||||
|
import { DEFAULT_GAS, DEFAULT_GASPRICE, MAX_GAS_ESTIMATION } from '~/util/constants';
|
||||||
|
|
||||||
|
export default class GasPriceEditor {
|
||||||
|
@observable errorEstimated = null;
|
||||||
|
@observable errorGas = null;
|
||||||
|
@observable errorPrice = null;
|
||||||
|
@observable estimated = DEFAULT_GAS;
|
||||||
|
@observable histogram = null;
|
||||||
|
@observable price = DEFAULT_GASPRICE;
|
||||||
|
@observable priceDefault = DEFAULT_GASPRICE;
|
||||||
|
@observable gas = DEFAULT_GAS;
|
||||||
|
@observable gasLimit = 0;
|
||||||
|
|
||||||
|
constructor (api, gasLimit, loadDefaults = true) {
|
||||||
|
this._api = api;
|
||||||
|
this.gasLimit = gasLimit;
|
||||||
|
|
||||||
|
if (loadDefaults) {
|
||||||
|
this.loadDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setEstimated = (estimated) => {
|
||||||
|
transaction(() => {
|
||||||
|
const bn = new BigNumber(estimated);
|
||||||
|
|
||||||
|
this.estimated = estimated;
|
||||||
|
|
||||||
|
if (bn.gte(MAX_GAS_ESTIMATION)) {
|
||||||
|
this.errorEstimated = ERRORS.gasException;
|
||||||
|
} else if (bn.gte(this.gasLimit)) {
|
||||||
|
this.errorEstimated = ERRORS.gasBlockLimit;
|
||||||
|
} else {
|
||||||
|
this.errorEstimated = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setHistogram = (gasHistogram) => {
|
||||||
|
this.histogram = gasHistogram;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setPrice = (price) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.errorPrice = validatePositiveNumber(price).numberError;
|
||||||
|
this.price = price;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setGas = (gas) => {
|
||||||
|
transaction(() => {
|
||||||
|
const { numberError } = validatePositiveNumber(gas);
|
||||||
|
const bn = new BigNumber(gas);
|
||||||
|
|
||||||
|
this.gas = gas;
|
||||||
|
|
||||||
|
if (numberError) {
|
||||||
|
this.errorGas = numberError;
|
||||||
|
} else if (bn.gte(this.gasLimit)) {
|
||||||
|
this.errorGas = ERRORS.gasBlockLimit;
|
||||||
|
} else {
|
||||||
|
this.errorGas = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action loadDefaults () {
|
||||||
|
Promise
|
||||||
|
.all([
|
||||||
|
this._api.parity.gasPriceHistogram(),
|
||||||
|
this._api.eth.gasPrice()
|
||||||
|
])
|
||||||
|
.then(([gasPriceHistogram, gasPrice]) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.setPrice(gasPrice.toFixed(0));
|
||||||
|
this.setHistogram(gasPriceHistogram);
|
||||||
|
|
||||||
|
this.priceDefault = gasPrice.toFixed();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn('getDefaults', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@ import { connect } from 'react-redux';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { LinearProgress } from 'material-ui';
|
import { LinearProgress } from 'material-ui';
|
||||||
|
|
||||||
import { txLink } from '../../3rdparty/etherscan/links';
|
import { txLink } from '~/3rdparty/etherscan/links';
|
||||||
import ShortenedHash from '../ShortenedHash';
|
import ShortenedHash from '../ShortenedHash';
|
||||||
|
|
||||||
import styles from './txHash.css';
|
import styles from './txHash.css';
|
||||||
|
@ -20,7 +20,7 @@ import { connect } from 'react-redux';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
import { txLink, addressLink } from '../../3rdparty/etherscan/links';
|
import { txLink, addressLink } from '~/3rdparty/etherscan/links';
|
||||||
|
|
||||||
import IdentityIcon from '../IdentityIcon';
|
import IdentityIcon from '../IdentityIcon';
|
||||||
import IdentityName from '../IdentityName';
|
import IdentityName from '../IdentityName';
|
||||||
|
@ -31,6 +31,7 @@ import CopyToClipboard from './CopyToClipboard';
|
|||||||
import Editor from './Editor';
|
import Editor from './Editor';
|
||||||
import Errors from './Errors';
|
import Errors from './Errors';
|
||||||
import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select, RadioButtons } from './Form';
|
import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select, RadioButtons } from './Form';
|
||||||
|
import GasPriceEditor from './GasPriceEditor';
|
||||||
import IdentityIcon from './IdentityIcon';
|
import IdentityIcon from './IdentityIcon';
|
||||||
import IdentityName from './IdentityName';
|
import IdentityName from './IdentityName';
|
||||||
import Loading from './Loading';
|
import Loading from './Loading';
|
||||||
@ -67,7 +68,7 @@ export {
|
|||||||
Errors,
|
Errors,
|
||||||
Form,
|
Form,
|
||||||
FormWrap,
|
FormWrap,
|
||||||
TypedInput,
|
GasPriceEditor,
|
||||||
Input,
|
Input,
|
||||||
InputAddress,
|
InputAddress,
|
||||||
InputAddressSelect,
|
InputAddressSelect,
|
||||||
@ -91,5 +92,6 @@ export {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
Tooltips,
|
Tooltips,
|
||||||
TxHash,
|
TxHash,
|
||||||
TxList
|
TxList,
|
||||||
|
TypedInput
|
||||||
};
|
};
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright 2015, 2016 Ethcore (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 checkIfTxFailed = (api, tx, gasSent) => {
|
|
||||||
return api.pollMethod('eth_getTransactionReceipt', tx)
|
|
||||||
.then((receipt) => {
|
|
||||||
// TODO: Right now, there's no way to tell wether the EVM code crashed.
|
|
||||||
// Because you usually send a bit more gas than estimated (to make sure
|
|
||||||
// it gets mined quickly), we transaction probably failed if all the gas
|
|
||||||
// has been used up.
|
|
||||||
return receipt.gasUsed.eq(gasSent);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default checkIfTxFailed;
|
|
@ -1,19 +0,0 @@
|
|||||||
// Copyright 2015, 2016 Ethcore (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 (chain) => {
|
|
||||||
return chain === 'morden' || chain === 'ropsten' || chain === 'testnet';
|
|
||||||
};
|
|
@ -18,7 +18,18 @@ const isValidReceipt = (receipt) => {
|
|||||||
return receipt && receipt.blockNumber && receipt.blockNumber.gt(0);
|
return receipt && receipt.blockNumber && receipt.blockNumber.gt(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const waitForConfirmations = (api, tx, confirmations) => {
|
export function checkIfTxFailed (api, tx, gasSent) {
|
||||||
|
return api.pollMethod('eth_getTransactionReceipt', tx)
|
||||||
|
.then((receipt) => {
|
||||||
|
// TODO: Right now, there's no way to tell wether the EVM code crashed.
|
||||||
|
// Because you usually send a bit more gas than estimated (to make sure
|
||||||
|
// it gets mined quickly), we transaction probably failed if all the gas
|
||||||
|
// has been used up.
|
||||||
|
return receipt.gasUsed.eq(gasSent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitForConfirmations (api, tx, confirmations) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
api.pollMethod('eth_getTransactionReceipt', tx, isValidReceipt)
|
api.pollMethod('eth_getTransactionReceipt', tx, isValidReceipt)
|
||||||
.then((receipt) => {
|
.then((receipt) => {
|
||||||
@ -39,6 +50,4 @@ const waitForConfirmations = (api, tx, confirmations) => {
|
|||||||
.catch(reject);
|
.catch(reject);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
export default waitForConfirmations;
|
|
@ -20,6 +20,7 @@ import util from '~/api/util';
|
|||||||
|
|
||||||
export const ERRORS = {
|
export const ERRORS = {
|
||||||
invalidAddress: 'address is an invalid network address',
|
invalidAddress: 'address is an invalid network address',
|
||||||
|
invalidAmount: 'the supplied amount should be a valid positive number',
|
||||||
duplicateAddress: 'the address is already in your address book',
|
duplicateAddress: 'the address is already in your address book',
|
||||||
invalidChecksum: 'address has failed the checksum formatting',
|
invalidChecksum: 'address has failed the checksum formatting',
|
||||||
invalidName: 'name should not be blank and longer than 2',
|
invalidName: 'name should not be blank and longer than 2',
|
||||||
@ -27,7 +28,9 @@ export const ERRORS = {
|
|||||||
invalidCode: 'code should be the compiled hex string',
|
invalidCode: 'code should be the compiled hex string',
|
||||||
invalidNumber: 'invalid number format',
|
invalidNumber: 'invalid number format',
|
||||||
negativeNumber: 'input number should be positive',
|
negativeNumber: 'input number should be positive',
|
||||||
decimalNumber: 'input number should not contain decimals'
|
decimalNumber: 'input number should not contain decimals',
|
||||||
|
gasException: 'the transaction will throw an exception with the current values',
|
||||||
|
gasBlockLimit: 'the transaction execution will exceed the block gas limit'
|
||||||
};
|
};
|
||||||
|
|
||||||
export function validateAbi (abi, api) {
|
export function validateAbi (abi, api) {
|
||||||
@ -133,6 +136,25 @@ export function validateName (name) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function validatePositiveNumber (number) {
|
||||||
|
let numberError = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const v = new BigNumber(number);
|
||||||
|
|
||||||
|
if (v.lt(0)) {
|
||||||
|
numberError = ERRORS.invalidAmount;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
numberError = ERRORS.invalidAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
number,
|
||||||
|
numberError
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function validateUint (value) {
|
export function validateUint (value) {
|
||||||
let valueError = null;
|
let valueError = null;
|
||||||
|
|
||||||
|
@ -15,9 +15,6 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.transactions {
|
|
||||||
}
|
|
||||||
|
|
||||||
.infonone {
|
.infonone {
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
import etherscan from '../../../3rdparty/etherscan';
|
import etherscan from '~/3rdparty/etherscan';
|
||||||
import { Container, TxList } from '~/ui';
|
import { Container, TxList } from '~/ui';
|
||||||
|
|
||||||
import styles from './transactions.css';
|
import styles from './transactions.css';
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.account {
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnicon {
|
.btnicon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
@ -97,7 +97,7 @@ class Account extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.account }>
|
<div>
|
||||||
{ this.renderDeleteDialog(account) }
|
{ this.renderDeleteDialog(account) }
|
||||||
{ this.renderEditDialog(account) }
|
{ this.renderEditDialog(account) }
|
||||||
{ this.renderFundDialog() }
|
{ this.renderFundDialog() }
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.accounts {
|
|
||||||
}
|
|
||||||
|
|
||||||
.accountTooltip {
|
.accountTooltip {
|
||||||
top: 13.3em;
|
top: 13.3em;
|
||||||
|
@ -82,7 +82,7 @@ class Accounts extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className={ styles.accounts }>
|
<div>
|
||||||
{ this.renderNewDialog() }
|
{ this.renderNewDialog() }
|
||||||
{ this.renderNewWalletDialog() }
|
{ this.renderNewWalletDialog() }
|
||||||
{ this.renderActionbar() }
|
{ this.renderActionbar() }
|
||||||
|
@ -14,37 +14,37 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.address {
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete .hero {
|
.delete {
|
||||||
padding-bottom: 1em;
|
.hero {
|
||||||
}
|
padding-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.delete .info {
|
.info {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete .icon {
|
.icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete .nameinfo {
|
.nameinfo {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete .header {
|
.header {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
padding-bottom: 0.25em;
|
padding-bottom: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete .address {
|
.address {
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete .description {
|
.description {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,6 @@ import Transactions from '../Account/Transactions';
|
|||||||
import Delete from './Delete';
|
import Delete from './Delete';
|
||||||
import { setVisibleAccounts } from '~/redux/providers/personalActions';
|
import { setVisibleAccounts } from '~/redux/providers/personalActions';
|
||||||
|
|
||||||
import styles from './address.css';
|
|
||||||
|
|
||||||
class Address extends Component {
|
class Address extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired,
|
api: PropTypes.object.isRequired,
|
||||||
@ -85,7 +83,7 @@ class Address extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.address }>
|
<div>
|
||||||
{ this.renderEditDialog(contact) }
|
{ this.renderEditDialog(contact) }
|
||||||
{ this.renderActionbar(contact) }
|
{ this.renderActionbar(contact) }
|
||||||
<Delete
|
<Delete
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.addresses {
|
|
||||||
}
|
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -26,21 +24,21 @@
|
|||||||
flex: 0 1 50%;
|
flex: 0 1 50%;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
|
|
||||||
.address:nth-child(odd)>div {
|
&:nth-child(odd)>div {
|
||||||
padding-right: 0.5em !important;
|
padding-right: 0.5em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address:nth-child(even)>div {
|
&:nth-child(even)>div {
|
||||||
padding-left: 0.5em !important;
|
padding-left: 0.5em !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty {
|
.empty {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
|
||||||
|
|
||||||
.empty div {
|
div {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ class Addresses extends Component {
|
|||||||
const { searchValues, sortOrder } = this.state;
|
const { searchValues, sortOrder } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.addresses }>
|
<div>
|
||||||
{ this.renderActionbar() }
|
{ this.renderActionbar() }
|
||||||
{ this.renderAddAddress() }
|
{ this.renderAddAddress() }
|
||||||
<Page>
|
<Page>
|
||||||
|
@ -19,7 +19,6 @@ import { connect } from 'react-redux';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import ActionCompareArrows from 'material-ui/svg-icons/action/compare-arrows';
|
import ActionCompareArrows from 'material-ui/svg-icons/action/compare-arrows';
|
||||||
import ActionDashboard from 'material-ui/svg-icons/action/dashboard';
|
import ActionDashboard from 'material-ui/svg-icons/action/dashboard';
|
||||||
// import CommunicationVpnKey from 'material-ui/svg-icons/communication/vpn-key';
|
|
||||||
import HardwareDesktopMac from 'material-ui/svg-icons/hardware/desktop-mac';
|
import HardwareDesktopMac from 'material-ui/svg-icons/hardware/desktop-mac';
|
||||||
import NotificationVpnLock from 'material-ui/svg-icons/notification/vpn-lock';
|
import NotificationVpnLock from 'material-ui/svg-icons/notification/vpn-lock';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
|
|
||||||
import { IdentityIcon, IdentityName, Input, InputAddress } from '~/ui';
|
import { IdentityIcon, IdentityName, Input, InputAddress } from '~/ui';
|
||||||
import ShortenedHash from '~/ui/ShortenedHash';
|
import ShortenedHash from '~/ui/ShortenedHash';
|
||||||
import { txLink } from '../../../../3rdparty/etherscan/links';
|
import { txLink } from '~/3rdparty/etherscan/links';
|
||||||
|
|
||||||
import styles from '../../contract.css';
|
import styles from '../../contract.css';
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { uniq } from 'lodash';
|
||||||
|
|
||||||
import { Container } from '~/ui';
|
import { Container } from '~/ui';
|
||||||
|
|
||||||
@ -38,7 +39,10 @@ export default class Events extends Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = events.map((event) => {
|
const eventsKey = uniq(events.map((e) => e.key));
|
||||||
|
const list = eventsKey.map((eventKey) => {
|
||||||
|
const event = events.find((e) => e.key === eventKey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Event
|
<Event
|
||||||
key={ event.key }
|
key={ event.key }
|
||||||
|
@ -15,26 +15,26 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.contract {
|
|
||||||
}
|
|
||||||
|
|
||||||
.events {
|
.events {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
}
|
|
||||||
|
|
||||||
.events tr {
|
tr {
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.event {
|
.event {
|
||||||
}
|
td {
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
|
||||||
.event td {
|
div {
|
||||||
vertical-align: top;
|
white-space: nowrap;
|
||||||
padding: 1em 0.5em;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.txhash {
|
.txhash {
|
||||||
@ -47,10 +47,6 @@
|
|||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.event td div {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mined {
|
.mined {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ class Contract extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.contract }>
|
<div>
|
||||||
{ this.renderActionbar(account) }
|
{ this.renderActionbar(account) }
|
||||||
{ this.renderDeleteDialog(account) }
|
{ this.renderDeleteDialog(account) }
|
||||||
{ this.renderEditDialog(account) }
|
{ this.renderEditDialog(account) }
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/* Copyright 2015, 2016 Ethcore (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/>.
|
|
||||||
*/
|
|
||||||
.contracts {
|
|
||||||
}
|
|
@ -28,8 +28,6 @@ import { setVisibleAccounts } from '~/redux/providers/personalActions';
|
|||||||
|
|
||||||
import List from '../Accounts/List';
|
import List from '../Accounts/List';
|
||||||
|
|
||||||
import styles from './contracts.css';
|
|
||||||
|
|
||||||
class Contracts extends Component {
|
class Contracts extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired
|
api: PropTypes.object.isRequired
|
||||||
@ -80,7 +78,7 @@ class Contracts extends Component {
|
|||||||
const { searchValues, sortOrder } = this.state;
|
const { searchValues, sortOrder } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.contracts }>
|
<div>
|
||||||
{ this.renderActionbar() }
|
{ this.renderActionbar() }
|
||||||
{ this.renderAddContract() }
|
{ this.renderAddContract() }
|
||||||
{ this.renderAddContract() }
|
{ this.renderAddContract() }
|
||||||
@ -159,7 +157,6 @@ class Contracts extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Actionbar
|
<Actionbar
|
||||||
className={ styles.toolbar }
|
|
||||||
title='Contracts'
|
title='Contracts'
|
||||||
buttons={ buttons } />
|
buttons={ buttons } />
|
||||||
);
|
);
|
||||||
|
@ -15,9 +15,6 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.layout {
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@ -35,31 +32,24 @@
|
|||||||
padding: 16px 2em !important;
|
padding: 16px 2em !important;
|
||||||
line-height: 24px !important;
|
line-height: 24px !important;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
}
|
|
||||||
|
|
||||||
.tabactive {
|
&>div {
|
||||||
}
|
height: 24px !important;
|
||||||
|
|
||||||
.tab>div,
|
&>div {
|
||||||
.tabactive>div {
|
display: inline-block !important;
|
||||||
height: 24px !important;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab>div>div,
|
svg {
|
||||||
.tabactive>div>div {
|
margin-right: 0.5em;
|
||||||
display: inline-block !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab svg,
|
.menu {
|
||||||
.tabactive svg {
|
vertical-align: top;
|
||||||
margin-right: 0.5em;
|
display: inline-block;
|
||||||
margin-bottom: 0 !important;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.tab .menu,
|
|
||||||
.tabactive .menu {
|
|
||||||
vertical-align: top;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.imageIcon {
|
.imageIcon {
|
||||||
@ -68,6 +58,8 @@
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabactive .imageIcon {
|
.tabactive {
|
||||||
opacity: 1;
|
.imageIcon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ export default class Settings extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.layout }>
|
<div>
|
||||||
<Actionbar title='settings' className={ styles.bar }>
|
<Actionbar title='settings' className={ styles.bar }>
|
||||||
<Tabs className={ styles.tabs } value={ hash }>
|
<Tabs className={ styles.tabs } value={ hash }>
|
||||||
{ this.renderTab(hash, 'views', <ImageRemoveRedEye />) }
|
{ this.renderTab(hash, 'views', <ImageRemoveRedEye />) }
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import { addressLink } from '../../../../../3rdparty/etherscan/links';
|
import { addressLink } from '~/3rdparty/etherscan/links';
|
||||||
import styles from './AccountLink.css';
|
import styles from './AccountLink.css';
|
||||||
|
|
||||||
export default class AccountLink extends Component {
|
export default class AccountLink extends Component {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import { txLink } from '../../../../3rdparty/etherscan/links';
|
import { txLink } from '~/3rdparty/etherscan/links';
|
||||||
|
|
||||||
export default class TxHashLink extends Component {
|
export default class TxHashLink extends Component {
|
||||||
|
|
||||||
|
@ -23,9 +23,6 @@
|
|||||||
width: $embedWidth;
|
width: $embedWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pending {
|
|
||||||
}
|
|
||||||
|
|
||||||
.none {
|
.none {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ class Embedded extends Component {
|
|||||||
const items = pending.sort(this._sortRequests).map(this.renderPending);
|
const items = pending.sort(this._sortRequests).map(this.renderPending);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.pending }>
|
<div>
|
||||||
{ items }
|
{ items }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -15,12 +15,6 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.request {
|
|
||||||
}
|
|
||||||
|
|
||||||
.noRequestsMsg {
|
.noRequestsMsg {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.items {
|
|
||||||
}
|
|
||||||
|
@ -98,9 +98,7 @@ class RequestsPage extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container title='Pending Requests'>
|
<Container title='Pending Requests'>
|
||||||
<div className={ styles.items }>
|
{ items }
|
||||||
{ items }
|
|
||||||
</div>
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -111,7 +109,6 @@ class RequestsPage extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RequestPending
|
<RequestPending
|
||||||
className={ styles.request }
|
|
||||||
onConfirm={ actions.startConfirmRequest }
|
onConfirm={ actions.startConfirmRequest }
|
||||||
onReject={ actions.startRejectRequest }
|
onReject={ actions.startRejectRequest }
|
||||||
isSending={ isSending || false }
|
isSending={ isSending || false }
|
||||||
|
@ -19,12 +19,10 @@ import React, { Component } from 'react';
|
|||||||
import { Actionbar } from '~/ui';
|
import { Actionbar } from '~/ui';
|
||||||
import RequestsPage from './containers/RequestsPage';
|
import RequestsPage from './containers/RequestsPage';
|
||||||
|
|
||||||
import styles from './signer.css';
|
|
||||||
|
|
||||||
export default class Signer extends Component {
|
export default class Signer extends Component {
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className={ styles.signer }>
|
<div>
|
||||||
<Actionbar
|
<Actionbar
|
||||||
title='Trusted Signer' />
|
title='Trusted Signer' />
|
||||||
<RequestsPage />
|
<RequestsPage />
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
/* Copyright 2015, 2016 Ethcore (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/>.
|
|
||||||
*/
|
|
||||||
/* todo [adgo] - make local */
|
|
||||||
:global .transition-appear {
|
|
||||||
opacity: 0.01;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .transition-appear.transition-appear-active {
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity .3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .transition-enter {
|
|
||||||
opacity: 0.01;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .transition-enter.transition-enter-active {
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity .3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .transition-leave {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .transition-leave.transition-leave-active {
|
|
||||||
opacity: 0.01;
|
|
||||||
transition: opacity .3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .absoluteAnimationContainer {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global .absoluteAnimationContainer > .transition-leave {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright 2015, 2016 Ethcore (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 AnimateChildren from './children';
|
|
||||||
|
|
||||||
export default Wrapped => class Animated extends Component {
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<AnimateChildren>
|
|
||||||
<Wrapped { ...this.props } />
|
|
||||||
</AnimateChildren>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,63 +0,0 @@
|
|||||||
// Copyright 2015, 2016 Ethcore (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, PropTypes } from 'react';
|
|
||||||
import { isReactComponent } from '../../util/react';
|
|
||||||
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|
||||||
import './AnimateChildren.css';
|
|
||||||
|
|
||||||
export default class AnimateChildren extends Component {
|
|
||||||
render () {
|
|
||||||
const className = this.props.absolute ? 'absoluteAnimationContainer' : '';
|
|
||||||
return (
|
|
||||||
<ReactCSSTransitionGroup
|
|
||||||
component='div'
|
|
||||||
className={ className }
|
|
||||||
transitionName='transition'
|
|
||||||
transitionAppear
|
|
||||||
transitionAppearTimeout={ 0 }
|
|
||||||
transitionLeaveTimeout={ 0 }
|
|
||||||
transitionEnterTimeout={ 0 }
|
|
||||||
>
|
|
||||||
{ this.renderChildren() }
|
|
||||||
</ReactCSSTransitionGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderChildren () {
|
|
||||||
const { children, isView } = this.props;
|
|
||||||
|
|
||||||
if (isView) {
|
|
||||||
return React.cloneElement(this.props.children, {
|
|
||||||
key: this.props.pathname
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isReactComponent(children)) {
|
|
||||||
return React.cloneElement(this.props.children, { ...this.props });
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
children: PropTypes.any.isRequired,
|
|
||||||
pathname: PropTypes.string,
|
|
||||||
isView: PropTypes.bool,
|
|
||||||
absolute: PropTypes.bool
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -15,7 +15,6 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import AnimateChildren from '../../components-compositors/Animated/children';
|
|
||||||
import Call from '../Call';
|
import Call from '../Call';
|
||||||
import CallsToolbar from '../CallsToolbar';
|
import CallsToolbar from '../CallsToolbar';
|
||||||
import styles from './Calls.css';
|
import styles from './Calls.css';
|
||||||
@ -73,13 +72,11 @@ export default class Calls extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimateChildren>
|
<div { ...this._test('empty-wrapper') }>
|
||||||
<div { ...this._test('empty-wrapper') }>
|
<h3 className={ styles.historyInfo } { ...this._test('empty') }>
|
||||||
<h3 className={ styles.historyInfo } { ...this._test('empty') }>
|
Fire up some calls and the results will be here.
|
||||||
Fire up some calls and the results will be here.
|
</h3>
|
||||||
</h3>
|
</div>
|
||||||
</div>
|
|
||||||
</AnimateChildren>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,17 +87,13 @@ export default class Calls extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return calls.map((call, idx) => (
|
||||||
<AnimateChildren>
|
<Call
|
||||||
{ calls.map((call, idx) => (
|
key={ calls.length - idx }
|
||||||
<Call
|
call={ call }
|
||||||
key={ calls.length - idx }
|
setActiveCall={ this.setActiveCall }
|
||||||
call={ call }
|
/>
|
||||||
setActiveCall={ this.setActiveCall }
|
));
|
||||||
/>
|
|
||||||
)) }
|
|
||||||
</AnimateChildren>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearActiveCall = () => {
|
clearActiveCall = () => {
|
||||||
|
@ -23,8 +23,6 @@ import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from '~/redux/
|
|||||||
import Debug from '../../components/Debug';
|
import Debug from '../../components/Debug';
|
||||||
import Status from '../../components/Status';
|
import Status from '../../components/Status';
|
||||||
|
|
||||||
import styles from './statusPage.css';
|
|
||||||
|
|
||||||
class StatusPage extends Component {
|
class StatusPage extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
nodeStatus: PropTypes.object.isRequired,
|
nodeStatus: PropTypes.object.isRequired,
|
||||||
@ -41,7 +39,7 @@ class StatusPage extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className={ styles.body }>
|
<div>
|
||||||
<Status { ...this.props } />
|
<Status { ...this.props } />
|
||||||
<Debug { ...this.props } />
|
<Debug { ...this.props } />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/* Copyright 2015, 2016 Ethcore (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/>.
|
|
||||||
*/
|
|
||||||
.body {
|
|
||||||
}
|
|
@ -23,6 +23,7 @@ const postcssImport = require('postcss-import');
|
|||||||
const postcssNested = require('postcss-nested');
|
const postcssNested = require('postcss-nested');
|
||||||
const postcssVars = require('postcss-simple-vars');
|
const postcssVars = require('postcss-simple-vars');
|
||||||
const rucksack = require('rucksack-css');
|
const rucksack = require('rucksack-css');
|
||||||
|
const CircularDependencyPlugin = require('circular-dependency-plugin');
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV || 'development';
|
const ENV = process.env.NODE_ENV || 'development';
|
||||||
const isProd = ENV === 'production';
|
const isProd = ENV === 'production';
|
||||||
@ -102,7 +103,12 @@ function getPlugins (_isProd = isProd) {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new webpack.optimize.OccurrenceOrderPlugin(!_isProd)
|
new webpack.optimize.OccurrenceOrderPlugin(!_isProd),
|
||||||
|
|
||||||
|
new CircularDependencyPlugin({
|
||||||
|
exclude: /node_modules/,
|
||||||
|
failOnError: true
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
if (_isProd) {
|
if (_isProd) {
|
||||||
|
Loading…
Reference in New Issue
Block a user