diff --git a/src/Signer/Signer.js b/src/Signer/Signer.js
new file mode 100644
index 000000000..8541349f8
--- /dev/null
+++ b/src/Signer/Signer.js
@@ -0,0 +1,24 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import React, { Component } from 'react';
+import { Route } from 'react-router-dom';
+
+import SignerDetails from './SignerDetails';
+import SignerList from './SignerList';
+
+class Signer extends Component {
+ render () {
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+export default Signer;
diff --git a/src/Signer/SignerDetails/SignerDetails.js b/src/Signer/SignerDetails/SignerDetails.js
new file mode 100644
index 000000000..f82251380
--- /dev/null
+++ b/src/Signer/SignerDetails/SignerDetails.js
@@ -0,0 +1,92 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import React, { Component } from 'react';
+import { fromWei } from '@parity/api/lib/util/wei';
+import { inject, observer } from 'mobx-react';
+
+@inject('signerStore')
+@observer
+class SignerDetails extends Component {
+ state = {
+ password: ''
+ };
+
+ handleAccept = () => {
+ const {
+ match: {
+ params: { requestId }
+ },
+ signerStore
+ } = this.props;
+ const { password } = this.state;
+ signerStore.acceptRequest(requestId, password);
+ };
+
+ handleChangePassword = ({ target: { value } }) => {
+ this.setState({ password: value });
+ };
+
+ handleReject = () => {
+ const {
+ match: {
+ params: { requestId }
+ },
+ signerStore
+ } = this.props;
+ signerStore.rejectRequest(requestId);
+ };
+
+ handleSubmit = e => {
+ e.preventDefault();
+ };
+
+ render () {
+ const {
+ match: {
+ params: { requestId }
+ },
+ signerStore: { requests }
+ } = this.props;
+ const { password } = this.state;
+ const request = requests[requestId];
+
+ if (!request) {
+ // This happens after we accept/reject a request
+ return null;
+ }
+
+ const transaction = request.payload.sendTransaction;
+
+ return (
+
+ );
+ }
+}
+
+export default SignerDetails;
diff --git a/src/Signer/SignerDetails/index.js b/src/Signer/SignerDetails/index.js
new file mode 100644
index 000000000..7afc360dd
--- /dev/null
+++ b/src/Signer/SignerDetails/index.js
@@ -0,0 +1,8 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import SignerDetails from './SignerDetails';
+
+export default SignerDetails;
diff --git a/src/Signer/SignerList/SignerList.js b/src/Signer/SignerList/SignerList.js
new file mode 100644
index 000000000..a28706400
--- /dev/null
+++ b/src/Signer/SignerList/SignerList.js
@@ -0,0 +1,38 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import React, { Component } from 'react';
+import { fromWei } from '@parity/api/lib/util/wei';
+import { inject, observer } from 'mobx-react';
+import { Link } from 'react-router-dom';
+
+@inject('signerStore')
+@observer
+class SignerList extends Component {
+ render () {
+ const {
+ signerStore: { pending }
+ } = this.props;
+ return (
+
+ List of requests to be signed (click to sign):
+ {pending.map(({ id, payload: { sendTransaction: { value } } }) => (
+ -
+ {/* TODO inline style is bad */}
+
+ - The one with {+fromWei(value)}ETH (show to? from?)
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default SignerList;
diff --git a/src/Signer/SignerList/index.js b/src/Signer/SignerList/index.js
new file mode 100644
index 000000000..54c165f13
--- /dev/null
+++ b/src/Signer/SignerList/index.js
@@ -0,0 +1,8 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import SignerList from './SignerList';
+
+export default SignerList;
diff --git a/src/Signer/index.js b/src/Signer/index.js
new file mode 100644
index 000000000..decd33d47
--- /dev/null
+++ b/src/Signer/index.js
@@ -0,0 +1,8 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import Signer from './Signer';
+
+export default Signer;
diff --git a/src/stores/createAccountStore.js b/src/stores/createAccountStore.js
index 23ff68def..d9f60192b 100644
--- a/src/stores/createAccountStore.js
+++ b/src/stores/createAccountStore.js
@@ -15,29 +15,25 @@ class CreateAccountStore {
@observable phrase = null; // The 12-word seed phrase
constructor () {
- this.parityStore = parityStore;
+ this.api = parityStore.api;
}
generateNewAccount = () => {
- const { api } = this.parityStore;
-
- return api.parity
+ return this.api.parity
.generateSecretPhrase()
.then(phrase => {
this.setPhrase(phrase);
- return api.parity.phraseToAddress(phrase);
+ return this.api.parity.phraseToAddress(phrase);
})
.then(address => this.setAddress(address));
};
saveAccountToParity = () => {
- const { api } = this.parityStore;
-
- return api.parity
+ return this.api.parity
.newAccountFromPhrase(this.phrase, this.password)
- .then(address => api.parity.setAccountName(this.address, this.name))
+ .then(address => this.api.parity.setAccountName(this.address, this.name))
.then(() =>
- api.parity.setAccountMeta(this.address, {
+ this.api.parity.setAccountMeta(this.address, {
timestamp: Date.now(),
passwordHint: this.hint
})
diff --git a/src/stores/index.js b/src/stores/index.js
index ae43065f1..6e071f07b 100644
--- a/src/stores/index.js
+++ b/src/stores/index.js
@@ -5,10 +5,12 @@
import createAccountStore from './createAccountStore';
import parityStore from './parityStore';
+import signerStore from './signerStore';
import tokensStore from './tokensStore';
export default {
createAccountStore,
parityStore,
+ signerStore,
tokensStore
};
diff --git a/src/stores/signerStore.js b/src/stores/signerStore.js
new file mode 100644
index 000000000..785cca7a3
--- /dev/null
+++ b/src/stores/signerStore.js
@@ -0,0 +1,67 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+//
+// SPDX-License-Identifier: MIT
+
+import { action, computed, observable } from 'mobx';
+
+import parityStore from './parityStore';
+
+class SignerStore {
+ @observable pending = [];
+
+ constructor () {
+ this.api = parityStore.api;
+
+ if (parityStore.isApiConnected) {
+ this.subscribePending();
+ } else {
+ // TODO This .on() is not working, so we poll every second
+ // this.api.on('connected', this.subscribePending);
+ this.interval = setInterval(() => {
+ if (parityStore.isApiConnected) {
+ this.subscribePending();
+ clearInterval(this.interval);
+ }
+ }, 1000);
+ }
+ }
+
+ acceptRequest = (requestId, password) =>
+ this.api.signer.confirmRequest(requestId, null, password);
+
+ rejectRequest = (requestId, password) =>
+ this.api.signer.rejectRequest(requestId, null, password);
+
+ @computed
+ get requests () {
+ const mapping = {}; // requestId -> request mapping
+ this.pending.forEach(request => {
+ mapping[request.id] = request;
+ });
+ return mapping;
+ }
+
+ @action
+ setPending = (pending = []) => {
+ this.pending = pending;
+ };
+
+ subscribePending = () => {
+ const callback = (err, pending) => {
+ if (err) {
+ throw new Error(err);
+ }
+
+ this.setPending(pending);
+ };
+
+ this.api
+ .subscribe('signer_requestsToConfirm', callback)
+ .then(() => this.api.signer.requestsToConfirm())
+ .then(pending => callback(null, pending))
+ .catch(callback);
+ };
+}
+
+export default new SignerStore();