Subscriptions return unsubscribe/dispose function (#527)

* Combinator return unsubscribe/dispose function

* Submittable extrinsics return UnsubFunction

* RPC methods with unsub callback returns

* Update changelog, bump version

* CHANGELOG typo

* Fix combinator unsubscribes

* Be explicit in returns for UnsubFunction (combineLatest)
This commit is contained in:
Jaco Greeff
2019-01-03 16:31:09 +01:00
committed by GitHub
parent 15d75f7166
commit 3be56ad56c
19 changed files with 173 additions and 137 deletions
+10
View File
@@ -1,3 +1,13 @@
# 0.36.1
Api Promise has been updated in the way we deal with subscriptions. Previously a subscription returned `Promise<number>` where the caller was to keep track of the id and use it in subsequent unsubscribes. Now any subscriptions return an unsubscribe/destroy function `(): void`, that is use for removing the subscriptions, e.g.
```js
const unsubscribe = api.query.balance.freeBalanceOf(Alice, (balance) => {...});
unsubscribe(); // here we destroy the subscription
```
# 0.35.1
Swapped to new metadata structures from Substrate. If the API is not working with your node, update Substrate to latest master branch. (Or 0.9.1 for Charred Cherry). Dropped support for old metadata as found as far back as BBQ Birch.
+1 -1
View File
@@ -9,5 +9,5 @@
"packages": [
"packages/*"
],
"version": "0.35.19"
"version": "0.36.0"
}
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-observable",
"version": "0.35.19",
"version": "0.36.0",
"description": "An Observable wrapper around the Polkadot JS API",
"main": "index.js",
"keywords": [
@@ -30,10 +30,10 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-rx#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/extrinsics": "^0.35.19",
"@polkadot/rpc-core": "^0.35.19",
"@polkadot/rpc-provider": "^0.35.19",
"@polkadot/storage": "^0.35.19",
"@polkadot/extrinsics": "^0.36.0",
"@polkadot/rpc-core": "^0.36.0",
"@polkadot/rpc-provider": "^0.36.0",
"@polkadot/storage": "^0.36.0",
"@types/rx": "^4.1.1",
"rxjs": "^6.3.3"
}
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api",
"version": "0.35.19",
"version": "0.36.0",
"description": "An RxJS wrapper around the Polkadot JS RPC",
"main": "index.js",
"keywords": [
@@ -30,11 +30,11 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/extrinsics": "^0.35.19",
"@polkadot/rpc-provider": "^0.35.19",
"@polkadot/rpc-rx": "^0.35.19",
"@polkadot/storage": "^0.35.19",
"@polkadot/types": "^0.35.19",
"@polkadot/extrinsics": "^0.36.0",
"@polkadot/rpc-provider": "^0.36.0",
"@polkadot/rpc-rx": "^0.36.0",
"@polkadot/storage": "^0.36.0",
"@polkadot/types": "^0.36.0",
"@types/rx": "^4.1.1",
"rxjs": "^6.3.3"
}
+14 -43
View File
@@ -2,31 +2,27 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { UnsubFunction } from './types';
import { isFunction } from '@polkadot/util';
export type CombinatorCallback = (value: Array<any>) => any;
export type CombinatorFunction = {
(cb: (value: any) => any): Promise<any>,
unsubscribe?: (subscriptionsId: number) => Promise<any>
(cb: (value: any) => any): UnsubFunction | any
};
let combinatorId = 5000;
const allCombinators: { [index: number]: Combinator } = {};
export default class Combinator {
protected _allHasFired: boolean = false;
protected _callback: CombinatorCallback;
protected _fired: Array<boolean> = [];
protected _fns: Array<CombinatorFunction> = [];
protected _id: number = ++combinatorId;
protected _isActive: boolean = true;
protected _results: Array<any> = [];
protected _subscriptionIds: Array<Promise<number>> = [];
protected _unsubscriptions: Array<UnsubFunction | any> = [];
constructor (fns: Array<CombinatorFunction | [Array<any>, CombinatorFunction]>, callback: CombinatorCallback) {
allCombinators[this._id] = this;
this._callback = callback;
this._subscriptionIds = fns.map((input, index): Promise<number> => {
this._unsubscriptions = fns.map((input, index) => {
const [args, fn] = Array.isArray(input)
? input
: [[], input];
@@ -39,22 +35,6 @@ export default class Combinator {
});
}
static lookup (id: number): Combinator {
return allCombinators[id];
}
static unsubscribe (id: number): Promise<any> {
const combinator = Combinator.lookup(id);
return combinator
? combinator.unsubscribe()
: Promise.resolve(false);
}
get id (): number {
return this._id;
}
protected allHasFired (): boolean {
if (!this._allHasFired) {
this._allHasFired = this._fired.filter((hasFired) => !hasFired).length === 0;
@@ -73,7 +53,7 @@ export default class Combinator {
}
protected triggerUpdate (): void {
if (!isFunction(this._callback) || !this.allHasFired()) {
if (!this._isActive || !isFunction(this._callback) || !this.allHasFired()) {
return;
}
@@ -84,22 +64,13 @@ export default class Combinator {
}
}
unsubscribe (): Promise<any> {
delete allCombinators[this._id];
unsubscribe (): void {
this._isActive = false;
return Promise.all(
this._subscriptionIds.map((subscriptionPromise, index) => {
const unsubscribe = this._fns[index].unsubscribe;
return !unsubscribe
? Promise.resolve(true)
: subscriptionPromise
.then((subscriptionId) =>
unsubscribe(subscriptionId)
)
.then(() => true)
.catch(() => false);
})
);
this._unsubscriptions.forEach((unsubscribe) => {
if (isFunction(unsubscribe)) {
unsubscribe();
}
});
}
}
+2 -14
View File
@@ -80,12 +80,7 @@ describe('Combinator', () => {
});
it('unsubscribes as required', (done) => {
const mocker = () => Promise.resolve(12345);
mocker.unsubscribe = async (subId: number) => {
if (subId === 12345) {
done();
}
};
const mocker = () => done;
const combinator = new Combinator([
mocker,
() => Promise.resolve(98765)
@@ -93,13 +88,6 @@ describe('Combinator', () => {
// ignore
});
combinator
.unsubscribe()
.then(() => {
// ignore
})
.catch(() => {
// ignore
});
combinator.unsubscribe();
});
});
@@ -5,7 +5,7 @@
import { KeyringPair } from '@polkadot/keyring/types';
import { AnyNumber, AnyU8a } from '@polkadot/types/types';
import { SubmittableSendResult } from '../types';
import { ApiPromiseInterface } from './types';
import { ApiPromiseInterface, UnsubFunction } from './types';
import { EventRecord, Extrinsic, ExtrinsicStatus, Hash, Method, SignedBlock } from '@polkadot/types/index';
@@ -41,7 +41,7 @@ export default class SubmittableExtrinsic extends Extrinsic {
};
}
send (statusCb?: (result: SubmittableSendResult) => any): Promise<Hash> {
send (statusCb?: (result: SubmittableSendResult) => any): Promise<Hash> | UnsubFunction {
if (!statusCb || !this._api.hasSubscriptions) {
return this._api.rpc.author.submitExtrinsic(this);
}
+68 -16
View File
@@ -2,9 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { RpcInterface$Section$Method } from '@polkadot/rpc-core/types';
import { ProviderInterface } from '@polkadot/rpc-provider/types';
import { ApiOptions } from '../types';
import { ApiPromiseInterface, QueryableStorageFunction, QueryableModuleStorage, QueryableStorage, SubmittableExtrinsics, SubmittableModuleExtrinsics, SubmittableExtrinsicFunction } from './types';
import { ApiPromiseInterface, DecoratedRpc, DecoratedRpc$Method, DecoratedRpc$Section, QueryableStorageFunction, QueryableModuleStorage, QueryableStorage, SubmittableExtrinsics, SubmittableModuleExtrinsics, SubmittableExtrinsicFunction, UnsubFunction } from './types';
import Rpc from '@polkadot/rpc-core/index';
import { Storage } from '@polkadot/storage/types';
@@ -12,12 +13,16 @@ import { Hash } from '@polkadot/types/index';
import { Codec } from '@polkadot/types/types';
import { MethodFunction, ModulesWithMethods } from '@polkadot/types/Method';
import { StorageFunction } from '@polkadot/types/StorageKey';
import { isFunction, logger } from '@polkadot/util';
import { isFunction, logger, assert } from '@polkadot/util';
import ApiBase from '../Base';
import Combinator, { CombinatorCallback, CombinatorFunction } from './Combinator';
import SubmittableExtrinsic from './SubmittableExtrinsic';
const NOOP = () => {
// ignore
};
const l = logger('api/promise');
/**
@@ -106,7 +111,7 @@ const l = logger('api/promise');
* });
* ```
*/
export default class ApiPromise extends ApiBase<Rpc, QueryableStorage, SubmittableExtrinsics> implements ApiPromiseInterface {
export default class ApiPromise extends ApiBase<DecoratedRpc, QueryableStorage, SubmittableExtrinsics> implements ApiPromiseInterface {
private _isReady: Promise<ApiPromise>;
/**
@@ -173,8 +178,50 @@ export default class ApiPromise extends ApiBase<Rpc, QueryableStorage, Submittab
return this._isReady;
}
protected decorateRpc (rpc: Rpc): Rpc {
return rpc;
protected decorateRpc (rpc: Rpc): DecoratedRpc {
const names = ['author', 'chain', 'state', 'system'] as Array<keyof DecoratedRpc>;
return names.reduce((result, section) => {
result[section] = Object.keys(rpc[section]).reduce((fns, method) => {
fns[method] = this.decorateMethod(rpc[section][method]);
return fns;
}, {} as DecoratedRpc$Section);
return result;
}, {} as DecoratedRpc);
}
protected decorateMethod (fn: RpcInterface$Section$Method): DecoratedRpc$Method {
if (!isFunction(fn.unsubscribe)) {
return fn;
}
return (..._params: Array<any>): UnsubFunction => {
const cb = _params[_params.length - 1];
assert(isFunction(cb), 'Expected callback as last paramater for subscription');
let isActive = true;
const params = _params
.slice(0, _params.length - 1)
.concat([(value?: any) => {
return !isActive
? undefined
: cb(value);
}]);
const subscriptionIdPromise = fn(...params);
return (): void => {
if (!isActive) {
return;
}
isActive = false;
subscriptionIdPromise
.then((subscriptionId) => fn.unsubscribe(subscriptionId))
.catch(NOOP);
};
};
}
/**
@@ -197,8 +244,12 @@ export default class ApiPromise extends ApiBase<Rpc, QueryableStorage, Submittab
* });
* ```
*/
combineLatest (fns: Array<CombinatorFunction>, callback: CombinatorCallback): Combinator {
return new Combinator(fns, callback);
combineLatest (fns: Array<CombinatorFunction>, callback: CombinatorCallback): UnsubFunction {
const combinator = new Combinator(fns, callback);
return (): void => {
combinator.unsubscribe();
};
}
protected decorateExtrinsics (extrinsics: ModulesWithMethods): SubmittableExtrinsics {
@@ -237,7 +288,13 @@ export default class ApiPromise extends ApiBase<Rpc, QueryableStorage, Submittab
}
private decorateStorageEntry (method: StorageFunction): QueryableStorageFunction {
const decorated: any = (...args: Array<any>): Promise<Codec | null | undefined> | Promise<number> => {
const subscribe = (...args: Array<any>) =>
this.rpc.state.subscribeStorage(
[[method, args.length === 1 ? undefined : args[0]]],
(result: Array<Codec | null | undefined> = []) =>
args[args.length - 1](result[0])
) as UnsubFunction;
const decorated: any = (...args: Array<any>): Promise<Codec | null | undefined> | UnsubFunction => {
if (args.length === 0 || !isFunction(args[args.length - 1])) {
return this.rpc.state.getStorage([method, args[0]]);
} else if (!this.hasSubscriptions && isFunction(args[args.length - 1])) {
@@ -246,17 +303,12 @@ export default class ApiPromise extends ApiBase<Rpc, QueryableStorage, Submittab
return this.rpc.state.getStorage([method, args.length === 1 ? undefined : args[0]]);
}
return this.rpc.state.subscribeStorage(
[[method, args.length === 1 ? undefined : args[0]]],
(result: Array<Codec | null | undefined> = []) =>
args[args.length - 1](result[0])
);
return subscribe;
};
decorated.at = (hash: Hash, arg?: any): Promise<Codec | null | undefined> =>
this.rpc.state.getStorage([method, arg], hash);
decorated.unsubscribe = (subscriptionId: number): Promise<any> =>
this.rpc.state.subscribeStorage.unsubscribe(subscriptionId);
this.rpc.state.getStorage([method, arg], hash) as Promise<Codec | null | undefined>;
decorated.subscribe = subscribe;
return this.decorateFunctionMeta(method, decorated) as QueryableStorageFunction;
}
+21 -6
View File
@@ -8,16 +8,31 @@ import { MethodFunction } from '@polkadot/types/Method';
import { StorageFunction } from '@polkadot/types/StorageKey';
import { ApiBaseInterface } from '../types';
import Rpc from '@polkadot/rpc-core/index';
import SubmittableExtrinsic from './SubmittableExtrinsic';
export type UnsubFunction = () => void;
export type DecoratedRpc$Method = (...params: Array<any>) => Promise<any> | UnsubFunction;
export interface DecoratedRpc$Section {
[index: string]: DecoratedRpc$Method;
}
export interface DecoratedRpc {
author: DecoratedRpc$Section;
chain: DecoratedRpc$Section;
state: DecoratedRpc$Section;
system: DecoratedRpc$Section;
}
export interface QueryableStorageFunction extends StorageFunction {
(cb: (value?: any | null) => any): UnsubFunction;
(arg: any, cb: (value?: any | null) => any): UnsubFunction;
(arg?: any): Promise<Codec | null | undefined>;
(cb: (value: any) => any): Promise<number>;
(arg: any, cb: (value: any) => any): Promise<number>;
at: (hash: Hash, arg?: any) => Promise<Codec | null | undefined>;
unsubscribe: (subscriptionId: number) => Promise<any>;
// This one is slightly more sane with regards to type-checking, requiring less boilerplate to
// coax the intent of the the actual function with a split between subs and calls
subscribe: ((arg: any, cb: (value?: any | null) => any) => UnsubFunction) | ((cb: (value?: any | null) => any) => UnsubFunction);
}
export interface QueryableModuleStorage {
@@ -40,7 +55,7 @@ export interface SubmittableExtrinsics {
[index: string]: SubmittableModuleExtrinsics;
}
export interface ApiPromiseInterface extends ApiBaseInterface<Rpc, QueryableStorage, SubmittableExtrinsics> {
export interface ApiPromiseInterface extends ApiBaseInterface<DecoratedRpc, QueryableStorage, SubmittableExtrinsics> {
readonly isReady: Promise<ApiPromiseInterface>;
}
+2 -1
View File
@@ -18,7 +18,8 @@ export interface ApiBaseInterface<R, S, E> {
readonly rpc: R;
readonly tx: E;
on: (type: ApiInterface$Events, handler: (...args: Array<any>) => any) => void;
on: (type: ApiInterface$Events, handler: (...args: Array<any>) => any) => this;
once: (type: ApiInterface$Events, handler: (...args: Array<any>) => any) => this;
}
export interface ApiOptions {
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/rpc-core",
"version": "0.35.19",
"version": "0.36.0",
"description": "A JavaScript wrapper for the Polkadot JsonRPC interface",
"main": "index.js",
"keywords": [
@@ -30,9 +30,9 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-core#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/jsonrpc": "^0.35.19",
"@polkadot/rpc-provider": "^0.35.19",
"@polkadot/types": "^0.35.19",
"@polkadot/util": "^0.33.27"
"@polkadot/jsonrpc": "^0.36.0",
"@polkadot/rpc-provider": "^0.36.0",
"@polkadot/types": "^0.36.0",
"@polkadot/util": "^0.33.28"
}
}
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/rpc-provider",
"version": "0.35.19",
"version": "0.36.0",
"description": "Transport providers for the API",
"main": "index.js",
"keywords": [
@@ -30,10 +30,10 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-provider#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/keyring": "^0.33.27",
"@polkadot/storage": "^0.35.19",
"@polkadot/util": "^0.33.27",
"@polkadot/util-crypto": "^0.33.27",
"@polkadot/keyring": "^0.33.28",
"@polkadot/storage": "^0.36.0",
"@polkadot/util": "^0.33.28",
"@polkadot/util-crypto": "^0.33.28",
"@types/nock": "^9.3.0",
"eventemitter3": "^3.1.0",
"isomorphic-fetch": "^2.2.1",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/rpc-rx",
"version": "0.35.19",
"version": "0.36.0",
"description": "An RxJs wrapper around the Polkadot JS API",
"main": "index.js",
"keywords": [
@@ -30,8 +30,8 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-rx#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/rpc-core": "^0.35.19",
"@polkadot/rpc-provider": "^0.35.19",
"@polkadot/rpc-core": "^0.36.0",
"@polkadot/rpc-provider": "^0.36.0",
"@types/rx": "^4.1.1",
"rxjs": "^6.3.3"
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/extrinsics",
"version": "0.35.19",
"version": "0.36.0",
"main": "index.js",
"repository": "https://github.com/polkadot-js/api.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,7 +11,7 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/types": "^0.35.19",
"@polkadot/util": "^0.33.27"
"@polkadot/types": "^0.36.0",
"@polkadot/util": "^0.33.28"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/jsonrpc",
"version": "0.35.19",
"version": "0.36.0",
"description": "Method definitions for the Polkadot RPC layer",
"main": "index.js",
"engines": {
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/storage",
"version": "0.35.19",
"version": "0.36.0",
"description": "Generic wrapper wrapper around state storage",
"main": "index.js",
"engines": {
@@ -30,9 +30,9 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-storage#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/keyring": "^0.33.27",
"@polkadot/types": "^0.35.19",
"@polkadot/util": "^0.33.27",
"@polkadot/util-crypto": "^0.33.27"
"@polkadot/keyring": "^0.33.28",
"@polkadot/types": "^0.36.0",
"@polkadot/util": "^0.33.28",
"@polkadot/util-crypto": "^0.33.28"
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/types",
"version": "0.35.19",
"version": "0.36.0",
"description": "Implementation of the Parity codec",
"main": "index.js",
"keywords": [
@@ -30,8 +30,8 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/types#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/keyring": "^0.33.27",
"@polkadot/util": "^0.33.27",
"@polkadot/keyring": "^0.33.28",
"@polkadot/util": "^0.33.28",
"core-js": "^2.6.1"
}
}
+2 -3
View File
@@ -63,13 +63,12 @@ function addRpc () {
}).join(', ');
const type = '`' + method.type + '`';
const isSub = method.isSubscription;
const renderMethod = `${md}\n▸ **${methodName}**(${args})`;
const renderMethod = `${md}\n▸ **${methodName}**(${args}`;
const renderReturnType = `: ${type}`;
const renderSignature = `${renderMethod}${renderReturnType}`;
const renderSignatureSub = `${renderMethod}**.subscribe**(CALLBACK)${renderReturnType}`;
const renderSummary = `${method && method.description ? `\n- **summary**: ${method.description}\n` : `\n\n`}`;
return isSub ? `${renderSignatureSub}${renderSummary}` : `${renderSignature}${renderSummary}`;
return `${renderSignature}${isSub ? ', CALLBACK' : ''})${renderSummary}`;
}, renderSection);
}, renderHeading + renderAnchors);
}
+15 -15
View File
@@ -1417,14 +1417,14 @@
typedoc-plugin-no-inherit "^1.0.2"
typescript "^3.2.2"
"@polkadot/keyring@^0.33.27":
version "0.33.27"
resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-0.33.27.tgz#f8b89bcf5e5a0975e72a7c146e78f4a727ccc697"
integrity sha512-khZe+jNggZ0LY6HA+mEKWXcdsHYDuW6eVNk3JMKK4MjdVfVRJ1Ep7dm2lMiHeJtXknJz57qzPKLelPI4YbQe8A==
"@polkadot/keyring@^0.33.28":
version "0.33.28"
resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-0.33.28.tgz#4b71941cab21b248d4b79e7f6520aa6566cc9110"
integrity sha512-b5XN16vPZgWzCKPGkjbeYpfGAlznSu2XON8I+//Fz6h44JxcihhysqqyYQmODAEg6ktolbKI18eHjN3eMQBqxA==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/util" "^0.33.27"
"@polkadot/util-crypto" "^0.33.27"
"@polkadot/util" "^0.33.28"
"@polkadot/util-crypto" "^0.33.28"
"@types/bs58" "^3.0.30"
bs58 "^4.0.1"
@@ -1433,13 +1433,13 @@
resolved "https://registry.yarnpkg.com/@polkadot/ts/-/ts-0.1.44.tgz#2fb28215f10b869bfa544fd8df8fccb4932d64f2"
integrity sha512-tor7vSd3ZsRBO9FIuKZQ9hfqEGkNZnanAFVGmoL1iSmdhcoKtYTlQe0BQafjIynqIMOfXdJ7Zes9PlorPtw6yw==
"@polkadot/util-crypto@^0.33.27":
version "0.33.27"
resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.33.27.tgz#efea792ebe43fa679e924f303bdcb6857c28e6d4"
integrity sha512-ZdlcUnPJOerbgbYJgMQHtGz8SGUr43geZ5/QIE4v8SkdSnwP6MKEvve/G2AkzmXIUZsLMpfW5k3CRsEFNHd1lQ==
"@polkadot/util-crypto@^0.33.28":
version "0.33.28"
resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.33.28.tgz#4f3b191511c3e0ca1e5c3a2a149cb01c9f291e08"
integrity sha512-FrRehpn+pNUWaxctn1soOctl7XQfB+L54FW9R8846GkY6XyrAlZVMQipxNC5oUb9O13gkxmvfB5holFKj8F6Kg==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/util" "^0.33.27"
"@polkadot/util" "^0.33.28"
"@types/bip39" "^2.4.1"
bip39 "^2.5.0"
blakejs "^1.1.0"
@@ -1447,10 +1447,10 @@
tweetnacl "^1.0.0"
xxhashjs "^0.2.2"
"@polkadot/util@^0.33.27":
version "0.33.27"
resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.33.27.tgz#982e9afdd648731c88690ab6208512ca3bcde1ab"
integrity sha512-jLYx8dcTag6ACdYybeGWBkmpQj7DsTZ2mCqInhQFCuYmb1h7P7QK/RRDrCQ+Ai3yHfHol8pq/k/oQrgKXpyt6g==
"@polkadot/util@^0.33.28":
version "0.33.28"
resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.33.28.tgz#e6b0fb680cae40038344bc197d15a18eec095826"
integrity sha512-4RMuTJ4iAX8eBbUtVK+og0ZIgirQor+eF77fULfzVEJyDL5+SigM7H0v8gCIYL0I6ClHDENijI6P9FrQpRABFQ==
dependencies:
"@babel/runtime" "^7.2.0"
"@types/bn.js" "^4.11.3"