* Fix broken transfer total balance (#4127) * Add proper label to method decoding inputs (#4136) * Another minor estimation fix (#4133) * Return 0 instead of error with out of gas on estimate_gas * Fix stuff up. * Another estimate gas fix. * Alter balance to maximum possible rather than GP=0. * Only increase to amount strictly necessary. * Get rid of unsafe code in ethkey, propagate incorrect Secret errors. (#4119) * Implementing secret * Fixing tests * Refactor VoteCollector (#4101) * dir * simple validator list * stub validator contract * make the engine hold Weak<Client> instead of IoChannel * validator set factory * register weak client with ValidatorContract * check chain security * add address array to generator * register provider contract * update validator set on notify * add validator contract spec * simple list test * split update and contract test * contract change * use client in tendermint * fix deadlock * step duration in params * adapt tendermint tests * add storage fields to test spec * constructor spec * execute under wrong address * create under correct address * revert * validator contract constructor * move genesis block lookup * add removal ability to contract * validator contract adding validators * fix basic authority * validator changing test * more docs * update sync tests * remove env_logger * another env_logger * cameltoe * hold EngineClient instead of Client * return error on misbehaviour * nicer return * sprinkle docs * Reenable mainnet update server. (#4137) * basic tests for subscribeToEvents (#4115) * subscribeToEvent fixtures ✅ * subscribeToEvent tests ✅ * temporarily skip failing test (#4138) * Improvements and optimisations to estimate_gas (#4142) * Return 0 instead of error with out of gas on estimate_gas * Fix stuff up. * Another estimate gas fix. * Alter balance to maximum possible rather than GP=0. * Only increase to amount strictly necessary. * Improvements and optimisations to estimate_gas. - Introduce proper error type - Avoid building costly traces * Fix tests. * Actually fix testsActually fix tests * Use estimateGas error (as per updated implementation) (#4131) * Use estimateGas error (as per updated implementation) * EXCEPTION_ERROR as per #4142 * Better error log reporting & handling (#4128) * Don't pop-up notifications after network switch (#4076) * Better notifications * Don't pollute with notifs if switched networks * Better connection close/open events / No more notifs on change network * PR Grumbles * Add close and open events to HTTP // Add tests * Fix tests * WIP Signer Fix * Fix Signer // Better reconnection handling * PR Grumbles * PR Grumbles * Fixes wrong fetching of balances + Notifications * Secure API WIP * Updated Secure API Connection + Status * Linting * Linting * Updated Secure API Logic * Proper handling of token updates // Fixing poping notifications * PR Grumbles * PR Grumbles * Fixing tests * Trim spaces from InputAddress (#4126) * Trim spaces for addresses * onSubmit has only value, not event * onSubmit (again) * Length check on trimmed value * Remove bindActionCreators({}, dispatch) (empty) (#4135)
284 lines
7.1 KiB
JavaScript
284 lines
7.1 KiB
JavaScript
// Copyright 2015, 2016 Parity Technologies (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 { action, computed, observable, transaction } from 'mobx';
|
|
import store from 'store';
|
|
|
|
import Contracts from '~/contracts';
|
|
import {
|
|
fetchBuiltinApps, fetchLocalApps,
|
|
fetchRegistryAppIds, fetchRegistryApp,
|
|
subscribeToChanges
|
|
} from '~/util/dapps';
|
|
|
|
const LS_KEY_DISPLAY = 'displayApps';
|
|
const LS_KEY_EXTERNAL_ACCEPT = 'acceptExternal';
|
|
const BUILTIN_APPS_KEY = 'BUILTIN_APPS_KEY';
|
|
|
|
let instance = null;
|
|
|
|
export default class DappsStore {
|
|
@observable apps = [];
|
|
@observable displayApps = {};
|
|
@observable modalOpen = false;
|
|
@observable externalOverlayVisible = true;
|
|
|
|
_api = null;
|
|
_subscriptions = {};
|
|
|
|
_cachedApps = {};
|
|
_manifests = {};
|
|
_registryAppsIds = null;
|
|
|
|
constructor (api) {
|
|
this._api = api;
|
|
|
|
this.readDisplayApps();
|
|
this.loadExternalOverlay();
|
|
this.subscribeToChanges();
|
|
}
|
|
|
|
/**
|
|
* Try to find the app from the local (local or builtin)
|
|
* apps, else fetch from the node
|
|
*/
|
|
loadApp (id) {
|
|
const { dappReg } = Contracts.get();
|
|
|
|
return this
|
|
.loadLocalApps()
|
|
.then(() => {
|
|
const app = this.apps.find((app) => app.id === id);
|
|
|
|
if (app) {
|
|
return app;
|
|
}
|
|
|
|
return this.fetchRegistryApp(dappReg, id, true);
|
|
});
|
|
}
|
|
|
|
loadLocalApps () {
|
|
return Promise
|
|
.all([
|
|
this.fetchBuiltinApps().then((apps) => this.addApps(apps)),
|
|
this.fetchLocalApps().then((apps) => this.addApps(apps))
|
|
]);
|
|
}
|
|
|
|
loadAllApps () {
|
|
const { dappReg } = Contracts.get();
|
|
|
|
return Promise
|
|
.all([
|
|
this.loadLocalApps(),
|
|
this.fetchRegistryApps(dappReg).then((apps) => this.addApps(apps))
|
|
])
|
|
.then(this.writeDisplayApps);
|
|
}
|
|
|
|
static get (api) {
|
|
if (!instance) {
|
|
instance = new DappsStore(api);
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
subscribeToChanges () {
|
|
const { dappReg } = Contracts.get();
|
|
|
|
// Unsubscribe from previous subscriptions, if any
|
|
if (this._subscriptions.block) {
|
|
this._api.unsubscribe(this._subscriptions.block);
|
|
}
|
|
|
|
if (this._subscriptions.filter) {
|
|
this._api.eth.uninstallFilter(this._subscriptions.filter);
|
|
}
|
|
|
|
// Subscribe to dapps reg changes
|
|
subscribeToChanges(this._api, dappReg, (appIds) => {
|
|
const updates = appIds.map((appId) => {
|
|
return this.fetchRegistryApp(dappReg, appId, true);
|
|
});
|
|
|
|
Promise
|
|
.all(updates)
|
|
.then((apps) => {
|
|
this.addApps(apps);
|
|
});
|
|
}).then((subscriptions) => {
|
|
this._subscriptions = subscriptions;
|
|
});
|
|
}
|
|
|
|
fetchBuiltinApps (force = false) {
|
|
if (!force && this._cachedApps[BUILTIN_APPS_KEY] !== undefined) {
|
|
return Promise.resolve(this._cachedApps[BUILTIN_APPS_KEY]);
|
|
}
|
|
|
|
this._cachedApps[BUILTIN_APPS_KEY] = fetchBuiltinApps()
|
|
.then((apps) => {
|
|
this._cachedApps[BUILTIN_APPS_KEY] = apps;
|
|
return apps;
|
|
});
|
|
|
|
return Promise.resolve(this._cachedApps[BUILTIN_APPS_KEY]);
|
|
}
|
|
|
|
fetchLocalApps () {
|
|
return fetchLocalApps(this._api);
|
|
}
|
|
|
|
fetchRegistryAppIds (force = false) {
|
|
if (!force && this._registryAppsIds) {
|
|
return Promise.resolve(this._registryAppsIds);
|
|
}
|
|
|
|
this._registryAppsIds = fetchRegistryAppIds()
|
|
.then((appIds) => {
|
|
this._registryAppsIds = appIds;
|
|
return this._registryAppsIds;
|
|
});
|
|
|
|
return Promise.resolve(this._registryAppsIds);
|
|
}
|
|
|
|
fetchRegistryApp (dappReg, appId, force = false) {
|
|
if (!force && this._cachedApps[appId] !== undefined) {
|
|
return Promise.resolve(this._cachedApps[appId]);
|
|
}
|
|
|
|
this._cachedApps[appId] = fetchRegistryApp(this._api, dappReg, appId)
|
|
.then((dapp) => {
|
|
this._cachedApps[appId] = dapp;
|
|
return dapp;
|
|
});
|
|
|
|
return Promise.resolve(this._cachedApps[appId]);
|
|
}
|
|
|
|
fetchRegistryApps (dappReg) {
|
|
return this
|
|
.fetchRegistryAppIds()
|
|
.then((appIds) => {
|
|
const promises = appIds.map((appId) => {
|
|
// Fetch the Dapp and display it ASAP
|
|
return this
|
|
.fetchRegistryApp(dappReg, appId)
|
|
.then((app) => {
|
|
if (app) {
|
|
this.addApps([ app ]);
|
|
}
|
|
|
|
return app;
|
|
});
|
|
});
|
|
|
|
return Promise.all(promises);
|
|
});
|
|
}
|
|
|
|
@computed get sortedBuiltin () {
|
|
return this.apps.filter((app) => app.type === 'builtin');
|
|
}
|
|
|
|
@computed get sortedLocal () {
|
|
return this.apps.filter((app) => app.type === 'local');
|
|
}
|
|
|
|
@computed get sortedNetwork () {
|
|
return this.apps.filter((app) => app.type === 'network');
|
|
}
|
|
|
|
@computed get visibleApps () {
|
|
return this.apps.filter((app) => this.displayApps[app.id] && this.displayApps[app.id].visible);
|
|
}
|
|
|
|
@computed get visibleBuiltin () {
|
|
return this.visibleApps.filter((app) => app.type === 'builtin');
|
|
}
|
|
|
|
@computed get visibleLocal () {
|
|
return this.visibleApps.filter((app) => app.type === 'local');
|
|
}
|
|
|
|
@computed get visibleNetwork () {
|
|
return this.visibleApps.filter((app) => app.type === 'network');
|
|
}
|
|
|
|
@action openModal = () => {
|
|
this.modalOpen = true;
|
|
}
|
|
|
|
@action closeModal = () => {
|
|
this.modalOpen = false;
|
|
}
|
|
|
|
@action closeExternalOverlay = () => {
|
|
this.externalOverlayVisible = false;
|
|
store.set(LS_KEY_EXTERNAL_ACCEPT, true);
|
|
}
|
|
|
|
@action loadExternalOverlay () {
|
|
this.externalOverlayVisible = !(store.get(LS_KEY_EXTERNAL_ACCEPT) || false);
|
|
}
|
|
|
|
@action hideApp = (id) => {
|
|
this.displayApps = Object.assign({}, this.displayApps, { [id]: { visible: false } });
|
|
this.writeDisplayApps();
|
|
}
|
|
|
|
@action showApp = (id) => {
|
|
this.displayApps = Object.assign({}, this.displayApps, { [id]: { visible: true } });
|
|
this.writeDisplayApps();
|
|
}
|
|
|
|
@action readDisplayApps = () => {
|
|
this.displayApps = store.get(LS_KEY_DISPLAY) || {};
|
|
}
|
|
|
|
@action writeDisplayApps = () => {
|
|
store.set(LS_KEY_DISPLAY, this.displayApps);
|
|
}
|
|
|
|
@action addApps = (_apps = []) => {
|
|
transaction(() => {
|
|
const apps = _apps.filter((app) => app);
|
|
|
|
// Get new apps IDs if available
|
|
const newAppsIds = apps
|
|
.map((app) => app.id)
|
|
.filter((id) => id);
|
|
|
|
this.apps = this.apps
|
|
.filter((app) => !app.id || !newAppsIds.includes(app.id))
|
|
.concat(apps || [])
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
const visibility = {};
|
|
apps.forEach((app) => {
|
|
if (!this.displayApps[app.id]) {
|
|
visibility[app.id] = { visible: app.visible };
|
|
}
|
|
});
|
|
|
|
this.displayApps = Object.assign({}, this.displayApps, visibility);
|
|
});
|
|
}
|
|
}
|