Merge branch 'master' into clippy-bump

Conflicts:
	rpc/src/v1/types/filter.rs
This commit is contained in:
Tomasz Drwięga 2016-11-29 11:56:55 +01:00
commit 44314c5d02
93 changed files with 1337 additions and 891 deletions

2
Cargo.lock generated
View File

@ -1263,7 +1263,7 @@ dependencies = [
[[package]]
name = "parity-ui-precompiled"
version = "1.4.0"
source = "git+https://github.com/ethcore/js-precompiled.git#7cb42b0c636f76eb478c9270a1e507ac3c3ba434"
source = "git+https://github.com/ethcore/js-precompiled.git#cb6836dddf8c9951e056283dcd9e105e97923d07"
dependencies = [
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -1,5 +1,8 @@
{
"presets": ["es2017", "es2016", "es2015", "stage-0", "react"],
"presets": [
"es2017", "es2016", "es2015",
"stage-0", "react"
],
"plugins": [
"transform-runtime",
"transform-decorators-legacy",
@ -10,6 +13,9 @@
"env": {
"production": {
"plugins": ["transform-react-remove-prop-types"]
},
"development": {
"plugins": ["react-hot-loader/babel"]
}
}
}

View File

@ -15,6 +15,7 @@
"no-debugger": "error",
"no-alert": "error",
"jsx-quotes": ["error", "prefer-single"],
"react/jsx-curly-spacing": ["error", "always"]
"react/jsx-curly-spacing": ["error", "always"],
"object-property-newline": 0
}
}

1
js/.npmrc Normal file
View File

@ -0,0 +1 @@
save-prefix='~'

View File

@ -1,6 +1,6 @@
{
"name": "parity.js",
"version": "0.2.74",
"version": "0.2.78",
"main": "release/index.js",
"jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>",
@ -26,16 +26,16 @@
],
"scripts": {
"build": "npm run build:lib && npm run build:dll && npm run build:app",
"build:app": "webpack --progress",
"build:lib": "webpack --config webpack.libraries --progress",
"build:dll": "webpack --config webpack.vendor --progress",
"build:app": "webpack --config webpack/app --progress",
"build:lib": "webpack --config webpack/libraries --progress",
"build:dll": "webpack --config webpack/vendor --progress",
"ci:build": "npm run ci:build:lib && npm run ci:build:dll && npm run ci:build:app",
"ci:build:app": "NODE_ENV=production webpack",
"ci:build:lib": "NODE_ENV=production webpack --config webpack.libraries",
"ci:build:dll": "NODE_ENV=production webpack --config webpack.vendor",
"ci:build:npm": "NODE_ENV=production webpack --config webpack.npm",
"ci:build:app": "NODE_ENV=production webpack --config webpack/app",
"ci:build:lib": "NODE_ENV=production webpack --config webpack/libraries",
"ci:build:dll": "NODE_ENV=production webpack --config webpack/vendor",
"ci:build:npm": "NODE_ENV=production webpack --config webpack/npm",
"start": "npm install && npm run build:lib && npm run build:dll && npm run start:app",
"start:app": "webpack-dev-server -d --history-api-fallback --open --hot --inline --progress --colors --port 3000",
"start:app": "node webpack/dev.server",
"clean": "rm -rf ./build ./coverage",
"coveralls": "npm run testCoverage && coveralls < coverage/lcov.info",
"lint": "eslint --ignore-path .gitignore ./src/",
@ -47,127 +47,132 @@
"prepush": "npm run lint:cached"
},
"devDependencies": {
"babel-cli": "^6.10.1",
"babel-core": "^6.10.4",
"babel-eslint": "^7.1.0",
"babel-loader": "^6.2.3",
"babel-plugin-lodash": "^3.2.2",
"babel-plugin-transform-class-properties": "^6.11.5",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-react-remove-prop-types": "^0.2.9",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-polyfill": "^6.13.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-es2015-rollup": "^1.1.1",
"babel-preset-es2016": "^6.11.3",
"babel-preset-es2017": "^6.14.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "6.9.0",
"babel-runtime": "^6.9.2",
"chai": "^3.5.0",
"babel-cli": "~6.18.0",
"babel-core": "~6.18.2",
"babel-eslint": "~7.1.0",
"babel-loader": "~6.2.3",
"babel-plugin-lodash": "~3.2.2",
"babel-plugin-transform-class-properties": "~6.19.0",
"babel-plugin-transform-decorators-legacy": "~1.3.4",
"babel-plugin-transform-react-remove-prop-types": "~0.2.9",
"babel-plugin-transform-runtime": "~6.15.0",
"babel-polyfill": "~6.16.0",
"babel-preset-es2015": "~6.18.0",
"babel-preset-es2015-rollup": "~1.2.0",
"babel-preset-es2016": "~6.16.0",
"babel-preset-es2017": "~6.16.0",
"babel-preset-react": "~6.16.0",
"babel-preset-stage-0": "~6.16.0",
"babel-register": "6.18.0",
"babel-runtime": "~6.18.0",
"chai": "~3.5.0",
"chai-enzyme": "0.4.2",
"cheerio": "0.20.0",
"copy-webpack-plugin": "^4.0.0",
"core-js": "^2.4.1",
"coveralls": "^2.11.11",
"css-loader": "^0.23.1",
"copy-webpack-plugin": "~4.0.0",
"core-js": "~2.4.1",
"coveralls": "~2.11.11",
"css-loader": "~0.26.0",
"enzyme": "2.3.0",
"eslint": "^3.1.0",
"eslint-config-semistandard": "^6.0.2",
"eslint-config-standard": "^5.3.5",
"eslint-config-standard-react": "^3.0.0",
"eslint-plugin-promise": "^2.0.0",
"eslint-plugin-react": "^5.1.1",
"eslint-plugin-standard": "^2.0.0",
"extract-loader": "0.0.2",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"fs-extra": "^0.30.0",
"happypack": "^2.2.1",
"history": "^2.0.0",
"html-loader": "^0.4.4",
"husky": "^0.11.9",
"eslint": "~3.10.2",
"eslint-config-semistandard": "~7.0.0",
"eslint-config-standard": "~6.2.1",
"eslint-config-standard-react": "~4.2.0",
"eslint-plugin-promise": "~3.4.0",
"eslint-plugin-react": "~6.7.1",
"eslint-plugin-standard": "~2.0.0",
"express": "~4.14.0",
"extract-loader": "0.1.0",
"extract-text-webpack-plugin": "~2.0.0-beta.4",
"file-loader": "~0.9.0",
"fs-extra": "~0.30.0",
"happypack": "~3.0.0",
"history": "~2.0.0",
"html-loader": "~0.4.4",
"html-webpack-plugin": "~2.24.1",
"http-proxy-middleware": "~0.17.2",
"husky": "~0.11.9",
"ignore-styles": "2.0.0",
"image-webpack-loader": "^1.8.0",
"istanbul": "^1.0.0-alpha.2",
"image-webpack-loader": "~3.0.0",
"istanbul": "~1.0.0-alpha.2",
"jsdom": "9.2.1",
"json-loader": "^0.5.4",
"mocha": "^3.0.0-1",
"json-loader": "~0.5.4",
"mocha": "~3.0.0-1",
"mock-local-storage": "1.0.2",
"mock-socket": "^3.0.1",
"nock": "^8.0.0",
"postcss-import": "^8.1.2",
"postcss-loader": "^0.8.1",
"postcss-nested": "^1.0.0",
"postcss-simple-vars": "^3.0.0",
"raw-loader": "^0.5.1",
"mock-socket": "~3.0.1",
"nock": "~8.0.0",
"postcss-import": "8.1.0",
"postcss-loader": "~1.1.1",
"postcss-nested": "~1.0.0",
"postcss-simple-vars": "~3.0.0",
"progress": "~1.1.8",
"raw-loader": "~0.5.1",
"react-addons-perf": "~15.3.2",
"react-addons-test-utils": "~15.3.2",
"react-copy-to-clipboard": "^4.2.3",
"react-dom": "~15.3.2",
"react-hot-loader": "~1.3.0",
"rucksack-css": "^0.8.6",
"sinon": "^1.17.4",
"sinon-as-promised": "^4.0.2",
"sinon-chai": "^2.8.0",
"style-loader": "^0.13.0",
"url-loader": "^0.5.7",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.15.2",
"react-hot-loader": "~3.0.0-beta.6",
"rucksack-css": "~0.8.6",
"sinon": "~1.17.4",
"sinon-as-promised": "~4.0.2",
"sinon-chai": "~2.8.0",
"style-loader": "~0.13.0",
"url-loader": "~0.5.7",
"webpack": "~2.1.0-beta.27",
"webpack-dev-middleware": "~1.8.4",
"webpack-error-notification": "0.1.6",
"webpack-hot-middleware": "~2.13.2",
"websocket": "^1.0.23"
"websocket": "~1.0.23"
},
"dependencies": {
"bignumber.js": "^2.3.0",
"bignumber.js": "~2.3.0",
"blockies": "0.0.2",
"brace": "^0.9.0",
"bytes": "^2.4.0",
"chart.js": "^2.3.0",
"es6-error": "^4.0.0",
"es6-promise": "^3.2.1",
"ethereumjs-tx": "^1.1.2",
"file-saver": "^1.3.3",
"format-json": "^1.0.3",
"format-number": "^2.0.1",
"geopattern": "^1.2.3",
"isomorphic-fetch": "^2.2.1",
"js-sha3": "^0.5.2",
"lodash": "^4.11.1",
"marked": "^0.3.6",
"brace": "~0.9.0",
"bytes": "~2.4.0",
"chart.js": "~2.3.0",
"es6-error": "~4.0.0",
"es6-promise": "~3.2.1",
"ethereumjs-tx": "~1.1.2",
"eventemitter3": "~2.0.2",
"file-saver": "~1.3.3",
"format-json": "~1.0.3",
"format-number": "~2.0.1",
"geopattern": "~1.2.3",
"isomorphic-fetch": "~2.2.1",
"js-sha3": "~0.5.2",
"lodash": "~4.11.1",
"marked": "~0.3.6",
"material-ui": "0.16.1",
"material-ui-chip-input": "^0.8.0",
"mobx": "^2.6.1",
"mobx-react": "^3.5.8",
"mobx-react-devtools": "^4.2.9",
"moment": "^2.14.1",
"phoneformat.js": "^1.0.3",
"qs": "^6.3.0",
"material-ui-chip-input": "~0.8.0",
"mobx": "~2.6.1",
"mobx-react": "~3.5.8",
"mobx-react-devtools": "~4.2.9",
"moment": "~2.14.1",
"phoneformat.js": "~1.0.3",
"qs": "~6.3.0",
"react": "~15.3.2",
"react-ace": "^4.0.0",
"react-ace": "~4.0.0",
"react-addons-css-transition-group": "~15.3.2",
"react-chartjs-2": "^1.5.0",
"react-chartjs-2": "~1.5.0",
"react-copy-to-clipboard": "~4.2.3",
"react-dom": "~15.3.2",
"react-dropzone": "^3.7.3",
"react-redux": "^4.4.5",
"react-router": "^2.6.1",
"react-router-redux": "^4.0.5",
"react-dropzone": "~3.7.3",
"react-redux": "~4.4.5",
"react-router": "~2.6.1",
"react-router-redux": "~4.0.5",
"react-tap-event-plugin": "~1.0.0",
"react-tooltip": "^2.0.3",
"recharts": "^0.15.2",
"redux": "^3.5.2",
"redux-actions": "^0.10.1",
"redux-thunk": "^2.1.0",
"rlp": "^2.0.0",
"scryptsy": "^2.0.0",
"react-tooltip": "~2.0.3",
"recharts": "~0.15.2",
"redux": "~3.5.2",
"redux-actions": "~0.10.1",
"redux-thunk": "~2.1.0",
"rlp": "~2.0.0",
"scryptsy": "~2.0.0",
"solc": "ngotchac/solc-js",
"store": "^1.3.20",
"utf8": "^2.1.1",
"valid-url": "^1.0.9",
"validator": "^5.7.0",
"web3": "^0.17.0-beta",
"whatwg-fetch": "^1.0.0",
"worker-loader": "^0.7.1"
"store": "~1.3.20",
"utf8": "~2.1.1",
"valid-url": "~1.0.9",
"validator": "~5.7.0",
"web3": "~0.17.0-beta",
"whatwg-fetch": "~1.0.0",
"worker-loader": "~0.7.1"
}
}

View File

@ -27,9 +27,10 @@ export const termsOfService = (
</ul>
);
export const postToServer = (query) => {
export const postToServer = (query, isTestnet = false) => {
const port = isTestnet ? 8443 : 443;
query = stringify(query);
return fetch('https://sms-verification.parity.io/?' + query, {
return fetch(`https://sms-verification.parity.io:${port}/?` + query, {
method: 'POST', mode: 'cors', cache: 'no-store'
})
.then((res) => {

View File

@ -15,16 +15,16 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import Abi from '../../abi';
import Api from '../api';
import { isInstanceOf } from '../util/types';
let nextSubscriptionId = 0;
export default class Contract {
constructor (api, abi) {
if (!isInstanceOf(api, Api)) {
if (!api) {
throw new Error('API instance needs to be provided to Contract');
} else if (!abi) {
}
if (!abi) {
throw new Error('ABI needs to be provided to Contract instance');
}

View File

@ -17,7 +17,7 @@
import BigNumber from 'bignumber.js';
import { isArray, isHex, isInstanceOf, isString } from '../util/types';
import { padLeft } from '../util/format';
import { padLeft, toHex } from '../util/format';
export function inAddress (address) {
// TODO: address validation if we have upper-lower addresses
@ -100,15 +100,7 @@ export function inFilter (options) {
}
export function inHex (str) {
if (str && str.toString) {
str = str.toString(16);
}
if (str && str.substr(0, 2) === '0x') {
return str.toLowerCase();
}
return `0x${(str || '').toLowerCase()}`;
return toHex(str);
}
export function inNumber10 (number) {

View File

@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { range } from 'lodash';
import { inHex } from '../format/input';
export function bytesToHex (bytes) {
return '0x' + bytes.map((b) => ('0' + b.toString(16)).slice(-2)).join('');
@ -38,11 +37,23 @@ export function asciiToHex (string) {
}
export function padRight (input, length) {
const value = inHex(input).substr(2, length * 2);
const value = toHex(input).substr(2, length * 2);
return '0x' + value + range(length * 2 - value.length).map(() => '0').join('');
}
export function padLeft (input, length) {
const value = inHex(input).substr(2, length * 2);
const value = toHex(input).substr(2, length * 2);
return '0x' + range(length * 2 - value.length).map(() => '0').join('') + value;
}
export function toHex (str) {
if (str && str.toString) {
str = str.toString(16);
}
if (str && str.substr(0, 2) === '0x') {
return str.toLowerCase();
}
return `0x${(str || '').toLowerCase()}`;
}

View File

@ -1 +1 @@
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]

View File

@ -19,7 +19,7 @@ import Registry from './registry';
import SignatureReg from './signaturereg';
import TokenReg from './tokenreg';
import GithubHint from './githubhint';
import smsVerification from './sms-verification';
import * as smsVerification from './sms-verification';
let instance = null;

View File

@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import subscribeToEvent from '../util/subscribe-to-event';
export const checkIfVerified = (contract, account) => {
return contract.instance.certified.call({}, [account]);
};
@ -50,3 +52,36 @@ export const checkIfRequested = (contract, account) => {
});
});
};
const blockNumber = (api) => {
return new Promise((resolve, reject) => {
api.subscribe('eth_blockNumber', (err, block) => {
if (err) {
return reject(err);
}
resolve(block);
})
.then((subscription) => {
api.unsubscribe(subscription);
})
.catch(reject);
});
};
export const awaitPuzzle = (api, contract, account) => {
return blockNumber(api)
.then((block) => {
return new Promise((resolve, reject) => {
const subscription = subscribeToEvent(contract, 'Puzzled', {
from: block.toNumber(),
filter: (log) => log.params.who.value === account
});
subscription.once('error', reject);
subscription.once('log', subscription.unsubscribe);
subscription.once('log', resolve);
subscription.once('timeout', () => {
reject(new Error('Timed out waiting for the puzzle.'));
});
});
});
};

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Basic Token Deployment</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="basiccoin.js"></script>
</body>
</html>

View File

@ -32,7 +32,6 @@ const routerHistory = useRouterHistory(createHashHistory)({});
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './basiccoin.html';
ReactDOM.render(
<Router history={ routerHistory }>

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Dapp Registry</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="dappreg.js"></script>
</body>
</html>

View File

@ -27,7 +27,6 @@ import Application from './dappreg/Application';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './dappreg.html';
ReactDOM.render(
<Application />,

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>GitHub Hint</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="githubhint.js"></script>
</body>
</html>

View File

@ -25,7 +25,6 @@ import Application from './githubhint/Application';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './githubhint.html';
ReactDOM.render(
<Application />,

42
js/src/dapps/index.ejs Normal file
View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= htmlWebpackPlugin.options.title %></title>
<style>
html, body, #container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-family: Roboto;
background-color: rgba(0, 0, 0, 0.8);
color: #ddd;
}
.loading {
font-size: 4em;
}
</style>
</head>
<body>
<div id="container">
<div class="loading-container">
<span class="loading">Loading...</span>
</div>
</div>
<script src="vendor.js"></script>
<% if (!htmlWebpackPlugin.options.secure) { %>
<script src="/parity-utils/parity.js"></script>
<% } %>
</body>
</html>

25
js/src/dapps/index.js Normal file
View File

@ -0,0 +1,25 @@
// 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/>.
module.exports = [
{ name: 'basiccoin', entry: 'basiccoin.js', title: 'Basic Token Deployment' },
{ name: 'dappreg', entry: 'dappreg.js', title: 'Dapp Registry' },
{ name: 'githubhint', entry: 'githubhint.js', title: 'GitHub Hint', secure: true },
{ name: 'localtx', entry: 'localtx.js', title: 'Local transactions Viewer', secure: true },
{ name: 'registry', entry: 'registry.js', title: 'Registry' },
{ name: 'signaturereg', entry: 'signaturereg.js', title: 'Method Signature Registry' },
{ name: 'tokenreg', entry: 'tokenreg.js', title: 'Token Registry' }
];

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Local transactions Viewer</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="localtx.js"></script>
</body>
</html>

View File

@ -25,7 +25,6 @@ import Application from './localtx/Application';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './localtx.html';
ReactDOM.render(
<Application />,

View File

@ -158,18 +158,18 @@ export default class Application extends Component {
{ Transaction.renderHeader() }
</thead>
<tbody>
{
transactions.map((tx, idx) => (
<Transaction
key={ tx.transaction.hash }
idx={ idx + 1 }
isLocal={ tx.isLocal }
transaction={ tx.transaction }
stats={ tx.stats }
blockNumber={ blockNumber }
/>
))
}
{
transactions.map((tx, idx) => (
<Transaction
key={ tx.transaction.hash }
idx={ idx + 1 }
isLocal={ tx.isLocal }
transaction={ tx.transaction }
stats={ tx.stats }
blockNumber={ blockNumber }
/>
))
}
</tbody>
</table>
);

View File

@ -83,7 +83,7 @@ class BaseTransaction extends Component {
return (
<span className={ styles.nowrap }>
{ noOfPropagations } ({ noOfPeers } peers)
{ noOfPropagations } ({ noOfPeers } peers)
</span>
);
}
@ -110,7 +110,7 @@ export class Transaction extends BaseTransaction {
static renderHeader () {
return (
<tr className={ styles.header }>
<th></th>
<th />
<th>
Transaction
</th>
@ -129,8 +129,7 @@ export class Transaction extends BaseTransaction {
<th>
# Propagated
</th>
<th>
</th>
<th />
</tr>
);
}
@ -201,7 +200,7 @@ export class LocalTransaction extends BaseTransaction {
static renderHeader () {
return (
<tr className={ styles.header }>
<th></th>
<th />
<th>
Transaction
</th>

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Token Registry</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="registry.js"></script>
</body>
</html>

View File

@ -27,7 +27,6 @@ import Container from './registry/Container';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './registry.html';
ReactDOM.render(
<Provider store={ store }>

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Method Signature Registry</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="signaturereg.js"></script>
</body>
</html>

View File

@ -25,7 +25,6 @@ import Application from './signaturereg/Application';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './signaturereg.html';
ReactDOM.render(
<Application />,

View File

@ -73,7 +73,7 @@ export default class Import extends Component {
Provide the ABI (Contract Interface) in the space provided below. Only non-constant functions (names &amp; types) will be imported, while constant functions and existing signatures will be ignored.
</div>
<div className={ styles.info }>
<textarea rows='8' className={ styles.error } onChange={ this.onAbiEdit }></textarea>
<textarea rows='8' className={ styles.error } onChange={ this.onAbiEdit } />
<div className={ styles.error }>
{ abiError }
</div>

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Token Registry</title>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="/parity-utils/parity.js"></script>
<script src="tokenreg.js"></script>
</body>
</html>

View File

@ -27,13 +27,12 @@ import Container from './tokenreg/Container';
import '../../assets/fonts/Roboto/font.css';
import '../../assets/fonts/RobotoMono/font.css';
import './style.css';
import './tokenreg.html';
ReactDOM.render(
(
<Provider store={ store }>
<Container />
</Provider>
<Provider store={ store }>
<Container />
</Provider>
),
document.querySelector('#container')
);

View File

@ -147,7 +147,7 @@ export const loadToken = (index) => (dispatch, getState) => {
dispatch(setTokenData(index, null));
dispatch(setTokenLoading(index, false));
if (!e instanceof TypeError) {
if (!(e instanceof TypeError)) {
console.error(`loadToken #${index} error`, e);
}
});

39
js/src/index.ejs Normal file
View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= htmlWebpackPlugin.options.title %></title>
<style>
html, body, #container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-family: Roboto;
background-color: rgba(0, 0, 0, 0.8);
color: #ddd;
}
.loading {
font-size: 4em;
}
</style>
</head>
<body>
<div id="container">
<div class="loading-container">
<span class="loading">Loading...</span>
</div>
</div>
<script src="vendor.js"></script>
</body>
</html>

View File

@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
<title>Parity</title>
<style>
html, body, #container {
height: 100%;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="vendor.js"></script>
<script src="commons.js"></script>
<script src="index.js"></script>
</body>
</html>

View File

@ -22,17 +22,20 @@ es6Promise.polyfill();
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { createHashHistory } from 'history';
import { Redirect, Router, Route, useRouterHistory } from 'react-router';
import { useRouterHistory } from 'react-router';
import qs from 'querystring';
import SecureApi from './secureApi';
import ContractInstances from './contracts';
import { initStore } from './redux';
import { ContextProvider, muiTheme } from './ui';
import { Accounts, Account, Addresses, Address, Application, Contract, Contracts, WriteContract, Dapp, Dapps, Settings, SettingsBackground, SettingsParity, SettingsProxy, SettingsViews, Signer, Status } from './views';
import ContextProvider from './ui/ContextProvider';
import muiTheme from './ui/Theme';
import MainApplication from './main';
import { setApi } from './redux/providers/apiActions';
@ -41,9 +44,6 @@ import './environment';
import '../assets/fonts/Roboto/font.css';
import '../assets/fonts/RobotoMono/font.css';
import styles from './reset.css';
import './index.html';
injectTapEventPlugin();
if (process.env.NODE_ENV === 'development') {
@ -77,32 +77,47 @@ window.secureApi = api;
const routerHistory = useRouterHistory(createHashHistory)({});
ReactDOM.render(
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
<Router className={ styles.reset } history={ routerHistory }>
<Redirect from='/' to='/accounts' />
<Redirect from='/auth' to='/accounts' query={ {} } />
<Redirect from='/settings' to='/settings/views' />
<Route path='/' component={ Application }>
<Route path='accounts' component={ Accounts } />
<Route path='account/:address' component={ Account } />
<Route path='addresses' component={ Addresses } />
<Route path='address/:address' component={ Address } />
<Route path='apps' component={ Dapps } />
<Route path='app/:id' component={ Dapp } />
<Route path='contracts' component={ Contracts } />
<Route path='contracts/write' component={ WriteContract } />
<Route path='contract/:address' component={ Contract } />
<Route path='settings' component={ Settings }>
<Route path='background' component={ SettingsBackground } />
<Route path='proxy' component={ SettingsProxy } />
<Route path='views' component={ SettingsViews } />
<Route path='parity' component={ SettingsParity } />
</Route>
<Route path='signer' component={ Signer } />
<Route path='status' component={ Status } />
<Route path='status/:subpage' component={ Status } />
</Route>
</Router>
</ContextProvider>,
<AppContainer>
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
<MainApplication
routerHistory={ routerHistory }
/>
</ContextProvider>
</AppContainer>,
document.querySelector('#container')
);
if (module.hot) {
// module.hot.accept('./redux', () => {
// // redux store has a method replaceReducer
// // const newStore = initStore(api);
// console.warn('REDUX UPDATE');
// // store.replaceReducer(appReducer);
// // ReactDOM.render(
// // <AppContainer>
// // <ContextProvider api={ api } muiTheme={ muiTheme } store={ newStore }>
// // <MainApplication
// // routerHistory={ routerHistory }
// // />
// // </ContextProvider>
// // </AppContainer>,
// // document.querySelector('#container')
// // );
// });
module.hot.accept('./main.js', () => {
require('./main.js');
ReactDOM.render(
<AppContainer>
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
<MainApplication
routerHistory={ routerHistory }
/>
</ContextProvider>
</AppContainer>,
document.querySelector('#container')
);
});
}

60
js/src/main.js Normal file
View File

@ -0,0 +1,60 @@
// 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 { Redirect, Router, Route } from 'react-router';
import { Accounts, Account, Addresses, Address, Application, Contract, Contracts, WriteContract, Dapp, Dapps, Settings, SettingsBackground, SettingsParity, SettingsProxy, SettingsViews, Signer, Status } from './views';
import styles from './reset.css';
export default class MainApplication extends Component {
static propTypes = {
routerHistory: PropTypes.any.isRequired
};
render () {
const { routerHistory } = this.props;
return (
<Router className={ styles.reset } history={ routerHistory }>
<Redirect from='/' to='/accounts' />
<Redirect from='/auth' to='/accounts' query={ {} } />
<Redirect from='/settings' to='/settings/views' />
<Route path='/' component={ Application }>
<Route path='accounts' component={ Accounts } />
<Route path='account/:address' component={ Account } />
<Route path='addresses' component={ Addresses } />
<Route path='address/:address' component={ Address } />
<Route path='apps' component={ Dapps } />
<Route path='app/:id' component={ Dapp } />
<Route path='contracts' component={ Contracts } />
<Route path='contracts/write' component={ WriteContract } />
<Route path='contract/:address' component={ Contract } />
<Route path='settings' component={ Settings }>
<Route path='background' component={ SettingsBackground } />
<Route path='proxy' component={ SettingsProxy } />
<Route path='views' component={ SettingsViews } />
<Route path='parity' component={ SettingsParity } />
</Route>
<Route path='signer' component={ Signer } />
<Route path='status' component={ Status } />
<Route path='status/:subpage' component={ Status } />
</Route>
</Router>
);
}
}

View File

@ -79,16 +79,16 @@ export default class LoadContract extends Component {
const contractsTab = Object.keys(contracts).length === 0
? null
: (
<Tab label='Local' >
{ this.renderEditor() }
<Tab label='Local' >
{ this.renderEditor() }
<SelectableList
onChange={ this.onClickContract }
>
<Subheader>Saved Contracts</Subheader>
{ this.renderContracts(contracts) }
</SelectableList>
</Tab>
<SelectableList
onChange={ this.onClickContract }
>
<Subheader>Saved Contracts</Subheader>
{ this.renderContracts(contracts) }
</SelectableList>
</Tab>
);
return (
@ -174,9 +174,9 @@ export default class LoadContract extends Component {
const secondaryText = description || `Saved ${moment(timestamp).fromNow()}`;
const remove = removable
? (
<IconButton onTouchTap={ onDelete }>
<DeleteIcon />
</IconButton>
<IconButton onTouchTap={ onDelete }>
<DeleteIcon />
</IconButton>
)
: null;

View File

@ -22,6 +22,10 @@ import SendIcon from 'material-ui/svg-icons/content/send';
import { Tabs, Tab } from 'material-ui/Tabs';
import Paper from 'material-ui/Paper';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { showSnackbar } from '../../redux/providers/snackbarActions';
import Form, { Input } from '../../ui/Form';
import { Button, Modal, IdentityName, IdentityIcon } from '../../ui';
@ -30,13 +34,14 @@ import styles from './passwordManager.css';
const TEST_ACTION = 'TEST_ACTION';
const CHANGE_ACTION = 'CHANGE_ACTION';
export default class PasswordManager extends Component {
class PasswordManager extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
account: PropTypes.object.isRequired,
showSnackbar: PropTypes.func.isRequired,
onClose: PropTypes.func
}
@ -98,10 +103,10 @@ export default class PasswordManager extends Component {
const passwordHint = meta && meta.passwordHint
? (
<span className={ styles.passwordHint }>
<span className={ styles.hintLabel }>Hint </span>
{ meta.passwordHint }
</span>
<span className={ styles.passwordHint }>
<span className={ styles.hintLabel }>Hint </span>
{ meta.passwordHint }
</span>
)
: null;
@ -333,7 +338,7 @@ export default class PasswordManager extends Component {
}
handleChangePassword = () => {
const { account } = this.props;
const { account, showSnackbar, onClose } = this.props;
const { currentPass, newPass, repeatNewPass, passwordHint } = this.state;
if (repeatNewPass !== newPass) {
@ -371,12 +376,9 @@ export default class PasswordManager extends Component {
.changePassword(account.address, currentPass, newPass)
])
.then(() => {
const message = {
value: 'Your password has been successfully changed',
success: true
};
this.setState({ waiting: false, message, showMessage: true });
showSnackbar(<div>Your password has been successfully changed.</div>);
this.setState({ waiting: false, showMessage: false });
onClose();
});
})
.catch(e => {
@ -385,3 +387,14 @@ export default class PasswordManager extends Component {
});
}
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({
showSnackbar
}, dispatch);
}
export default connect(
null,
mapDispatchToProps
)(PasswordManager);

View File

@ -53,7 +53,7 @@ export default class GatherData extends Component {
{ this.renderCertified() }
{ this.renderRequested() }
<Input
label={ 'phone number' }
label={ 'phone number in international format' }
hint={ 'the SMS will be sent to this number' }
error={ isNumberValid ? null : 'invalid number' }
disabled={ isVerified }

View File

@ -25,7 +25,7 @@ import {
LOADING,
QUERY_DATA,
POSTING_REQUEST, POSTED_REQUEST,
REQUESTING_SMS, REQUESTED_SMS,
REQUESTING_SMS, QUERY_CODE,
POSTING_CONFIRMATION, POSTED_CONFIRMATION,
DONE
} from './store';
@ -48,7 +48,7 @@ export default class SMSVerification extends Component {
[LOADING]: 0,
[QUERY_DATA]: 1,
[POSTING_REQUEST]: 2, [POSTED_REQUEST]: 2, [REQUESTING_SMS]: 2,
[REQUESTED_SMS]: 3,
[QUERY_CODE]: 3,
[POSTING_CONFIRMATION]: 4, [POSTED_CONFIRMATION]: 4,
[DONE]: 5
}
@ -137,7 +137,7 @@ export default class SMSVerification extends Component {
step,
fee, number, isNumberValid, isVerified, hasRequested,
requestTx, isCodeValid, confirmationTx,
setNumber, setConsentGiven, setCode
setCode
} = this.props.store;
switch (phase) {

View File

@ -47,7 +47,7 @@ export default class SendRequest extends Component {
case REQUESTING_SMS:
return (
<p>Requesting an SMS from the Parity server.</p>
<p>Requesting an SMS from the Parity server and waiting for the puzzle to be put into the contract.</p>
);
default:

View File

@ -20,19 +20,16 @@ import { sha3 } from '../../api/util/sha3';
import Contracts from '../../contracts';
import { checkIfVerified, checkIfRequested } from '../../contracts/sms-verification';
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '../../contracts/sms-verification';
import { postToServer } from '../../3rdparty/sms-verification';
import checkIfTxFailed from '../../util/check-if-tx-failed';
import waitForConfirmations from '../../util/wait-for-block-confirmations';
const validCode = /^[A-Z\s]+$/i;
export const LOADING = 'fetching-contract';
export const QUERY_DATA = 'query-data';
export const POSTING_REQUEST = 'posting-request';
export const POSTED_REQUEST = 'posted-request';
export const REQUESTING_SMS = 'requesting-sms';
export const REQUESTED_SMS = 'requested-sms';
export const QUERY_CODE = 'query-code';
export const POSTING_CONFIRMATION = 'posting-confirmation';
export const POSTED_CONFIRMATION = 'posted-confirmation';
@ -50,11 +47,9 @@ export default class VerificationStore {
@observable number = '';
@observable requestTx = null;
@observable code = '';
@observable isCodeValid = null;
@observable confirmationTx = null;
@computed get isCodeValid () {
return validCode.test(this.code);
}
@computed get isNumberValid () {
return phone.isValidNumber(this.number);
}
@ -72,20 +67,19 @@ export default class VerificationStore {
return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null;
case QUERY_DATA:
return this.isNumberValid && this.consentGiven;
case REQUESTED_SMS:
return this.requestTx;
case QUERY_CODE:
return this.isCodeValid;
return this.requestTx && this.isCodeValid === true;
case POSTED_CONFIRMATION:
return this.confirmationTx;
return !!this.confirmationTx;
default:
return false;
}
}
constructor (api, account) {
constructor (api, account, isTestnet) {
this.api = api;
this.account = account;
this.isTestnet = isTestnet;
this.step = LOADING;
Contracts.create(api).registry.getContract('smsverification')
@ -151,7 +145,26 @@ export default class VerificationStore {
}
@action setCode = (code) => {
const { contract, account } = this;
if (!contract || !account || code.length === 0) return;
const confirm = contract.functions.find((fn) => fn.name === 'confirm');
const options = { from: account };
const values = [ sha3(code) ];
this.code = code;
this.isCodeValid = null;
confirm.estimateGas(options, values)
.then((gas) => {
options.gas = gas.mul(1.2).toFixed(0);
return confirm.call(options, values);
})
.then((result) => {
this.isCodeValid = result === true;
})
.catch((err) => {
this.error = 'Failed to check if the code is valid: ' + err.message;
});
}
@action sendRequest = () => {
@ -188,11 +201,15 @@ export default class VerificationStore {
chain
.then(() => {
this.step = REQUESTING_SMS;
return postToServer({ number, address: account });
return api.parity.netChain();
})
.then((chain) => {
this.step = REQUESTING_SMS;
return postToServer({ number, address: account }, this.isTestnet);
})
.then(() => awaitPuzzle(api, contract, account))
.then(() => {
this.step = REQUESTED_SMS;
this.step = QUERY_CODE;
})
.catch((err) => {
this.error = 'Failed to request a confirmation SMS: ' + err.message;

View File

@ -17,7 +17,7 @@
import { newError } from '../ui/Errors/actions';
import { setAddressImage } from './providers/imagesActions';
import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from './providers/statusActions';
import { toggleView } from '../views/Settings';
import { toggleView } from '../views/Settings/actions';
export {
newError,

View File

@ -19,9 +19,9 @@ import { routerReducer } from 'react-router-redux';
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer } from './providers';
import { errorReducer } from '../ui/Errors';
import { settingsReducer } from '../views/Settings';
import { tooltipReducer } from '../ui/Tooltips';
import errorReducer from '../ui/Errors/reducers';
import settingsReducer from '../views/Settings/reducers';
import tooltipReducer from '../ui/Tooltips/reducers';
export default function () {
return combineReducers({

View File

@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
import FileSaver from 'file-saver';
import FileDownloadIcon from 'material-ui/svg-icons/file/file-download';
import { Button } from '../../';
import Button from '../../Button';
class ActionbarExport extends Component {
static propTypes = {

View File

@ -20,7 +20,8 @@ import FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
import ContentClear from 'material-ui/svg-icons/content/clear';
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import { Modal, Button } from '../../';
import Button from '../../Button';
import Modal from '../../Modal';
import styles from './import.css';

View File

@ -17,7 +17,8 @@
import React, { Component, PropTypes } from 'react';
import ActionSearch from 'material-ui/svg-icons/action/search';
import { Button, InputChip } from '../../';
import Button from '../../Button';
import InputChip from '../../Form/InputChip';
import styles from './search.css';

View File

@ -22,7 +22,7 @@ import MenuItem from 'material-ui/MenuItem';
import SortIcon from 'material-ui/svg-icons/content/sort';
import { Button } from '../../';
import Button from '../../Button';
import SortStore from './sortStore';
import styles from './sort.css';

View File

@ -38,9 +38,9 @@ export default class Title extends Component {
const byLine = typeof byline === 'string'
? (
<span title={ byline }>
{ byline }
</span>
<span title={ byline }>
{ byline }
</span>
)
: byline;

View File

@ -22,7 +22,10 @@ import IconButton from 'material-ui/IconButton';
import AddIcon from 'material-ui/svg-icons/content/add';
import RemoveIcon from 'material-ui/svg-icons/content/remove';
import { Input, InputAddressSelect, Select } from '../../../ui';
import Input from '../../../ui/Form/Input';
import InputAddressSelect from '../../../ui/Form/InputAddressSelect';
import Select from '../../../ui/Form/Select';
import { ABI_TYPES } from '../../../util/abi';
import styles from './typedInput.css';

View File

@ -18,6 +18,8 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import ShortenedHash from '../ShortenedHash';
const defaultName = 'UNNAMED';
class IdentityName extends Component {
@ -41,7 +43,7 @@ class IdentityName extends Component {
return null;
}
const addressFallback = shorten ? this.formatHash(address) : address;
const addressFallback = shorten ? (<ShortenedHash data={ address } />) : address;
const fallback = unknown ? defaultName : addressFallback;
const isUuid = hasAccount && account.name === account.uuid;
const displayName = (name && name.toUpperCase().trim()) ||
@ -55,14 +57,6 @@ class IdentityName extends Component {
</span>
);
}
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
}
function mapStateToProps (state) {

View File

@ -0,0 +1,17 @@
// 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 from './shortenedHash';

View File

@ -0,0 +1,21 @@
/* 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/>.
*/
.hash {
display: inline-block;
word-break: break-all;
}

View File

@ -0,0 +1,41 @@
// 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 styles from './shortenedHash.css';
export default class ShortenedHash extends Component {
static propTypes = {
data: PropTypes.string.isRequired
}
render () {
const { data } = this.props;
let shortened = data.toLowerCase();
if (shortened.slice(0, 2) === '0x') {
shortened = shortened.slice(2);
}
if (shortened.length > (6 + 6)) {
shortened = shortened.slice(0, 6) + '…' + shortened.slice(-6);
}
return (
<abbr className={ styles.hash } title={ shortened }>{ shortened }</abbr>
);
}
}

View File

@ -74,10 +74,10 @@ class Tooltip extends Component {
label='Next'
onTouchTap={ onNextTooltip } />
] : (
<FlatButton
icon={ <ActionDoneAll /> }
label='Done'
onTouchTap={ onCloseTooltips } />
<FlatButton
icon={ <ActionDoneAll /> }
label='Done'
onTouchTap={ onCloseTooltips } />
);
return (

View File

@ -15,19 +15,12 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.details {
}
.header {
}
.hash {
padding-top: 1em;
word-break: break-all;
}
.confirm {
padding-top: 1em;
opacity: 0.5;
}

View File

@ -19,7 +19,9 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { LinearProgress } from 'material-ui';
import { txLink } from '../../3rdparty/etherscan/links';
import ShortenedHash from '../ShortenedHash';
import styles from './txHash.css';
@ -62,22 +64,23 @@ class TxHash extends Component {
render () {
const { hash, isTest, summary } = this.props;
let header = null;
if (!summary) {
header = (
<div className={ styles.header }>
The transaction has been posted to the network with a transaction hash of
</div>
);
const link = (
<a href={ txLink(hash, isTest) } target='_blank'>
<ShortenedHash data={ hash } />
</a>
);
let header = (
<p>The transaction has been posted to the network, with a hash of { link }.</p>
);
if (summary) {
header = (<p>{ link }</p>);
}
return (
<div className={ styles.details }>
<div>
{ header }
<div className={ styles.hash }>
<a href={ txLink(hash, isTest) } target='_blank'>{ hash }</a>
</div>
{ this.renderConfirmations() }
</div>
);
@ -87,17 +90,29 @@ class TxHash extends Component {
const { maxConfirmations } = this.props;
const { blockNumber, transaction } = this.state;
let txBlock = 'Pending';
let confirmations = 'No';
let value = 0;
if (transaction && transaction.blockNumber && transaction.blockNumber.gt(0)) {
const num = blockNumber.minus(transaction.blockNumber).plus(1);
txBlock = `#${transaction.blockNumber.toFormat(0)}`;
confirmations = num.toFormat(0);
value = num.gt(maxConfirmations) ? maxConfirmations : num.toNumber();
if (!(transaction && transaction.blockNumber && transaction.blockNumber.gt(0))) {
return (
<div className={ styles.confirm }>
<LinearProgress
className={ styles.progressbar }
color='white'
mode='indeterminate'
/>
<div className={ styles.progressinfo }>waiting for confirmations</div>
</div>
);
}
const confirmations = blockNumber.minus(transaction.blockNumber).plus(1);
const value = Math.min(confirmations.toNumber(), maxConfirmations);
let count;
if (confirmations.gt(maxConfirmations)) {
count = confirmations.toFormat(0);
} else {
count = confirmations.toFormat(0) + `/${maxConfirmations}`;
}
const unit = value === 1 ? 'confirmation' : 'confirmations';
return (
<div className={ styles.confirm }>
<LinearProgress
@ -106,9 +121,10 @@ class TxHash extends Component {
max={ maxConfirmations }
value={ value }
color='white'
mode='determinate' />
mode='determinate'
/>
<div className={ styles.progressinfo }>
{ txBlock } / { confirmations } confirmations
<abbr title={ `block #${blockNumber.toFormat(0)}` }>{ count } { unit }</abbr>
</div>
</div>
);

View File

@ -37,6 +37,7 @@ import Modal, { Busy as BusyStep, Completed as CompletedStep } from './Modal';
import muiTheme from './Theme';
import Page from './Page';
import ParityBackground from './ParityBackground';
import ShortenedHash from './ShortenedHash';
import SignerIcon from './SignerIcon';
import Tags from './Tags';
import Tooltips, { Tooltip } from './Tooltips';
@ -79,6 +80,7 @@ export {
Page,
ParityBackground,
RadioButtons,
ShortenedHash,
SignerIcon,
Tags,
Tooltip,

19
js/src/util/is-testnet.js Normal file
View File

@ -0,0 +1,19 @@
// 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';
};

View File

@ -0,0 +1,77 @@
// 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 EventEmitter from 'eventemitter3';
const defaults = {
from: 0, // TODO
to: 'latest',
timeout: null,
filter: () => true
};
const subscribeToEvent = (contract, name, opt = {}) => {
opt = Object.assign({}, defaults, opt);
let subscription = null;
let timeout = null;
const unsubscribe = () => {
if (subscription) {
contract.unsubscribe(subscription);
subscription = null;
}
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
};
const emitter = new EventEmitter();
emitter.unsubscribe = unsubscribe;
if (typeof opt.timeout === 'number') {
timeout = setTimeout(() => {
unsubscribe();
emitter.emit('timeout');
}, opt.timeout);
}
const callback = (err, logs) => {
if (err) {
return emitter.emit('error', err);
}
for (let log of logs) {
if (opt.filter(log)) {
emitter.emit('log', log);
}
}
};
contract.subscribe(name, {
fromBlock: opt.from, toBlock: opt.to
}, callback)
.then((_subscription) => {
subscription = _subscription;
})
.catch((err) => {
emitter.emit('error', err);
});
return emitter;
};
export default subscribeToEvent;

View File

@ -19,6 +19,7 @@ import React, { Component, PropTypes } from 'react';
import moment from 'moment';
import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui';
import ShortenedHash from '../../../../ui/ShortenedHash';
import { txLink, addressLink } from '../../../../3rdparty/etherscan/links';
import styles from '../transactions.css';
@ -95,7 +96,7 @@ export default class Transaction extends Component {
href={ txLink(transaction.hash, isTest) }
target='_blank'
>
{ this.formatHash(transaction.hash) }
<ShortenedHash data={ transaction.hash } />
</a>
</div>
</td>
@ -150,14 +151,6 @@ export default class Transaction extends Component {
);
}
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
formatNumber (number) {
return new BigNumber(number).toFormat();
}

View File

@ -47,6 +47,7 @@ class Account extends Component {
params: PropTypes.object,
accounts: PropTypes.object,
isTestnet: PropTypes.bool,
balances: PropTypes.object
}
@ -65,8 +66,9 @@ class Account extends Component {
componentDidMount () {
const { api } = this.context;
const { address } = this.props.params;
const { isTestnet } = this.props;
const verificationStore = new VerificationStore(api, address);
const verificationStore = new VerificationStore(api, address, isTestnet);
this.setState({ verificationStore });
this.setVisibleAccounts();
}
@ -326,11 +328,13 @@ class Account extends Component {
function mapStateToProps (state) {
const { accounts } = state.personal;
const { isTest } = state.nodeStatus;
const { balances } = state.balances;
const { images } = state;
return {
accounts,
isTestnet: isTest,
balances,
images
};

View File

@ -92,7 +92,7 @@ class Accounts extends Component {
const loadings = ((accounts && Object.keys(accounts)) || []).map((_, idx) => (
<div key={ idx } className={ styles.loading }>
<div></div>
<div />
</div>
));

View File

@ -19,6 +19,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
import { Tab as MUITab } from 'material-ui/Tabs';
import { isEqual } from 'lodash';
import { Badge, Tooltip } from '../../../ui';
@ -162,9 +163,13 @@ class TabBar extends Component {
}
shouldComponentUpdate (nextProps, nextState) {
const prevViews = this.props.views.map((v) => v.id).sort();
const nextViews = nextProps.views.map((v) => v.id).sort();
return (nextProps.hash !== this.props.hash) ||
(nextProps.pending.length !== this.props.pending.length) ||
(nextState.activeViewId !== this.state.activeViewId);
(nextState.activeViewId !== this.state.activeViewId) ||
(!isEqual(prevViews, nextViews));
}
render () {
@ -192,7 +197,7 @@ class TabBar extends Component {
return (
<ToolbarGroup>
<div className={ styles.last }>
<div></div>
<div />
</div>
</ToolbarGroup>
);
@ -206,7 +211,7 @@ class TabBar extends Component {
.map((view, index) => {
const body = (view.id === 'accounts')
? (
<Tooltip className={ styles.tabbarTooltip } text='navigate between the different parts and views of the application, switching between an account view, token view and distributed application view' />
<Tooltip className={ styles.tabbarTooltip } text='navigate between the different parts and views of the application, switching between an account view, token view and distributed application view' />
)
: null;
@ -217,7 +222,7 @@ class TabBar extends Component {
active={ active }
view={ view }
onChange={ this.onChange }
key={ index }
key={ view.id }
pendings={ pending.length }
>
{ body }

View File

@ -19,6 +19,7 @@ import moment from 'moment';
import React, { Component, PropTypes } from 'react';
import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui';
import ShortenedHash from '../../../../ui/ShortenedHash';
import { txLink } from '../../../../3rdparty/etherscan/links';
import styles from '../../contract.css';
@ -71,7 +72,7 @@ export default class Event extends Component {
<div className={ styles.eventType }>
{ event.type }({ keys })
</div>
<a href={ url } target='_blank'>{ this.formatHash(event.transactionHash) }</a>
<a href={ url } target='_blank'><ShortenedHash data={ event.transactionHash } /></a>
</td>
<td className={ styles.eventDetails }>
<div className={ styles.eventParams }>
@ -82,14 +83,6 @@ export default class Event extends Component {
);
}
formatHash (hash) {
if (!hash || hash.length <= 16) {
return hash;
}
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
}
renderAddressName (address, withName = true) {
return (
<span className={ styles.eventAddress }>

View File

@ -65,8 +65,7 @@ export default class Dapp extends Component {
name={ name }
sandbox='allow-forms allow-popups allow-same-origin allow-scripts'
scrolling='auto'
src={ src }>
</iframe>
src={ src } />
);
}
}

View File

@ -51,8 +51,7 @@ export default class AddDapps extends Component {
] }
visible
scroll>
<div className={ styles.warning }>
</div>
<div className={ styles.warning } />
{ this.renderList(store.sortedLocal, 'Applications locally available', 'All applications installed locally on the machine by the user for access by the Parity client.') }
{ this.renderList(store.sortedBuiltin, 'Applications bundled with Parity', 'Experimental applications developed by the Parity team to show off dapp capabilities, integration, experimental features and to control certain network-wide client behaviour.') }
{ this.renderList(store.sortedNetwork, 'Applications on the global network', 'These applications are not affiliated with Parity nor are they published by Parity. Each remain under the control of their respective authors. Please ensure that you understand the goals for each application before interacting.') }

View File

@ -130,9 +130,15 @@ export default class DappsStore {
}
_getHost (api) {
return process.env.NODE_ENV === 'production'
const host = process.env.DAPPS_URL || (process.env.NODE_ENV === 'production'
? this._api.dappsUrl
: '';
: '');
if (host === '/') {
return '';
}
return host;
}
_fetchBuiltinApps () {

View File

@ -19,6 +19,7 @@
.transaction {
flex: 1;
overflow: auto;
}
.transaction > * {

View File

@ -80,7 +80,7 @@ export default class TransactionPendingForm extends Component {
onClick={ this.onToggleReject }
className={ styles.rejectToggle }
>
{ html }
{ html }
</a>
);
}

View File

@ -62,7 +62,7 @@ export default class Calls extends Component {
onClick={ this.clearHistory }
className={ styles.removeIcon }
>
<i className='icon-trash'></i>
<i className='icon-trash' />
</a>
);
}

View File

@ -140,7 +140,7 @@ export default class EditableValue extends Component {
title={ `Reset to ${this.props.defaultValue}` }
{ ...this._testInherit('reset') }
>
<i className='icon-anchor'></i>
<i className='icon-anchor' />
</a>
);
}
@ -154,7 +154,7 @@ export default class EditableValue extends Component {
onClick={ this.onSubmit }
{ ...this._testInherit('submit') }
>
<i className='icon-check'></i>
<i className='icon-check' />
</a>,
<a
key={ 'cancel' }
@ -162,7 +162,7 @@ export default class EditableValue extends Component {
onClick={ this.onCancel }
{ ...this._testInherit('cancel') }
>
<i className='icon-close'></i>
<i className='icon-close' />
</a>
];
}
@ -175,7 +175,7 @@ export default class EditableValue extends Component {
title='Edit'
{ ...this._testInherit('edit') }
>
<i className='icon-pencil'></i>
<i className='icon-pencil' />
</a>
);
}

View File

@ -53,7 +53,7 @@ export default class JsonEditor extends Component {
className={ `${styles.editor} ${errorClass}` }
value={ this.state.value }
/>
{ this.renderError() }
{ this.renderError() }
</div>
);
}

View File

@ -66,7 +66,7 @@ export default class RpcCalls extends Component {
</div>
</div>
</div>
<div style={ { clear: 'both' } }></div>
<div style={ { clear: 'both' } } />
<div className='dapp-container'>
<div className='row'>
<div className='col col-6 mobile-full'>

View File

@ -46,7 +46,7 @@ class RpcDocs extends Component {
</div>
</div>
</div>
<div style={ { clear: 'both' } }></div>
<div style={ { clear: 'both' } } />
<div className='dapp-container'>
<div className='row'>
<div className='col col-12'>

View File

@ -24,10 +24,10 @@ export default class RpcNav extends Component {
return (
<div className={ styles.nav }>
<Link to={ '/rpc/calls' } activeClassName={ styles.activeNav } { ...this._test('rpc-calls-link') }>
<i className='icon-call-out'></i>
<i className='icon-call-out' />
</Link>
<Link to={ '/rpc/docs' } activeClassName={ styles.activeNav } { ...this._test('rpc-docs-link') }>
<i className='icon-docs'></i>
<i className='icon-docs' />
</Link>
</div>
);

View File

@ -118,8 +118,7 @@ class WriteContract extends Component {
<span
className={ styles.slider }
onMouseDown={ this.handleStartResize }
>
</span>
/>
</div>
<div

View File

@ -24,17 +24,17 @@ const SNIPPETS = {
snippet0: {
name: 'Token.sol',
description: 'Standard ERP20 Token Contract',
id: 'snippet0', sourcecode: require('raw!../../contracts/snippets/token.sol')
id: 'snippet0', sourcecode: require('raw-loader!../../contracts/snippets/token.sol')
},
snippet1: {
name: 'StandardToken.sol',
description: 'Implementation of ERP20 Token Contract',
id: 'snippet1', sourcecode: require('raw!../../contracts/snippets/standard-token.sol')
id: 'snippet1', sourcecode: require('raw-loader!../../contracts/snippets/standard-token.sol')
},
snippet2: {
name: 'HumanStandardToken.sol',
description: 'Implementation of the Human Token Contract',
id: 'snippet2', sourcecode: require('raw!../../contracts/snippets/human-standard-token.sol')
id: 'snippet2', sourcecode: require('raw-loader!../../contracts/snippets/human-standard-token.sol')
}
};

View File

@ -1,238 +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 HappyPack = require('happypack');
const path = require('path');
const postcssImport = require('postcss-import');
const postcssNested = require('postcss-nested');
const postcssVars = require('postcss-simple-vars');
const rucksack = require('rucksack-css');
const webpack = require('webpack');
const WebpackErrorNotificationPlugin = require('webpack-error-notification');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ENV = process.env.NODE_ENV || 'development';
const isProd = ENV === 'production';
const DEST = process.env.BUILD_DEST || '.build';
module.exports = {
debug: !isProd,
cache: !isProd,
devtool: isProd ? '#eval' : '#cheap-module-eval-source-map',
context: path.join(__dirname, './src'),
entry: {
// dapps
'basiccoin': ['./dapps/basiccoin.js'],
'dappreg': ['./dapps/dappreg.js'],
'githubhint': ['./dapps/githubhint.js'],
'registry': ['./dapps/registry.js'],
'signaturereg': ['./dapps/signaturereg.js'],
'localtx': ['./dapps/localtx.js'],
'tokenreg': ['./dapps/tokenreg.js'],
// app
'index': ['./index.js']
},
output: {
path: path.join(__dirname, DEST),
filename: '[name].js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [ 'happypack/loader?id=js' ]
},
{
test: /\.js$/,
include: /node_modules\/material-ui-chip-input/,
loader: 'babel'
},
{
test: /\.json$/,
loaders: ['json']
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]!extract-loader!html-loader'
},
{
test: /\.css$/,
include: [/src/],
loaders: [ 'happypack/loader?id=css' ]
},
{
test: /\.css$/,
exclude: [/src/],
loader: 'style!css'
},
{
test: /\.(png|jpg)$/,
loader: 'file-loader?name=[name].[hash].[ext]'
},
{
test: /\.(woff(2)|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader'
}
],
noParse: [
/node_modules\/sinon/
]
},
resolve: {
root: path.join(__dirname, 'node_modules'),
fallback: path.join(__dirname, 'node_modules'),
extensions: ['', '.js', '.jsx'],
unsafeCache: true
},
resolveLoaders: {
root: path.join(__dirname, 'node_modules'),
fallback: path.join(__dirname, 'node_modules')
},
htmlLoader: {
root: path.resolve(__dirname, 'assets/images'),
attrs: ['img:src', 'link:href']
},
postcss: [
postcssImport({
addDependencyTo: webpack
}),
postcssNested({}),
postcssVars({
unknown: function (node, name, result) {
node.warn(result, `Unknown variable ${name}`);
}
}),
rucksack({
autoprefixer: true
})
],
plugins: (function () {
const plugins = [
new HappyPack({
id: 'css',
threads: 4,
loaders: [
'style',
'css?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
'postcss'
]
}),
new HappyPack({
id: 'js',
threads: 4,
loaders: isProd ? ['babel'] : [
'react-hot',
'babel?cacheDirectory=true'
]
}),
new CopyWebpackPlugin([{ from: './error_pages.css', to: 'styles.css' }], {}),
new WebpackErrorNotificationPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(ENV),
RPC_ADDRESS: JSON.stringify(process.env.RPC_ADDRESS),
PARITY_URL: JSON.stringify(process.env.PARITY_URL),
LOGGING: JSON.stringify(!isProd)
}
}),
new webpack.DllReferencePlugin({
context: '.',
manifest: require(`./${DEST}/vendor-manifest.json`)
})
];
if (!isProd) {
plugins.push(
new webpack.optimize.CommonsChunkPlugin({
filename: 'commons.js',
name: 'commons'
})
);
}
if (isProd) {
plugins.push(
new webpack.optimize.CommonsChunkPlugin({
chunks: ['index'],
name: 'commons'
})
);
plugins.push(new webpack.optimize.OccurrenceOrderPlugin(false));
plugins.push(new webpack.optimize.DedupePlugin());
plugins.push(new webpack.optimize.UglifyJsPlugin({
screwIe8: true,
compress: {
warnings: false
},
output: {
comments: false
}
}));
}
return plugins;
}()),
devServer: {
contentBase: `./${DEST}`,
historyApiFallback: false,
quiet: false,
hot: !isProd,
proxy: [
{
context: (pathname, req) => {
return pathname === '/' && req.method === 'HEAD';
},
target: 'http://127.0.0.1:8180',
changeOrigin: true,
autoRewrite: true
},
{
context: '/api',
target: 'http://127.0.0.1:8080',
changeOrigin: true,
autoRewrite: true
},
{
context: '/app',
target: 'http://127.0.0.1:8080',
changeOrigin: true,
pathRewrite: {
'^/app': ''
}
},
{
context: '/parity-utils',
target: 'http://127.0.0.1:3000',
changeOrigin: true,
pathRewrite: {
'^/parity-utils': ''
}
},
{
context: '/rpc',
target: 'http://127.0.0.1:8080',
changeOrigin: true
}
]
}
};

158
js/webpack/app.js Normal file
View File

@ -0,0 +1,158 @@
// 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 webpack = require('webpack');
const path = require('path');
const WebpackErrorNotificationPlugin = require('webpack-error-notification');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Shared = require('./shared');
const DAPPS = require('../src/dapps');
const FAVICON = path.resolve(__dirname, '../assets/images/parity-logo-black-no-text.png');
const DEST = process.env.BUILD_DEST || '.build';
const ENV = process.env.NODE_ENV || 'development';
const isProd = ENV === 'production';
module.exports = {
cache: !isProd,
devtool: isProd ? '#eval' : '#cheap-module-eval-source-map',
context: path.join(__dirname, '../src'),
entry: Object.assign({}, Shared.dappsEntry, {
index: './index.js'
}),
output: {
publicPath: '/',
path: path.join(__dirname, '../', DEST),
filename: '[name].[hash].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// use: [ 'happypack/loader?id=js' ]
use: isProd ? ['babel-loader'] : [
'babel-loader?cacheDirectory=true'
],
options: Shared.getBabelrc()
},
{
test: /\.js$/,
include: /node_modules\/material-ui-chip-input/,
use: [ 'babel-loader' ]
},
{
test: /\.json$/,
use: [ 'json-loader' ]
},
{
test: /\.html$/,
use: [
'file-loader?name=[name].[ext]!extract-loader',
{
loader: 'html-loader',
options: {
root: path.resolve(__dirname, '../assets/images'),
attrs: ['img:src', 'link:href']
}
}
]
},
{
test: /\.css$/,
include: [ /src/ ],
// use: [ 'happypack/loader?id=css' ]
use: [
'style-loader',
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
'postcss-loader'
]
},
{
test: /\.css$/,
exclude: [ /src/ ],
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.(png|jpg)$/,
use: [ 'file-loader?name=[name].[hash].[ext]' ]
},
{
test: /\.(woff(2)|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [ 'file-loader' ]
}
],
noParse: [
/node_modules\/sinon/
]
},
resolve: {
modules: [
path.join(__dirname, '../node_modules')
],
extensions: ['.json', '.js', '.jsx'],
unsafeCache: true
},
plugins: (function () {
const plugins = Shared.getPlugins().concat([
new CopyWebpackPlugin([{ from: './error_pages.css', to: 'styles.css' }], {}),
new WebpackErrorNotificationPlugin(),
new webpack.DllReferencePlugin({
context: '.',
manifest: require(`../${DEST}/vendor-manifest.json`)
}),
new HtmlWebpackPlugin({
title: 'Parity',
filename: 'index.html',
template: './index.ejs',
favicon: FAVICON,
chunks: [ isProd ? null : 'commons', 'index' ]
})
], DAPPS.map((dapp) => {
return new HtmlWebpackPlugin({
title: dapp.title,
filename: dapp.name + '.html',
template: './dapps/index.ejs',
favicon: FAVICON,
secure: dapp.secure,
chunks: [ isProd ? null : 'commons', dapp.name ]
});
}));
if (!isProd) {
plugins.push(
new webpack.optimize.CommonsChunkPlugin({
filename: 'commons.[hash].js',
name: 'commons',
minChunks: Infinity
})
);
}
return plugins;
}())
};

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
// test only
/**
* Run `PARITY_URL="127.0.0.1:8180" NODE_ENV="production" npm run build`
* Run `DAPPS_URL="/" PARITY_URL="127.0.0.1:8180" NODE_ENV="production" npm run build`
* to build the project ; use this server to test that the minifed
* version is working (this is a simple proxy server)
*/
@ -23,39 +23,17 @@
var express = require('express');
var proxy = require('http-proxy-middleware');
var Shared = require('./shared');
var app = express();
var wsProxy = proxy('ws://127.0.0.1:8180', { changeOrigin: true });
Shared.addProxies(app);
app.use(express.static('.build'));
app.use('/api/*', proxy({
target: 'http://127.0.0.1:8080',
changeOrigin: true
}));
app.use('/app/*', proxy({
target: 'http://127.0.0.1:8080',
changeOrigin: true,
pathRewrite: {
'^/app': ''
}
}));
app.use('/parity-utils/*', proxy({
target: 'http://127.0.0.1:3000',
changeOrigin: true,
pathRewrite: {
'^/parity-utils': ''
}
}));
app.use('/rpc/*', proxy({
target: 'http://127.0.0.1:8080',
changeOrigin: true
}));
app.use(wsProxy);
var server = app.listen(3000);
var server = app.listen(process.env.PORT || 3000, function () {
console.log('Listening on port', server.address().port);
});
server.on('upgrade', wsProxy.upgrade);

80
js/webpack/dev.server.js Normal file
View File

@ -0,0 +1,80 @@
// 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 webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const http = require('http');
const express = require('express');
const ProgressBar = require('progress');
const webpackConfig = require('./app');
const Shared = require('./shared');
let progressBar = { update: () => {} };
/**
* Add webpack hot middleware to each entry in the config
* and HMR to the plugins
*/
(function updateWebpackConfig () {
Object.keys(webpackConfig.entry).forEach((key) => {
const entry = webpackConfig.entry[key];
webpackConfig.entry[key] = [].concat(
'react-hot-loader/patch',
'webpack-hot-middleware/client?reload=true',
entry
);
});
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
webpackConfig.plugins.push(new webpack.NamedModulesPlugin());
webpackConfig.plugins.push(new webpack.NoErrorsPlugin());
webpackConfig.plugins.push(new webpack.ProgressPlugin(
(percentage) => progressBar.update(percentage)
));
})();
const app = express();
const compiler = webpack(webpackConfig);
app.use(webpackHotMiddleware(compiler, {
log: console.log
}));
app.use(webpackDevMiddleware(compiler, {
noInfo: false,
quiet: false,
progress: true,
publicPath: webpackConfig.output.publicPath,
stats: {
colors: true
}
}));
app.use(express.static(webpackConfig.output.path));
// Add the dev proxies in the express App
Shared.addProxies(app);
const server = http.createServer(app);
server.listen(process.env.PORT || 3000, function () {
console.log('Listening on port', server.address().port);
progressBar = new ProgressBar('[:bar] :percent :etas', { total: 50 });
});

View File

@ -16,16 +16,16 @@
// Run with `webpack --config webpack.libraries.js --progress`
const HappyPack = require('happypack');
const path = require('path');
const webpack = require('webpack');
const Shared = require('./shared');
const DEST = process.env.BUILD_DEST || '.build';
const ENV = process.env.NODE_ENV || 'development';
const isProd = ENV === 'production';
const DEST = process.env.BUILD_DEST || '.build';
module.exports = {
context: path.join(__dirname, './src'),
context: path.join(__dirname, '../src'),
entry: {
// library
'inject': ['./web3.js'],
@ -33,59 +33,31 @@ module.exports = {
'parity': ['./parity.js']
},
output: {
path: path.join(__dirname, DEST),
path: path.join(__dirname, '../', DEST),
filename: '[name].js',
library: '[name].js',
libraryTarget: 'umd'
},
module: {
loaders: [
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'happypack/loader?id=js'
// use: [ 'happypack/loader?id=js' ]
use: isProd ? ['babel-loader'] : [
// 'react-hot-loader',
'babel-loader?cacheDirectory=true'
]
},
{
test: /\.json$/,
loaders: ['json']
use: [ 'json-loader' ]
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]'
use: [ 'file-loader?name=[name].[ext]' ]
}
]
},
plugins: (function () {
const plugins = [
new HappyPack({
id: 'js',
threads: 4,
loaders: [ 'babel' ]
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(ENV),
RPC_ADDRESS: JSON.stringify(process.env.RPC_ADDRESS),
PARITY_URL: JSON.stringify(process.env.PARITY_URL),
LOGGING: JSON.stringify(!isProd)
}
})
];
if (isProd) {
plugins.push(new webpack.optimize.OccurrenceOrderPlugin(false));
plugins.push(new webpack.optimize.DedupePlugin());
plugins.push(new webpack.optimize.UglifyJsPlugin({
screwIe8: true,
compress: {
warnings: false
},
output: {
comments: false
}
}));
}
return plugins;
}())
plugins: Shared.getPlugins()
};

View File

@ -15,19 +15,20 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const packageJson = require('./package.json');
const packageJson = require('../package.json');
const Shared = require('./shared');
const ENV = process.env.NODE_ENV || 'development';
const isProd = ENV === 'production';
module.exports = {
context: path.join(__dirname, './src'),
context: path.join(__dirname, '../src'),
target: 'node',
entry: 'library.js',
output: {
path: path.join(__dirname, '.npmjs'),
path: path.join(__dirname, '../.npmjs'),
filename: 'library.js',
library: 'Parity',
libraryTarget: 'umd',
@ -41,52 +42,45 @@ module.exports = {
noParse: [
/babel-polyfill/
],
loaders: [
rules: [
{
test: /(\.jsx|\.js)$/,
loader: 'babel',
// use: [ 'happypack/loader?id=js' ],
use: isProd ? ['babel-loader'] : [
// 'react-hot-loader',
'babel-loader?cacheDirectory=true'
],
exclude: /node_modules/
}
]
},
resolve: {
root: path.resolve('./src'),
extensions: ['', '.js']
modules: [
path.resolve('./src'),
path.join(__dirname, '../node_modules')
],
extensions: ['.json', '.js', '.jsx']
},
plugins: (function () {
const plugins = [
new CopyWebpackPlugin([
{
from: '../parity.package.json',
to: 'package.json',
transform: function (content, path) {
const json = JSON.parse(content.toString());
json.version = packageJson.version;
return new Buffer(JSON.stringify(json, null, ' '), 'utf-8');
}
},
{
from: '../LICENSE'
},
{
from: '../parity.md',
to: 'README.md'
}
], { copyUnmodified: true })
];
if (isProd) {
plugins.push(new webpack.optimize.UglifyJsPlugin({
screwIe8: true,
compress: {
warnings: false
},
output: {
comments: false
plugins: Shared.getPlugins().concat([
new CopyWebpackPlugin([
{
from: '../parity.package.json',
to: 'package.json',
transform: function (content, path) {
const json = JSON.parse(content.toString());
json.version = packageJson.version;
return new Buffer(JSON.stringify(json, null, ' '), 'utf-8');
}
}));
}
return plugins;
}())
},
{
from: '../LICENSE'
},
{
from: '../parity.md',
to: 'README.md'
}
], { copyUnmodified: true })
])
};

176
js/webpack/shared.js Normal file
View File

@ -0,0 +1,176 @@
// 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 webpack = require('webpack');
const path = require('path');
const fs = require('fs');
// const HappyPack = require('happypack');
const postcssImport = require('postcss-import');
const postcssNested = require('postcss-nested');
const postcssVars = require('postcss-simple-vars');
const rucksack = require('rucksack-css');
const ENV = process.env.NODE_ENV || 'development';
const isProd = ENV === 'production';
function getBabelrc () {
const babelrc = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../.babelrc')));
const es2015Index = babelrc.presets.findIndex((p) => p === 'es2015');
// [ "es2015", { "modules": false } ]
babelrc.presets[es2015Index] = [ 'es2015', { modules: false } ];
babelrc['babelrc'] = false;
return babelrc;
}
function getPlugins (_isProd = isProd) {
const postcss = [
postcssImport({
addDependencyTo: webpack
}),
postcssNested({}),
postcssVars({
unknown: function (node, name, result) {
node.warn(result, `Unknown variable ${name}`);
}
}),
rucksack({
autoprefixer: true
})
];
const plugins = [
// NB: HappyPack is not yet working with Webpack 2... (as of Nov. 26)
// new HappyPack({
// id: 'css',
// threads: 4,
// loaders: [
// 'style-loader',
// 'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
// 'postcss-loader'
// ]
// }),
// new HappyPack({
// id: 'js',
// threads: 4,
// loaders: _isProd ? ['babel'] : [
// 'react-hot-loader',
// 'babel-loader?cacheDirectory=true'
// ]
// }),
// new HappyPack({
// id: 'babel',
// threads: 4,
// loaders: ['babel-loader']
// }),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(ENV),
RPC_ADDRESS: JSON.stringify(process.env.RPC_ADDRESS),
PARITY_URL: JSON.stringify(process.env.PARITY_URL),
DAPPS_URL: JSON.stringify(process.env.DAPPS_URL),
LOGGING: JSON.stringify(!isProd)
}
}),
new webpack.LoaderOptionsPlugin({
minimize: isProd,
debug: !isProd,
options: {
context: path.join(__dirname, '../src'),
postcss: postcss,
babel: getBabelrc()
}
}),
new webpack.optimize.OccurrenceOrderPlugin(!_isProd)
];
if (_isProd) {
plugins.push(new webpack.optimize.UglifyJsPlugin({
screwIe8: true,
compress: {
warnings: false
},
output: {
comments: false
}
}));
}
return plugins;
}
function getDappsEntry () {
const DAPPS = require('../src/dapps');
return DAPPS.reduce((_entry, dapp) => {
_entry[dapp.name] = './dapps/' + dapp.entry;
return _entry;
}, {});
}
function addProxies (app) {
const proxy = require('http-proxy-middleware');
app.use(proxy((pathname, req) => {
return pathname === '/' && req.method === 'HEAD';
}, {
target: 'http://127.0.0.1:8180',
changeOrigin: true,
autoRewrite: true
}));
app.use('/api', proxy({
target: 'http://127.0.0.1:8080',
changeOrigin: true,
autoRewrite: true
}));
app.use('/app', proxy({
target: 'http://127.0.0.1:8080',
changeOrigin: true,
pathRewrite: {
'^/app': ''
}
}));
app.use('/parity-utils', proxy({
target: 'http://127.0.0.1:3000',
changeOrigin: true,
pathRewrite: {
'^/parity-utils': ''
}
}));
app.use('/rpc', proxy({
target: 'http://127.0.0.1:8080',
changeOrigin: true
}));
}
module.exports = {
getBabelrc: getBabelrc,
getPlugins: getPlugins,
dappsEntry: getDappsEntry(),
addProxies: addProxies
};

View File

@ -14,11 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
const HappyPack = require('happypack');
const webpack = require('webpack');
const path = require('path');
const Shared = require('./shared');
const ENV = process.env.NODE_ENV || 'development';
const isProd = ENV === 'production';
const DEST = process.env.BUILD_DEST || '.build';
let modules = [
@ -45,69 +46,38 @@ let modules = [
'scryptsy'
];
if (!isProd) {
modules = modules.concat([
'webpack-dev-server/client?http://localhost:3000',
'react-hot-loader', 'core-js', 'core-js/library'
]);
}
module.exports = {
entry: {
vendor: modules
},
module: {
loaders: [
rules: [
{
test: /\.json$/,
loaders: ['json']
use: [ 'json-loader' ]
},
{
test: /\.js$/,
include: /(ethereumjs-tx)/,
loaders: [ 'happypack/loader?id=js' ]
use: [ 'babel-loader' ]
}
]
},
output: {
filename: '[name].js',
path: `${DEST}/`,
path: path.resolve(__dirname, '../', `${DEST}/`),
library: '[name]_lib'
},
plugins: (function () {
const plugins = [
new webpack.DllPlugin({
name: '[name]_lib',
path: `${DEST}/[name]-manifest.json`
}),
plugins: Shared.getPlugins().concat([
new webpack.DllPlugin({
name: '[name]_lib',
path: path.resolve(__dirname, '../', `${DEST}/[name]-manifest.json`)
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(ENV)
}
}),
new HappyPack({
id: 'js',
threads: 4,
loaders: ['babel']
})
];
if (isProd) {
plugins.push(new webpack.optimize.OccurrenceOrderPlugin(false));
plugins.push(new webpack.optimize.DedupePlugin());
plugins.push(new webpack.optimize.UglifyJsPlugin({
screwIe8: true,
compress: {
warnings: false
},
output: {
comments: false
}
}));
}
return plugins;
}())
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(ENV)
}
})
])
};

View File

@ -20,11 +20,11 @@ use std::sync::{Arc, Weak};
use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
use util::Address;
use util::{Address, U128, Uint};
use jsonrpc_core::Error;
use v1::traits::Personal;
use v1::types::{H160 as RpcH160, H256 as RpcH256, TransactionRequest};
use v1::types::{H160 as RpcH160, H256 as RpcH256, U128 as RpcU128, TransactionRequest};
use v1::helpers::errors;
use v1::helpers::dispatch::{self, sign_and_dispatch};
@ -72,15 +72,27 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
.map_err(|e| errors::account("Could not create account.", e))
}
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<u64>) -> Result<bool, Error> {
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<RpcU128>) -> Result<bool, Error> {
try!(self.active());
let account: Address = account.into();
let store = take_weak!(self.accounts);
let duration = match duration {
None => None,
Some(duration) => {
let duration: U128 = duration.into();
let v = duration.low_u64() as u32;
if duration != v.into() {
return Err(errors::invalid_params("Duration", "Invalid Number"));
} else {
Some(v)
}
},
};
let r = match (self.allow_perm_unlock, duration) {
(false, _) => store.unlock_account_temporarily(account, account_pass),
(true, Some(0)) => store.unlock_account_permanently(account, account_pass),
(true, Some(d)) => store.unlock_account_timed(account, account_pass, d as u32 * 1000),
(true, Some(d)) => store.unlock_account_timed(account, account_pass, d * 1000),
(true, None) => store.unlock_account_timed(account, account_pass, 300_000),
};
match r {

View File

@ -164,3 +164,45 @@ fn sign_and_send_transaction() {
assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response));
}
#[test]
fn should_unlock_account_temporarily() {
let tester = setup();
let address = tester.accounts.new_account("password123").unwrap();
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_unlockAccount",
"params": [
""#.to_owned() + &format!("0x{:?}", address) + r#"",
"password123",
"0x100"
],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(&request), Some(response.into()));
assert!(tester.accounts.sign(address, None, Default::default()).is_ok(), "Should unlock account.");
}
#[test]
fn should_unlock_account_permanently() {
let tester = setup();
let address = tester.accounts.new_account("password123").unwrap();
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_unlockAccount",
"params": [
""#.to_owned() + &format!("0x{:?}", address) + r#"",
"password123",
null
],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(&request), Some(response.into()));
assert!(tester.accounts.sign(address, None, Default::default()).is_ok(), "Should unlock account.");
}

View File

@ -18,7 +18,7 @@
use jsonrpc_core::Error;
use v1::helpers::auto_args::Wrap;
use v1::types::{H160, H256, TransactionRequest};
use v1::types::{U128, H160, H256, TransactionRequest};
build_rpc_trait! {
/// Personal rpc interface. Safe (read-only) functions.
@ -34,7 +34,7 @@ build_rpc_trait! {
/// Unlocks specified account for use (can only be one unlocked account at one moment)
#[rpc(name = "personal_unlockAccount")]
fn unlock_account(&self, H160, String, Option<u64>) -> Result<bool, Error>;
fn unlock_account(&self, H160, String, Option<U128>) -> Result<bool, Error>;
/// Sends transaction and signs it in single call. The account is not unlocked in such case.
#[rpc(name = "personal_signAndSendTransaction")]

View File

@ -124,7 +124,7 @@ impl Serialize for FilterChanges {
mod tests {
use serde_json;
use std::str::FromStr;
use util::hash::*;
use util::hash::H256;
use super::{VariadicValue, Topic, Filter};
use v1::types::BlockNumber;
use ethcore::filter::Filter as EthFilter;

View File

@ -50,6 +50,6 @@ pub use self::receipt::Receipt;
pub use self::rpc_settings::RpcSettings;
pub use self::trace::{LocalizedTrace, TraceResults};
pub use self::trace_filter::TraceFilter;
pub use self::uint::U256;
pub use self::uint::{U128, U256};
pub use self::work::Work;
pub use self::histogram::Histogram;

View File

@ -18,7 +18,7 @@ use std::cmp;
use std::str::FromStr;
use rustc_serialize::hex::ToHex;
use serde;
use util::{U256 as EthU256, Uint};
use util::{U256 as EthU256, U128 as EthU128, Uint};
macro_rules! impl_uint {
($name: ident, $other: ident, $size: expr) => {
@ -98,6 +98,7 @@ macro_rules! impl_uint {
}
}
impl_uint!(U128, EthU128, 2);
impl_uint!(U256, EthU256, 4);

View File

@ -111,6 +111,7 @@ known_heap_size!(0, PeerInfo);
type PacketDecodeError = DecoderError;
const PROTOCOL_VERSION_63: u8 = 63;
const PROTOCOL_VERSION_62: u8 = 62;
const PROTOCOL_VERSION_1: u8 = 1;
const MAX_BODIES_TO_SEND: usize = 256;
const MAX_HEADERS_TO_SEND: usize = 512;
@ -607,7 +608,7 @@ impl ChainSync {
trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, self.network_id, peer.network_id);
return Ok(());
}
if (warp_protocol && peer.protocol_version != PROTOCOL_VERSION_1) || (!warp_protocol && peer.protocol_version != PROTOCOL_VERSION_63) {
if (warp_protocol && peer.protocol_version != PROTOCOL_VERSION_1) || (!warp_protocol && peer.protocol_version != PROTOCOL_VERSION_63 && peer.protocol_version != PROTOCOL_VERSION_62) {
io.disable_peer(peer_id);
trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version);
return Ok(());
@ -1415,7 +1416,7 @@ impl ChainSync {
/// Send Status message
fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), NetworkError> {
let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer) != 0;
let protocol = if warp_protocol { PROTOCOL_VERSION_1 } else { PROTOCOL_VERSION_63 };
let protocol = if warp_protocol { PROTOCOL_VERSION_1 } else { io.eth_protocol_version(peer) };
trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol);
let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 });
let chain = io.chain().chain_info();