API formatting for inputs & outputs (#171)

* API formatting for inputs & outputs

* Shorten naming

* getStorage (signle key) operational

* Remove api-format (not used in api anymore)

* Cleanup creation logic

* Cleanup linting

* Cleanup storage creation

* e2e state test

* Add code test

* Add isBare flag to toU8a

* Uppercase... wtill wrong though

* Update metadata json

* We are creating keys properly

* Cleanup tslint

* Type splitting,m handling Tuple & Vector

* StorageChangeSet results in-place

* Update deps

* Allow Tuples to have array constructors

* Test for uncloded vec/tuple

* Update deps
This commit is contained in:
Jaco Greeff
2018-09-28 15:42:23 +02:00
committed by GitHub
parent 8380455599
commit 74737b6367
70 changed files with 748 additions and 697 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ const config = require('@polkadot/dev/config/jest');
module.exports = Object.assign({}, config, {
moduleNameMapper: {
'@polkadot/api-(codec|format|jsonrpc|provider|rx)(.*)$': '<rootDir>/packages/api-$1/src/$2',
'@polkadot/api-(codec|jsonrpc|provider|rx)(.*)$': '<rootDir>/packages/api-$1/src/$2',
'@polkadot/api(.*)$': '<rootDir>/packages/api/src/$1',
'@polkadot/extrinsics(.*)$': '<rootDir>/packages/type-extrinsics/src/$1',
'@polkadot/jsonrpc(.*)$': '<rootDir>/packages/type-jsonrpc/src/$1',
+2 -2
View File
@@ -30,7 +30,7 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-codec#readme",
"dependencies": {
"@babel/runtime": "^7.0.0",
"@polkadot/util": "^0.30.4",
"@polkadot/util-keyring": "^0.30.4"
"@polkadot/util": "^0.30.7",
"@polkadot/util-keyring": "^0.30.7"
}
}
+7 -5
View File
@@ -114,10 +114,12 @@ export default class Address extends Base<AccountId | AccountIndex> {
return this.raw.toString();
}
toU8a (): Uint8Array {
return u8aConcat(
Address.writeLength(this.raw.byteLength()),
this.raw.toU8a()
);
toU8a (isBare?: boolean): Uint8Array {
return isBare
? this.raw.toU8a(true)
: u8aConcat(
Address.writeLength(this.raw.byteLength()),
this.raw.toU8a(isBare)
);
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ export default class Bool extends Base<boolean> {
return this.raw;
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return new Uint8Array([this.raw ? 1 : 0]);
}
+2 -2
View File
@@ -48,9 +48,9 @@ export default class Bytes extends U8a {
return this;
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return u8aConcat(
this._length.toU8a(),
this._length.toU8a(isBare),
this.raw
);
}
+4 -2
View File
@@ -6,6 +6,7 @@ import { AnyU8a } from './types';
import Option from './codec/Option';
import Struct from './codec/Struct';
import Tuple from './codec/Tuple';
import StorageData from './StorageData';
import StorageKey from './StorageKey';
@@ -41,8 +42,9 @@ export type KeyValueOptionValue = {
};
// A key/value change. This is similar to the KeyValue structure,
// however in this case the value could be optional.
export class KeyValueOption extends Struct {
// however in this case the value could be optional. Here it extends
// from a Tuple, indicating the use inside areas such as StorageChangeSet
export class KeyValueOption extends Tuple {
constructor (value?: KeyValueOptionValue) {
super({
key: StorageKey,
File diff suppressed because one or more lines are too long
+39 -24
View File
@@ -2,6 +2,8 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { AnyNumber } from './types';
import Vector from './codec/Vector';
import Base from './codec/Base';
import Enum from './codec/Enum';
@@ -17,12 +19,12 @@ import U16 from './U16';
// end and work up. (Just so we don't use before definition)
export class EventMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
name: Text,
arguments: Vector.with(Type),
documentation: Vector.with(Text)
});
}, value);
}
get arguments (): Vector<Type> {
@@ -39,11 +41,11 @@ export class EventMetadata extends Struct {
}
export class OuterEventMetadataEvent extends Struct {
constructor () {
constructor (value?: any) {
super({
name: Text,
events: Vector.with(EventMetadata)
});
}, value);
}
get events (): Vector<EventMetadata> {
@@ -56,11 +58,11 @@ export class OuterEventMetadataEvent extends Struct {
}
export class OuterEventMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
name: Text,
events: Vector.with(OuterEventMetadataEvent)
});
}, value);
}
get events (): Vector<OuterEventMetadataEvent> {
@@ -73,11 +75,11 @@ export class OuterEventMetadata extends Struct {
}
export class FunctionArgumentMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
name: Text,
type: Type
});
}, value);
}
get name (): Text {
@@ -90,13 +92,13 @@ export class FunctionArgumentMetadata extends Struct {
}
export class FunctionMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
id: U16,
name: Text,
arguments: Vector.with(FunctionArgumentMetadata),
documentation: Vector.with(Text)
});
}, value);
}
get arguments (): Vector<FunctionArgumentMetadata> {
@@ -117,11 +119,11 @@ export class FunctionMetadata extends Struct {
}
export class CallMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
name: Text,
functions: Vector.with(FunctionMetadata)
});
}, value);
}
get functions (): Vector<FunctionMetadata> {
@@ -134,11 +136,11 @@ export class CallMetadata extends Struct {
}
export class ModuleMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
name: Text,
call: CallMetadata
});
}, value);
}
get call (): CallMetadata {
@@ -151,17 +153,17 @@ export class ModuleMetadata extends Struct {
}
export class StorageFunctionModifier extends Enum {
constructor () {
super(['None', 'Default', 'Required']);
constructor (value?: any) {
super(['None', 'Default', 'Required'], value);
}
}
export class StorageFunctionType$Map extends Struct {
constructor () {
constructor (value?: any) {
super({
key: Type,
value: Type
});
}, value);
}
get key (): Type {
@@ -192,16 +194,29 @@ export class StorageFunctionType extends EnumType<Type | StorageFunctionType$Map
get asType (): Type {
return (this.raw as Base<Type>).raw;
}
toString (): string {
return this.isMap
? this.asMap.value.toString()
: this.asType.toString();
}
}
type StorageFunctionMetadataValue = {
name?: string | Text,
modifier?: StorageFunctionModifier | AnyNumber,
type?: StorageFunctionType,
documentation?: Vector<Text> | Array<string>
};
export class StorageFunctionMetadata extends Struct {
constructor () {
constructor (value?: StorageFunctionMetadataValue) {
super({
name: Text,
modifier: StorageFunctionModifier,
type: StorageFunctionType,
documentation: Vector.with(Text)
});
}, value);
}
get documentation (): Vector<Text> {
@@ -222,11 +237,11 @@ export class StorageFunctionMetadata extends Struct {
}
export class StorageMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
prefix: Text,
functions: Vector.with(StorageFunctionMetadata)
});
}, value);
}
get functions (): Vector<StorageFunctionMetadata> {
@@ -239,12 +254,12 @@ export class StorageMetadata extends Struct {
}
export class RuntimeModuleMetadata extends Struct {
constructor () {
constructor (value?: any) {
super({
prefix: Text,
module: ModuleMetadata,
storage: Option.with(StorageMetadata)
});
}, value);
}
get module (): ModuleMetadata {
+13 -9
View File
@@ -5,6 +5,7 @@
import BN from 'bn.js';
import bnToBn from '@polkadot/util/bn/toBn';
import bnToU8a from '@polkadot/util/bn/toU8a';
import isU8a from '@polkadot/util/is/u8a';
import u8aToBn from '@polkadot/util/u8a/toBn';
import Base from './codec/Base';
@@ -16,8 +17,7 @@ const BITLENGTH = 64;
// per-second. For any encoding/decoding the 1000 multiplier would be applied to
// get it in line with JavaScript formats
export default class Moment extends Base<Date> {
// NOTE
constructor (value: Moment | Date | number = 0) {
constructor (value: Uint8Array | Moment | Date | number = 0) {
super(
value instanceof Date
? new Date(Math.ceil(value.getTime() / 1000) * 1000)
@@ -25,12 +25,16 @@ export default class Moment extends Base<Date> {
);
}
static decode (value: Moment | number | BN): Date {
return value instanceof Moment
? value.raw
: new Date(
bnToBn(value).toNumber() * 1000
);
static decode (value: Uint8Array | Moment | number | BN): Date {
if (value instanceof Moment) {
return value.raw;
} if (isU8a(value)) {
value = u8aToBn(value, true);
}
return new Date(
bnToBn(value).toNumber() * 1000
);
}
byteLength (): number {
@@ -55,7 +59,7 @@ export default class Moment extends Base<Date> {
return this.toNumber();
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return bnToU8a(this.toNumber(), BITLENGTH, true);
}
+57 -3
View File
@@ -2,8 +2,62 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Bytes from './Bytes';
import { AnyU8a } from './types';
// A representation of a storage key (typically hashed) in the system
export default class StorageKey extends Bytes {
import isFunction from '@polkadot/util/is/function';
import toU8a from '@polkadot/util/u8a/toU8a';
import U8a from './codec/U8a';
import Bytes from './Bytes';
import { StorageFunctionMetadata } from './Metadata';
export interface StorageFunction {
(arg?: any): Uint8Array;
meta: StorageFunctionMetadata;
}
// A representation of a storage key (typically hashed) in the system. It can be constructed
// by passing in a raw key or a StorageFunction with (optional) arguments.
export default class StorageKey extends Bytes {
private _outputType: string | null;
constructor (value: AnyU8a | StorageKey | StorageFunction | [StorageFunction, any]) {
super(StorageKey.encode(value));
this._outputType = StorageKey.getType(value as StorageKey);
}
static encode (value: AnyU8a | StorageKey | StorageFunction | [StorageFunction, any]): Uint8Array {
if (value instanceof StorageKey || value instanceof U8a) {
return value.raw;
} else if (isFunction(value)) {
return value();
} else if (Array.isArray(value)) {
const [fn, arg] = value;
if (isFunction(fn)) {
return fn(arg);
}
}
return toU8a(value);
}
static getType (value: StorageKey | StorageFunction | [StorageFunction, any]): string | null {
if (value instanceof StorageKey) {
return value.outputType;
} else if (isFunction(value)) {
return value.meta.type.toString();
} else if (Array.isArray(value)) {
const [fn] = value;
return fn.meta.type.toString();
}
return null;
}
get outputType (): string | null {
return this._outputType;
}
}
+2 -2
View File
@@ -66,14 +66,14 @@ export default class Text extends Base<string> {
return this.raw;
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
// NOTE Since we trim in the fromU8a, here we re-calculate the actual length
const encoded = u8aFromUtf8(this.raw);
this._length.setValue(encoded.length);
return u8aConcat(
this._length.toU8a(),
this._length.toU8a(isBare),
encoded
);
}
+1 -1
View File
@@ -33,7 +33,7 @@ export default class Type extends Text {
// Note Since we are mangling what we get in beyond recognition, we really should
// not allow the re-encoding. Additionally, this is probably more of a decoder-only
// helper, so treat it as such.
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
throw new Error('Type::toU8a: unimplemented');
}
+5 -1
View File
@@ -2,6 +2,10 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import logger from '@polkadot/util/logger';
export const l = logger('codec');
// The actual base class for any type. As it stands, this should not be used on it's own,
// so we expose the interface, but throw on anything. This allows subclasses to actaully
// only implement part (things that are unused/unexpected should just error-out)
@@ -38,7 +42,7 @@ export default class Base <T = any> {
throw new Error('Base::toString: unimplemented');
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
throw new Error('Base::toU8a: unimplemented');
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ export default class Enum extends Base<number> {
return this.raw;
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return new Uint8Array([this.raw]);
}
+9 -2
View File
@@ -21,7 +21,7 @@ export default class EnumType <T> extends Base<Base<T>> {
private _index: number;
private _indexes: Array<number>;
constructor (def: TypesDef, index?: number, value?: any) {
constructor (def: TypesDef, index?: number | EnumType<T>, value?: any) {
super(
new (Object.values(def)[0])()
);
@@ -52,7 +52,14 @@ export default class EnumType <T> extends Base<Base<T>> {
return this;
}
setValue (index?: number, value?: any): void {
setValue (index?: | EnumType<T> | number, value?: any): void {
if (index instanceof EnumType) {
this._index = index._index;
this.raw = new this._Types[this._index](index.raw);
return;
}
this._index = this._indexes.indexOf(index || 0);
if (this._index === -1) {
+4 -2
View File
@@ -95,8 +95,10 @@ export default class Length extends Base<BN> {
return this.raw.toNumber();
}
toU8a (): Uint8Array {
return Length.encode(this.raw);
toU8a (isBare?: boolean): Uint8Array {
return isBare
? new Uint8Array()
: Length.encode(this.raw);
}
setValue (value: BN | number): void {
+5 -1
View File
@@ -73,7 +73,11 @@ export default class Option <T> extends Base<Base<T>> {
: this.raw.toJSON();
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
if (isBare) {
return this.raw.toU8a(true);
}
const u8a = new Uint8Array(this.byteLength());
if (!this._isEmpty) {
+26 -15
View File
@@ -4,7 +4,7 @@
import u8aConcat from '@polkadot/util/u8a/concat';
import Base from './Base';
import Base, { l } from './Base';
// A Struct defines an Object with key/values - where the values are Base<T> values. It removes
// a lot of repetition from the actual coding, define a structure type, pass it the key/Base<T>
@@ -24,19 +24,9 @@ export default class Struct <
protected _jsonMap: Map<keyof S, string>;
protected _Types: E;
constructor (Types: S, value: V = {} as V, jsonMap: Map<keyof S, string> = new Map()) {
constructor (Types: S, value: V | Array<any> = {} as V, jsonMap: Map<keyof S, string> = new Map(), isTuple: boolean = false) {
super(
Object
.keys(Types)
.reduce((raw: T, key) => {
// @ts-ignore FIXME Ok, something weird is going on here or I just don't get it...
// it works, so ignore the checker, although it drives me batty. (It started when
// the [key in keyof T] was added, the idea is to provide better checks, which
// does backfire here, but works externally.)
raw[key] = new Types[key](value[key]);
return raw;
}, {} as T)
Struct.decode(Types, value, isTuple)
);
this._jsonMap = jsonMap;
@@ -50,6 +40,27 @@ export default class Struct <
}, {} as E);
}
static decode <S, V, T> (Types: S, value: V | Array<any>, isTuple: boolean): T {
l.debug(() => ['Struct.decode', { Types, value }]);
return Object
.keys(Types)
.reduce((raw: T, key, index) => {
// @ts-ignore FIXME Ok, something weird is going on here or I just don't get it...
// it works, so ignore the checker, although it drives me batty. (It started when
// the [key in keyof T] was added, the idea is to provide better checks, which
// does backfire here, but works externally.)
raw[key] = new Types[key](
isTuple && Array.isArray(value)
? value[index]
// @ts-ignore as above
: value[key]
);
return raw;
}, {} as T);
}
static with <
S = { [index: string]: { new(value?: any): Base } }
> (Types: S): { new(value?: any): Struct<S> } {
@@ -106,10 +117,10 @@ export default class Struct <
return Object.keys(this.raw);
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return u8aConcat(
...Object.values(this.raw).map((entry) =>
entry.toU8a()
entry.toU8a(isBare)
)
);
}
+9 -4
View File
@@ -9,10 +9,15 @@ import Struct from './Struct';
// is a specialization of the Struct type where the toJSON/fromJSON operates on Array structures,
// while the U8a encoding is handled in the same way as a Struct
export default class Tuple <
// S & T definitions maps to what we have in Struct (naming expanded there)
// S & T definitions maps to what we have in Struct (naming documented there)
S = { [index: string]: { new(value?: any): Base } },
T = { [K in keyof S]: Base }
> extends Struct<S, T> {
T = { [K in keyof S]: Base },
V = { [K in keyof S]: any }
> extends Struct<S, T, V> {
constructor (Types: S, value?: V | Array<any>, jsonMap?: Map<keyof S, string>) {
super(Types, value, jsonMap, true);
}
static with <
S = { [index: string]: { new(value?: any): Base } }
> (Types: S): { new(value?: any): Tuple<S> } {
@@ -23,7 +28,7 @@ export default class Tuple <
};
}
fromJSON (input: any): Tuple<S, T> {
fromJSON (input: any): Tuple<S, T, V> {
Object.values(this.raw).forEach((entry, index) => {
entry.fromJSON(input[index]);
});
+1 -1
View File
@@ -50,7 +50,7 @@ export default class U8a extends Base<Uint8Array> {
return this.toHex();
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return this.raw;
}
+5 -1
View File
@@ -7,6 +7,7 @@ import { AnyNumber } from '../types';
import BN from 'bn.js';
import isHex from '@polkadot/util/is/hex';
import isString from '@polkadot/util/is/string';
import isU8a from '@polkadot/util/is/u8a';
import bnToBn from '@polkadot/util/bn/toBn';
import bnToHex from '@polkadot/util/bn/toHex';
import bnToU8a from '@polkadot/util/bn/toU8a';
@@ -39,6 +40,9 @@ export default class UInt extends Base<BN> {
return value.raw;
} else if (isHex(value)) {
return hexToBn(value as string);
} else if (isU8a(value)) {
// NOTE When passing u8a in (typically from decoded data), it is always u8a
return u8aToBn(value, true);
} else if (isString(value)) {
return new BN(value, 10);
}
@@ -70,7 +74,7 @@ export default class UInt extends Base<BN> {
return this.toString();
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return bnToU8a(this.raw, this._bitLength, true);
}
+16 -7
View File
@@ -53,11 +53,15 @@ export default class Vector <
}, this._length.byteLength());
}
filter (fn: (entry: T, index?: number) => any): Array<T> {
filter (fn: (item: T, index?: number) => any): Array<T> {
return this.raw.filter(fn);
}
forEach (fn: (entry: T, index?: number) => any): any {
find (fn: (item: T, index?: number) => any): T | undefined {
return this.raw.find(fn);
}
forEach (fn: (item: T, index?: number) => any): any {
return this.raw.forEach(fn);
}
@@ -90,11 +94,16 @@ export default class Vector <
return this.raw[index];
}
map <O> (fn: (entry: T, index?: number) => O): Array<O> {
map <O> (fn: (item: T, index?: number) => O): Array<O> {
return this.raw.map(fn);
}
reduce <O> (fn: (result: O, entry: T, index?: number) => O, initial: O): O {
push (item: T): void {
this.raw.push(item);
this._length.setValue(this.raw.length);
}
reduce <O> (fn: (result: O, item: T, index?: number) => O, initial: O): O {
return this.raw.reduce(fn, initial);
}
@@ -104,11 +113,11 @@ export default class Vector <
);
}
toU8a (): Uint8Array {
toU8a (isBare?: boolean): Uint8Array {
return u8aConcat(
this._length.toU8a(),
this._length.toU8a(isBare),
...this.raw.map((entry) =>
entry.toU8a()
entry.toU8a(isBare)
)
);
}
@@ -0,0 +1,85 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { typeSplit, getType, getTupleType, getVectorType } from './createType';
describe('typeSplit', () => {
it('splits simple types into an array', () => {
expect(
typeSplit('Text, u32, u64')
).toEqual(['Text', 'u32', 'u64']);
});
it('splits nested combinations', () => {
expect(
typeSplit('Text, (u32), Vec<u64>')
).toEqual(['Text', '(u32)', 'Vec<u64>']);
});
it('keeps nested tuples together', () => {
expect(
typeSplit('Text, (u32, u128), Vec<u64>')
).toEqual(['Text', '(u32, u128)', 'Vec<u64>']);
});
it('keeps nested vector tuples together', () => {
expect(
typeSplit('Text, (u32, u128), Vec<(u64, u32)>')
).toEqual(['Text', '(u32, u128)', 'Vec<(u64, u32)>']);
});
it('allows for deep nesting', () => {
expect(
typeSplit('Text, (u32, (u128, u8)), Vec<(u64, (u32, u32))>')
).toEqual(['Text', '(u32, (u128, u8))', 'Vec<(u64, (u32, u32))>']);
});
it('checks for unclosed vec', () => {
expect(
() => typeSplit('Text, Vec<u64')
).toThrow(/Invalid Vector/);
});
it('checks for unclosed tuple', () => {
expect(
() => typeSplit('Text, (u64, u32')
).toThrow(/Invalid Tuple/);
});
});
describe('getTupleType', () => {
it('does not allow invalid tuples, end )', () => {
expect(
() => getTupleType('(u64, u32')
).toThrow(/tuple wrapped/);
});
it('does not allow invalid tuples, start (', () => {
expect(
() => getTupleType('u64, u32)')
).toThrow(/tuple wrapped/);
});
});
describe('getVectorType', () => {
it('does not allow invalid vectors, end >', () => {
expect(
() => getVectorType('Vec<u64')
).toThrow(/Vec wrapped/);
});
it('does not allow invalid vectors, start Vec<', () => {
expect(
() => getVectorType('u64>')
).toThrow(/Vec wrapped/);
});
});
describe('getType', () => {
it('does not allow invalid types', () => {
expect(
() => getType('SomethingInvalid')
).toThrow(/determine type/);
});
});
+123
View File
@@ -0,0 +1,123 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import assert from '@polkadot/util/assert';
import * as Types from '../index';
import Base, { l } from './Base';
import Tuple from './Tuple';
import Vector from './Vector';
type Constructor = { new (value?: any): Base };
// safely split a string on ', ' while taking care of any nested occurences
export function typeSplit (type: string): Array<string> {
let tDepth = 0;
let vDepth = 0;
let start = 0;
const result = [];
for (let index = 0; index < type.length; index++) {
switch (type[index]) {
case ',':
// we are not nested, add the type
if (tDepth === 0 && vDepth === 0) {
result.push(type.substr(start, index - start).trim());
start = index + 1;
}
break;
case '(':
// inc tuple depth
tDepth++;
break;
case ')':
// dec tuple depth
tDepth--;
break;
case '<':
// inc vec depth
vDepth++;
break;
case '>':
// dec tuple depth
vDepth--;
break;
default:
break;
}
}
assert(tDepth === 0, `Invalid Tuple in ${type}`);
assert(vDepth === 0, `Invalid Vector in ${type}`);
// the final leg of the journey
result.push(type.substr(start, type.length - start).trim());
return result;
}
// Handle Vector types, i.e Vec<AccountId> or Vec<(AccountId, Balance)>
export function getVectorType (type: string): Constructor {
l.debug(() => ['getVectorType', { type }]);
assert(type.substr(0, 4) === 'Vec<' && type[type.length - 1] === '>', `Expected Vec wrapped with <>`);
// strip wrapping Vec<>
const subType = type.substr(4, type.length - 5);
return Vector.with(
getType(subType)
);
}
// Handle tuple types, (u32, String, AccountId). It could be nested and wrapped in other
// types, i.e. (u32, Vec<(AccountId, Balance)>)
export function getTupleType (type: string): Constructor {
l.debug(() => ['getTupleType', { type }]);
assert(type[0] === '(' && type[type.length - 1] === ')', `Expected tuple wrapped with ()`);
// strip wrapping ()'s
const innerTypes = typeSplit(type.substr(1, type.length - 2));
return Tuple.with(
innerTypes.reduce((result, type, index) => {
result[`entry${index}`] = getType(type);
return result;
}, {} as { [index: string]: Constructor })
);
}
// Returns the type Class for construction
export function getType (_type: string): Constructor {
const type = _type.trim();
l.debug(() => ['getType', { type }]);
if (type[0] === '(') {
return getTupleType(type);
} else if (type.substr(0, 4) === 'Vec<') {
return getVectorType(type);
}
const Type = (Types as any)[type];
assert(Type, `Unable to determine type from '${type}'`);
return Type;
}
export default function createType (type: string, value?: any): Base {
l.debug(() => ['createType', { type, value }]);
const Type = getType(type);
return new Type(value);
}
+2
View File
@@ -11,3 +11,5 @@ export { default as Base } from './Base';
export { default as Struct } from './Struct';
export { default as Tuple } from './Tuple';
export { default as Vector } from './Vector';
export { default as createType } from './createType';
+7 -6
View File
@@ -52,12 +52,13 @@ export { default as StorageKey } from './StorageKey';
export { default as Text } from './Text';
// NOTE Type is currently only used internally (possibly in codec-related work)
// export { default as Type } from './Type';
export { default as U8 } from './U8';
export { default as U16 } from './U16';
export { default as U32 } from './U32';
export { default as U64 } from './U64';
export { default as U128 } from './U128';
export { default as U256 } from './U256';
// NOTE We are exporting the U* classes as lowercase, matching with Rust
export { default as u8 } from './U8';
export { default as u16 } from './U16';
export { default as u32 } from './U32';
export { default as u64 } from './U64';
export { default as u128 } from './U128';
export { default as u256 } from './U256';
export { default as ValidatorPrefs } from './ValidatorPrefs';
export { default as VoteThreshold } from './VoteThreshold';
export { default as VoteIndex } from './VoteIndex';
+1 -1
View File
@@ -7,6 +7,6 @@ import BN from 'bn.js';
import U8a from './codec/U8a';
import UInt from './codec/UInt';
export type AnyNumber = UInt | BN | number | string;
export type AnyNumber = UInt | BN | Uint8Array | number | string;
export type AnyU8a = U8a | Uint8Array | Array<number> | string;
View File
-15
View File
@@ -1,15 +0,0 @@
ISC License (ISC)
Copyright 2017-2018 @polkadot/api-format authors & contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
-21
View File
@@ -1,21 +0,0 @@
[![polkadotjs](https://img.shields.io/badge/polkadot-js-orange.svg?style=flat-square)](https://polkadot.js.org)
![isc](https://img.shields.io/badge/license-ISC-lightgrey.svg?style=flat-square)
[![style](https://img.shields.io/badge/code%20style-semistandard-lightgrey.svg?style=flat-square)](https://github.com/Flet/semistandard)
[![npm](https://img.shields.io/npm/v/@polkadot/api-format.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/api-format)
[![travis](https://img.shields.io/travis/polkadot-js/api.svg?style=flat-square)](https://travis-ci.org/polkadot-js/api)
[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/api.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/api/maintainability)
[![coverage](https://img.shields.io/coveralls/polkadot-js/api.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/api?branch=master)
[![dependency](https://david-dm.org/polkadot-js/api.svg?style=flat-square&path=packages/api-format)](https://david-dm.org/polkadot-js/api?path=packages/api-format)
[![devDependency](https://david-dm.org/polkadot-js/api/dev-status.svg?style=flat-square&path=packages/api-format)](https://david-dm.org/polkadot-js/api?path=packages/api-format#info=devDependencies)
# @polkadot/api-format
Formatters that are used by the application API interface, taking care of transparently formatting parameters (inputs) and the results (output) for requests made over the client RPC interfaces.
## Usage
Installation -
```
npm install --save @polkadot/api-format
```
-39
View File
@@ -1,39 +0,0 @@
{
"name": "@polkadot/api-format",
"version": "0.30.1",
"description": "Input/Output formatters for JsonRPC exchange",
"main": "index.js",
"keywords": [
"Polkadot",
"JsonRPC"
],
"author": "Jaco Greeff <jacogr@gmail.com>",
"maintainers": [
"Jaco Greeff <jacogr@gmail.com>"
],
"contributors": [],
"license": "ISC",
"engines": {
"node": ">=6.4"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"repository": {
"type": "git",
"url": "git+https://github.com/polkadot-js/api.git"
},
"bugs": {
"url": "https://github.com/polkadot-js/api/issues"
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-format#readme",
"dependencies": {
"@babel/runtime": "^7.0.0",
"@polkadot/api-codec": "^0.30.1",
"@polkadot/jsonrpc": "^0.30.1",
"@polkadot/primitives": "^0.30.1",
"@polkadot/util": "^0.30.4",
"@polkadot/util-keyring": "^0.30.4"
}
}
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import echo from './echo';
describe('echo', () => {
it('returns input value as output value', () => {
const input = { 'some': 'object' };
expect(
echo(input)
).toEqual(input);
});
});
-12
View File
@@ -1,12 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
/**
* A function returning any value passed to it
* @param {any} value The input value
* @return {any} The value passed as input
*/
export default function echo (value: any): any {
return value;
}
-77
View File
@@ -1,77 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import format from './format';
import echo from './echo';
describe('format', () => {
let formatters;
let echoSpy;
let warnSpy;
beforeEach(() => {
echoSpy = jest.fn(echo);
warnSpy = jest.spyOn(console, 'log');
formatters = new Map([
['Address', echoSpy],
['Exception', () => {
throw new Error('something went wrong');
}]
]);
});
afterEach(() => {
echoSpy.mockRestore();
warnSpy.mockRestore();
});
it('formats unknown types with a fallback', () => {
expect(
format(formatters, ['Unknown'], ['test'])
).toEqual(['test']);
});
it('logs a warning with unknown types', () => {
format(formatters, ['Unknown'], ['test']);
expect(warnSpy).toHaveBeenCalledWith(
expect.anything(), expect.anything(), "Unable to find default formatter for 'Unknown', falling back to echo"
);
});
it('wraps exceptions with the type', () => {
expect(
() => format(formatters, ['Exception'], ['test'])
).toThrow(/Error formatting 'test' as 'Exception'/);
});
describe('primitives', () => {
it('formats known types using the supplied formatter', () => {
format(formatters, ['Address'], ['0xaddress']);
expect(echoSpy).toHaveBeenCalledWith('0xaddress');
});
});
describe('primitive[]', () => {
it('formats using the primitive type', () => {
format(formatters, [['Address']], [['0x123', '0x234']]);
expect(echoSpy).toHaveBeenCalledWith('0x123');
expect(echoSpy).toHaveBeenCalledWith('0x234');
});
it('returns formatted values as arrays', () => {
expect(
format(formatters, [['Address']], [['0x123', '0x234']])
).toEqual([['0x123', '0x234']]);
});
});
it('formats each value in an array', () => {
expect(
format(formatters, ['Unknown', 'Unknown'], ['test', 'blah'])
).toEqual(['test', 'blah']);
});
});
-60
View File
@@ -1,60 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Storages } from '@polkadot/storage/types';
import { SectionItem, Param$Types, Param$Type$Array } from '@polkadot/params/types';
import { FormattersFunctionMap } from './types';
import typeToString from '@polkadot/params/typeToString';
import isUndefined from '@polkadot/util/is/undefined';
import logger from '@polkadot/util/logger';
import u8aToHex from '@polkadot/util/u8a/toHex';
import createStorageKey from '@polkadot/storage/key';
import echo from './echo';
const l = logger('api-format');
function formatSingleType (formatters: FormattersFunctionMap, type: Param$Types, value: any): any {
if (type === 'StorageKey') {
const [key, ...params]: [SectionItem<Storages>, Array<any>] = value;
return u8aToHex(
createStorageKey(key).apply(null, params)
);
}
const formatter = formatters.get(type);
if (isUndefined(formatter)) {
l.debug(() => `Unable to find default formatter for '${typeToString(type)}', falling back to echo`);
return echo(value);
}
try {
return formatter(value);
} catch (error) {
throw new Error(`Error formatting '${value.toString()}' as '${typeToString(type)}': ${error.message}`);
}
}
function formatArrayType (formatters: FormattersFunctionMap, [ type ]: Param$Type$Array, value: Array<any>): any {
return value.map((value) => {
return formatSingleType(formatters, type, value);
});
}
export default function format (formatters: FormattersFunctionMap, types: Array<Param$Types>, values: Array<any>): Array<any> {
return values.map((value, index): any => {
const type = types[index];
if (Array.isArray(type)) {
// FIXME we are currently not catering for tuples
return formatArrayType(formatters, type, value);
}
return formatSingleType(formatters, type, value);
});
}
-11
View File
@@ -1,11 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import formatInputs from './input';
import formatOutput from './output';
export {
formatInputs,
formatOutput
};
-25
View File
@@ -1,25 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { formatInputs } from './index';
describe('formatInputs', () => {
it('formats each value in an array', () => {
expect(
formatInputs(
[
{ name: 'foo', type: 'Bytes' },
{ name: 'bar', type: 'Hash' }
],
[
new Uint8Array([0x12, 0x34]),
new Uint8Array([0xab, 0xcd])
]
)
).toEqual([
'0x1234',
'0xabcd'
]);
});
});
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Params, Param$Types } from '@polkadot/params/types';
import { FormatterFunction } from './types';
import assert from '@polkadot/util/assert';
import addressDecode from '@polkadot/util-keyring/address/decode';
import bytesEncode from '@polkadot/primitives/json/bytes/encode';
import hashEncode from '@polkadot/primitives/json/hash/encode';
import format from './format';
const formatters = new Map<Param$Types, FormatterFunction>([
// funnily named, goes from address -> u8a
['AccountId', addressDecode],
['Bytes', bytesEncode],
['Hash', hashEncode]
]);
export default function formatInputs (params: Params, values: Array<any>): Array<any> {
const required = params.filter(({ isOptional }) => !isOptional);
const optionalText = params.length
? ` (${(params.length - required.length) || 'none'} optional)`
: '';
assert(values.length >= required.length && values.length <= params.length, `${params.length || 'no'} params expected${optionalText}, found ${values.length} instead`);
const types = params.map(({ type }) => type);
return format(formatters, types, values);
}
-41
View File
@@ -1,41 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { formatOutput } from './index';
describe('formatOutput', () => {
it('formats the value', () => {
expect(
JSON.stringify(
formatOutput(
'Header',
{
digest: {
logs: ['0x5678', '0x789a']
},
extrinsicsRoot: '0xabcd',
number: '0x1234',
parentHash: '0x1234',
stateRoot: '0x5678'
}
)
)
).toEqual(
JSON.stringify({
digest: {
logs: [
new Uint8Array([0x56, 0x78]),
new Uint8Array([0x78, 0x9a])
]
},
extrinsicsRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd]),
number: new BN(0x1234),
parentHash: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34]),
stateRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x56, 0x78])
})
);
});
});
-57
View File
@@ -1,57 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Param$Types } from '@polkadot/params/types';
import { FormatterFunction } from './types';
import Metadata from '@polkadot/api-codec/Metadata';
import addressEncode from '@polkadot/util-keyring/address/encode';
import bnDecode from '@polkadot/primitives/json/bn/decode';
import bytesDecode from '@polkadot/primitives/json/bytes/decode';
import hashDecode from '@polkadot/primitives/json/hash/decode';
import headerDecode from '@polkadot/primitives/json/header/decode';
import blockDecode from '@polkadot/primitives/json/block/decode';
import isNull from '@polkadot/util/is/null';
import isUndefined from '@polkadot/util/is/undefined';
import format from './format';
// NOTE Here we are trying to do things a bit differently, i.e. more in line with where we think things
// could go with the primitive classes. (Good testbed anyway for the decoding, although maybe a bit messy
// with duplication). Overall, bit hackly since it shoehorns in a potential new implementation into an
// original way of doing things
const metaDecode = (input: Array<number>) => {
const metadata = new Metadata();
try {
metadata.fromJSON(input);
} catch (error) {
console.error('current', JSON.stringify(metadata.toJSON()), error);
throw error;
}
return metadata;
};
const formatters = new Map<Param$Types, FormatterFunction>([
// publicKey -> address
['AccountId', addressEncode],
['BlockNumber', bnDecode],
['Bytes', bytesDecode],
['Hash', hashDecode],
['Header', headerDecode],
['Metadata', metaDecode],
['SignedBlock', blockDecode],
['u64', bnDecode]
]);
export default function formatOutput (type: Param$Types, value?: any): any | null {
if (isUndefined(value) || isNull(value)) {
return value;
}
return format(formatters, [type], [value])[0];
}
-9
View File
@@ -1,9 +0,0 @@
// Copyright 2017-2018 @polkadot/api-format authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Param$Types } from '@polkadot/params/types';
export type FormatterFunction = (value: any) => any;
type FormattersFunctionMap = Map<Param$Types, FormatterFunction>;
+3 -3
View File
@@ -35,9 +35,9 @@
"dependencies": {
"@babel/runtime": "^7.0.0",
"@polkadot/storage": "^0.30.1",
"@polkadot/util": "^0.30.4",
"@polkadot/util-crypto": "^0.30.4",
"@polkadot/util-keyring": "^0.30.4",
"@polkadot/util": "^0.30.7",
"@polkadot/util-crypto": "^0.30.7",
"@polkadot/util-keyring": "^0.30.7",
"@types/nock": "^9.1.3",
"eventemitter3": "^3.1.0",
"isomorphic-fetch": "^2.2.1",
+2 -3
View File
@@ -19,15 +19,14 @@ const ERROR_SUBSCRIBE = 'HTTP Provider does not have subscriptions, use WebSocke
* The HTTP Provider allows sending requests using HTTP. it does not support subscriptions
* so you won´t be able to listen to events such as new blocks or balance changes.
* It is usually preferrable using the [[WsProvider]].
* @example
* ```javascript
*
* @example
* import createApi from '@polkadot/api';
* import WsProvider from '@polkadot/api-provider/ws';
*
* const provider = new WsProvider('http://127.0.0.1:9933');
* const api = createApi(provider);
* ```
*
* @see [[WsProvider]]
*/
export default class HttpProvider implements ProviderInterface {
+4 -8
View File
@@ -40,15 +40,13 @@ interface WSProviderInterface extends ProviderInterface {
/**
* The WebSocket Provider allows sending requests using WebSocket. Unlike the [[HttpProvider]],
* it does support subscriptions and allows listening to events such as new blocks or balance changes.
* [[include:create_api.adoc]].
* @example
* ```javascript
*
* @example
* import createApi from '@polkadot/api';
* import WsProvider from '@polkadot/api-provider/ws';
* const provider = new WsProvider('ws://127.0.0.1:9944');
* const api = createApi(provider);
* ```
*
* @see [[HttpProvider]]
*/
export default class WsProvider extends E3.EventEmitter implements WSProviderInterface {
@@ -167,18 +165,16 @@ export default class WsProvider extends E3.EventEmitter implements WSProviderInt
* @param {Array<any>} params Parameters
* @param {ProviderInterface$Callback} callback Callback
* @return {Promise<number>} Promise resolving to the dd of the subscription you can use with [[unsubscribe]].
* @example
* ```javascript
*
* @example
* const provider = new WsProvider('ws://127.0.0.1:9944');
* const api = createApi(provider);
*
* api.state.storage([[storage.staking.public.freeBalanceOf, <Address>]], (_, values) => {
* api.state.storage([[storage.balances.freeBalance, <Address>]], (_, values) => {
* console.log(values)
* }).then((subscriptionId) => {
* console.log('balance changes subscription id: ', subscriptionId)
* })
* ```
*/
async subscribe (type: string, method: string, params: Array<any>, callback: ProviderInterface$Callback): Promise<number> {
const id = await this.send(method, params, { callback, type });
@@ -25,17 +25,4 @@ describe.skip('e2e basics', () => {
throw error;
});
});
it('retrieves the wasm metadata', () => {
return api.state
.getMetadata()
.then((meta) => {
console.error(JSON.stringify(meta.toJSON()));
})
.catch((error) => {
console.error(error);
throw error;
});
});
});
@@ -19,8 +19,8 @@ describe.skip('e2e krumme lanke', () => {
api.state
.subscribeStorage(
[
[storage.system.public.accountIndexOf, '5Ejbye9R8ygByQPrDSasaUid1munedPZUmg4f118HGmtodGp'],
[storage.staking.public.freeBalanceOf, '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFacT7']
[storage.system.accountNonce, '5Ejbye9R8ygByQPrDSasaUid1munedPZUmg4f118HGmtodGp'],
[storage.balances.freeBalance, '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFacT7']
],
(error, data) => {
if (error) {
@@ -0,0 +1,81 @@
// Copyright 2017-2018 @polkadot/api-provider authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import storage from '@polkadot/storage/testing';
import Api from '../../api/src';
import Ws from '../src/ws';
const ALICE = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ';
describe.skip('e2e state', () => {
let api;
beforeEach(() => {
jest.setTimeout(30000);
api = new Api(new Ws('ws://127.0.0.1:9944'));
});
it('retrieves code', () => {
return api.state
.getStorage([
storage.substrate.code
])
.then((code) => {
console.error(code.toHex().substr(0, 256), '...');
})
.catch((error) => {
console.error(error);
throw error;
});
});
it('retrieves the wasm metadata', () => {
return api.state
.getMetadata()
.then((meta) => {
console.error(JSON.stringify(meta.toJSON()));
})
.catch((error) => {
console.error(error);
throw error;
});
});
it('retrieves balances', () => {
return api.state
.getStorage([
storage.balances.freeBalance, ALICE
])
.then((balance) => {
console.error(balance);
expect(balance.toBn().isZero()).not.toEqual(true);
})
.catch((error) => {
console.error(error);
throw error;
});
});
it('retrieves timestamp', () => {
return api.state
.getStorage([
storage.timestamp.now
])
.then((moment) => {
console.error(moment);
expect(moment.toNumber()).not.toEqual(0);
})
.catch((error) => {
console.error(error);
throw error;
});
});
});
+1 -3
View File
@@ -23,15 +23,13 @@ type CachedMap = {
/**
* An RxJs wrapper around the [[api]].
* @example
* ```javascript
*
* @example
* import RxApi from '@polkadot/api';
* import WsProvider from '@polkadot/api-provider/ws';
*
* const provider = new WsProvider('http://127.0.0.1:9944');
* const rxapi = new RxApi(provider);
* ```
*/
export default class RxApi implements RxApiInterface {
private _api: ApiInterface;
+1 -2
View File
@@ -30,10 +30,9 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme",
"dependencies": {
"@babel/runtime": "^7.0.0",
"@polkadot/api-format": "^0.30.1",
"@polkadot/api-provider": "^0.30.1",
"@polkadot/jsonrpc": "^0.30.1",
"@polkadot/params": "^0.30.1",
"@polkadot/util": "^0.30.4"
"@polkadot/util": "^0.30.7"
}
}
@@ -2,17 +2,17 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import storage from '@polkadot/storage';
import storage from '@polkadot/storage/testing';
import Api from './index';
const ADDR_ONE = '5EhmTa7fL6SdjgKXo9g6hetR6nHnRAmrtisoGFWEESjzECtY';
const ADDR_TWO = '5FjbQAHSptRU4Q7Py6zDsRnE7UkpZikJVg5nm1tmu3WuZXKd';
const ENC_ONE = '0x11cf1094db4db43356b7787c3e59c39f';
const ENC_TWO = '0x924776c687da8e30afdd2ac87d2c67da';
const ENC_ONE = '0x24988a82b3bbaae58680bc9de5dea5aa';
const ENC_TWO = '0xdb190750267d8849c35316ec9d342111';
describe('formatResult', () => {
describe('formatting', () => {
let api;
let provider;
@@ -25,8 +25,8 @@ describe('formatResult', () => {
subscription(null, {
block: '0x1234',
changes: [
['0x11cf1094db4db43356b7787c3e59c39f', '0x0102'],
['0x924776c687da8e30afdd2ac87d2c67da', '0x0201']
[ENC_ONE, '0x0102'],
[ENC_TWO, '0x0201']
]
})
)
@@ -34,12 +34,11 @@ describe('formatResult', () => {
api = new Api(provider);
});
it.skip('encodes key (with params), decoding response', () => {
it('encodes key (with params), decoding response', () => {
return api.state
.getStorage([
// FIXME changed storage api
storage.staking.public.freeBalanceOf, ADDR_ONE
])
.getStorage(
[storage.balances.freeBalance, ADDR_ONE]
)
.then((value) => {
expect(
provider.send
@@ -51,15 +50,16 @@ describe('formatResult', () => {
});
});
it.skip('encodes multiple keys, decoding multiple results', (done) => {
it('encodes multiple keys, decoding multiple results', (done) => {
api.state
.storage(
[
// FIXME changed storage api
[storage.staking.public.freeBalanceOf, ADDR_ONE],
[storage.staking.public.freeBalanceOf, ADDR_TWO]
[storage.balances.freeBalance, ADDR_ONE],
[storage.balances.freeBalance, ADDR_TWO]
],
(error, value) => {
console.error(value);
expect(
provider.subscribe
).toHaveBeenCalledWith(
@@ -69,7 +69,9 @@ describe('formatResult', () => {
expect.anything()
);
expect(
value.map((bn) => bn.toNumber())
value.map((balance) =>
balance.toNumber()
)
).toEqual([513, 258]);
done(error);
+56 -33
View File
@@ -5,13 +5,11 @@
import { ProviderInterface, ProviderInterface$Callback } from '@polkadot/api-provider/types';
import { Interfaces, Interface$Sections } from '@polkadot/jsonrpc/types';
import { SectionItem } from '@polkadot/params/types';
import { Storages } from '@polkadot/storage/types';
import { ApiInterface, ApiInterface$Section, ApiInterface$Section$Method } from './types';
import formatInputs from '@polkadot/api-format/input';
import formatOutput from '@polkadot/api-format/output';
import { Base, Vector, createType } from '@polkadot/api-codec/codec';
import { StorageChangeSet, StorageKey } from '@polkadot/api-codec/index';
import interfaces from '@polkadot/jsonrpc/index';
import decodeParams from '@polkadot/params/decode';
import signature from '@polkadot/params/signature';
import assert from '@polkadot/util/assert';
import ExtError from '@polkadot/util/ext/error';
@@ -20,14 +18,11 @@ import isUndefined from '@polkadot/util/is/undefined';
/**
* @example
* ```javascript
*
* import Api from '@polkadot/api';
* import WsProvider from '@polkadot/api-provider/ws';
*
* const provider = new WsProvider('http://127.0.0.1:9944');
* const api = new Api(provider);
* ```
*/
export default class Api implements ApiInterface {
private _provider: ProviderInterface;
@@ -78,12 +73,17 @@ export default class Api implements ApiInterface {
const call = async (...values: Array<any>): Promise<any> => {
// TODO Warn on deprecated methods
try {
const params = formatInputs(method.params, values);
const result = await this._provider.send(rpcName, params);
const params = this.formatInputs(method, values);
const paramsJson = params.map((param) => param.toJSON());
const result = await this._provider.send(rpcName, paramsJson);
return this.formatResult(method, params, values, result);
return this.formatOutput(method, params, result);
} catch (error) {
throw new ExtError(`${signature(method)}:: ${error.message}`, (error as ExtError).code, undefined);
const message = `${signature(method)}:: ${error.message}`;
console.error(message, error);
throw new ExtError(message, (error as ExtError).code, undefined);
}
};
@@ -99,14 +99,19 @@ export default class Api implements ApiInterface {
assert(isFunction(cb), `Expected callback in last position of params`);
const params = formatInputs(method.params, values);
const params = this.formatInputs(method, values);
const paramsJson = params.map((param) => param.toJSON());
const update = (error: Error | null, result?: any) => {
cb(error, this.formatResult(method, params, values, result));
cb(error, this.formatOutput(method, params, result));
};
return this._provider.subscribe(rpcName, method.subscribe[0], params, update);
return this._provider.subscribe(rpcName, method.subscribe[0], paramsJson, update);
} catch (error) {
throw new ExtError(`${signature(method)}:: ${error.message}`, (error as ExtError).code, undefined);
const message = `${signature(method)}:: ${error.message}`;
console.error(message, error);
throw new ExtError(message, (error as ExtError).code, undefined);
}
};
@@ -117,29 +122,47 @@ export default class Api implements ApiInterface {
return call;
}
private formatResult (method: SectionItem<Interfaces>, params: Array<any>, inputs: Array<any>, result?: any): any {
if (method.type === 'StorageResult') {
return this.formatStorageOutput(inputs[0][0], result);
}
private formatInputs (method: SectionItem<Interfaces>, inputs: Array<any>): Array<Base> {
assert(method.params.length === inputs.length, `Expected ${method.params.length} parameters, ${inputs.length} found instead`);
if (method.type === 'StorageResultSet') {
return params[0].map((key: string, index: number) => {
const input = inputs[0][index][0];
const { changes = [] }: { block: string, changes: Array<[string, string]> } = result || {};
const value = changes.find(([_key]) => key === _key);
return method.params.map(({ type }, index) =>
createType(type as string, inputs[index])
);
}
if (!value) {
return undefined;
private formatOutput (method: SectionItem<Interfaces>, params: Array<Base>, result?: any): Base {
const base = createType(method.type as string, result);
if (method.type === 'StorageData') {
const type = (params[0] as StorageKey).outputType;
if (type) {
return createType(type, base.raw);
}
} else if (method.type === 'StorageChangeSet') {
return (params[0] as Vector<StorageKey>).reduce((vector, _key: StorageKey) => {
const type = _key.outputType;
if (!type) {
throw new Error('Cannot format StorageChangeSet, output type missing for key');
}
return this.formatStorageOutput(input, value[1]);
});
const key = _key.toHex();
const item = (base as StorageChangeSet).changes.find((item) =>
item.key.toHex() === key
);
if (!item) {
throw new Error('No result found for key in StorageChangeSet');
}
vector.push(createType(type, item.value.value));
return vector;
}, new (Vector.with(Base))());
}
return formatOutput(method.type, result);
}
private formatStorageOutput (key: SectionItem<Storages>, result?: any): any {
return decodeParams(key.type, result, 'latest', true).value;
return base;
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ describe('methodSend', () => {
const method = api.createMethodSend('test_bleh', methods.bleh);
return method(1).catch((error) => {
expect(error.message).toMatch(/no params expected, found 1 instead/);
expect(error.message).toMatch(/parameters, 1 found instead/);
});
});
+1 -1
View File
@@ -13,6 +13,6 @@
"@babel/runtime": "^7.0.0",
"@polkadot/params": "^0.30.1",
"@polkadot/primitives": "^0.30.1",
"@polkadot/util": "^0.30.4"
"@polkadot/util": "^0.30.7"
}
}
+3 -3
View File
@@ -46,7 +46,7 @@ const getStorage: CreateItemOptions = {
params: [
param('key', 'StorageKey')
],
type: 'StorageResult'
type: 'StorageData'
};
const getStorageAt: CreateItemOptions = {
@@ -99,9 +99,9 @@ const storage: CreateItemOptions = {
'state_unsubscribeStorage'
],
params: [
param('keys', ['StorageKey'])
param('keys', 'Vec<StorageKey>')
],
type: 'StorageResultSet'
type: 'StorageChangeSet'
};
const privateMethods: CreateItemOptionsMap = {};
+2 -2
View File
@@ -32,7 +32,7 @@
"@polkadot/extrinsics": "^0.30.1",
"@polkadot/params": "^0.30.1",
"@polkadot/primitives": "^0.30.1",
"@polkadot/util": "^0.30.4",
"@polkadot/util-keyring": "^0.30.4"
"@polkadot/util": "^0.30.7",
"@polkadot/util-keyring": "^0.30.7"
}
}
@@ -112,8 +112,8 @@ export default function decodeValue (decode: Decoder, type: Param$Type, _input:
case 'VoteThreshold':
return byte(input);
case 'StorageResult':
case 'StorageResultSet':
case 'StorageData':
case 'StorageChangeSet':
default:
// tslint:disable-next-line
(type as never);
@@ -7,11 +7,11 @@ import toU8a from '@polkadot/util/u8a/toU8a';
import encode from './index';
describe('storageKey', () => {
it.skip('encodes storageKey -> Uint8Array properly', () => {
describe.skip('storageKey', () => {
it('encodes storageKey -> Uint8Array properly', () => {
expect(
encode('StorageKey', [
storage.staking.public.freeBalanceOf,
storage.balances.freeBalance,
'5EhmTa7fL6SdjgKXo9g6hetR6nHnRAmrtisoGFWEESjzECtY'
])
).toEqual(
+1 -1
View File
@@ -14,7 +14,7 @@ export type EncodingVersions = 'poc-1' | 'latest';
// - @polkadot/storage/key/params.ts
// - decode/value/index.js
// - encode/type/index.js
export type Param$Type = 'AccountId' | 'AccountIndex' | 'Balance' | 'BlockNumber' | 'bool' | 'Bytes' | 'Call' | 'CandidateReceipt' | 'Code' | 'Digest' | 'Gas' | 'Hash' | 'Header' | 'KeyValue' | 'Metadata' | 'MisbehaviorReport' | 'ParachainId' | 'PendingExtrinsics' | 'PropIndex' | 'Proposal' | 'ReferendumIndex' | 'RuntimeVersion' | 'SessionKey' | 'Signature' | 'SignedBlock' | 'StorageKey' | 'StorageKeyValue' | 'StorageResult' | 'StorageResultSet' | 'String' | 'Timestamp' | 'u32' | 'u64' | 'u128' | 'VoteIndex' | 'VoteThreshold';
export type Param$Type = 'AccountId' | 'AccountIndex' | 'Balance' | 'BlockNumber' | 'bool' | 'Bytes' | 'Call' | 'CandidateReceipt' | 'Code' | 'Digest' | 'Gas' | 'Hash' | 'Header' | 'KeyValue' | 'Metadata' | 'MisbehaviorReport' | 'ParachainId' | 'PendingExtrinsics' | 'PropIndex' | 'Proposal' | 'ReferendumIndex' | 'RuntimeVersion' | 'SessionKey' | 'Signature' | 'SignedBlock' | 'StorageKey' | 'StorageKeyValue' | 'StorageData' | 'StorageChangeSet' | 'String' | 'Timestamp' | 'u32' | 'u64' | 'u128' | 'VoteIndex' | 'VoteThreshold' | 'Vec<StorageKey>';
export type Param$Type$Array = Array<Param$Type | Array<Param$Type | Array<Param$Type>>>;
+2 -2
View File
@@ -29,8 +29,8 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-primitives#readme",
"dependencies": {
"@babel/runtime": "^7.0.0",
"@polkadot/trie-hash": "^0.30.4",
"@polkadot/util": "^0.30.4"
"@polkadot/trie-hash": "^0.30.7",
"@polkadot/util": "^0.30.7"
},
"devDependencies": {
"bn.js": "^4.11.8"
+4 -3
View File
@@ -30,10 +30,11 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-storage#readme",
"dependencies": {
"@babel/runtime": "^7.0.0",
"@polkadot/api-codec": "^0.30.1",
"@polkadot/params": "^0.30.1",
"@polkadot/primitives": "^0.30.1",
"@polkadot/util": "^0.30.4",
"@polkadot/util-crypto": "^0.30.4",
"@polkadot/util-keyring": "^0.30.4"
"@polkadot/util": "^0.30.7",
"@polkadot/util-crypto": "^0.30.7",
"@polkadot/util-keyring": "^0.30.7"
}
}
@@ -5,7 +5,7 @@
import Metadata from '@polkadot/api-codec/Metadata';
import json from '@polkadot/api-codec/Metadata.rpc.json';
import { fromMetadata } from './fromMetadata';
import fromMetadata from './fromMetadata';
// Use the pre-generated metadata
const metadata = new Metadata().fromJSON(json.result);
@@ -23,7 +23,7 @@ describe('fromMetadata', () => {
// FIXME check again when we have a valid chain/UI
it('should return the correct storage key', () => {
expect(newStorage.balances.freeBalance('5GwPuAgYgP6q58uWTXp4uSg6FwfzQv9HfFZwAFEREUrQjCvy')).toEqual(
Uint8Array.from([237, 14, 33, 216, 167, 215, 237, 69, 175, 111, 52, 40, 57, 42, 106, 40])
Uint8Array.from([52, 103, 23, 10, 157, 95, 244, 9, 70, 215, 120, 149, 1, 238, 109, 69])
);
});
});
+23 -24
View File
@@ -2,20 +2,12 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Metadata, { RuntimeModuleMetadata } from '@polkadot/api-codec/Metadata';
import { createFunction } from './utils/createFunction';
import { ModuleStorage, Storage } from './types';
/**
* Sets the 1st letter of a string to lowercase.
*
* @param s - The string to lower first letter.
* TODO Move to @polkadot/util
*/
function lowerFirstLetter (s: string) {
return s.charAt(0).toLowerCase() + s.slice(1);
}
import Metadata from '@polkadot/api-codec/Metadata';
import { stringLowerFirst } from '@polkadot/util/string';
import createFunction from './utils/createFunction';
/**
* Extend a storage object with the storage modules & module functions present
@@ -24,20 +16,27 @@ function lowerFirstLetter (s: string) {
* @param storage - A storage object to be extended.
* @param metadata - The metadata to extend the storage object against.
*/
export const fromMetadata = (storage: Storage, metadata: Metadata) => {
metadata.modules.forEach((moduleMetadata: RuntimeModuleMetadata) => {
export default function fromMetadata (storage: Storage, metadata: Metadata) {
const result = Object.keys(storage).reduce((result, key) => {
result[key] = storage[key];
return result;
}, {} as Storage);
return metadata.modules.reduce((result, moduleMetadata) => {
if (!moduleMetadata.storage) {
return;
return result;
}
const newModule: ModuleStorage = {
};
const prefix = moduleMetadata.storage.prefix.toString();
moduleMetadata.storage.functions.forEach(func => {
result[stringLowerFirst(prefix)] = moduleMetadata.storage.functions.reduce((newModule, func) => {
// Lowercase the 'f' in storage.balances.freeBalance
newModule[lowerFirstLetter(func.name.toString())] = createFunction(moduleMetadata.prefix, func);
});
storage[moduleMetadata.prefix.toString()] = newModule;
});
return storage;
};
newModule[stringLowerFirst(func.name.toString())] = createFunction(prefix, func.name, func);
return newModule;
}, {} as ModuleStorage);
return result;
}, result);
}
+3 -4
View File
@@ -4,10 +4,9 @@
import { StorageFunctionModifier, StorageFunctionType } from '@polkadot/api-codec/Metadata';
import Text from '@polkadot/api-codec/Text';
import U8a from '@polkadot/api-codec/codec/U8a';
import Vector from '@polkadot/api-codec/codec/Vector';
import { createFunction } from './utils/createFunction';
import createFunction from './utils/createFunction';
interface SubstrateMetadata {
documentation: string;
@@ -15,13 +14,13 @@ interface SubstrateMetadata {
}
// Small helper function to factorize code on this page.
const createRuntimeFunction = (prefix: string, functionMetadata: SubstrateMetadata) =>
const createRuntimeFunction = (name: string, functionMetadata: SubstrateMetadata) =>
// TODO The expected 2nd argument is a StorageFunctionMetadata, but we
// actually only need the fields `documentation` and `type` of it, so in
// order to not input other fields (byteLength, fromJSON...) we lazily cast
// as any.
createFunction(
new U8a(prefix),
'', name,
{
documentation: new Vector(Text, [functionMetadata.documentation]),
modifier: new StorageFunctionModifier().fromJSON(0),
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2017-2018 @polkadot/storage authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import metadataJson from '@polkadot/api-codec/Metadata.rpc.json';
import Metadata from '@polkadot/api-codec/Metadata';
import storage from './index';
import fromMetadata from './fromMetadata';
export default fromMetadata(
storage,
new Metadata().fromJSON(metadataJson.result)
);
+1 -6
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { StorageFunctionMetadata } from '@polkadot/api-codec/Metadata';
import { StorageFunction } from '@polkadot/api-codec/StorageKey';
import BN from 'bn.js';
import { Section } from '@polkadot/params/types';
@@ -10,10 +10,6 @@ import * as substrate from './substrate';
type Substrate = keyof typeof substrate;
export interface StorageFunction extends StorageFunctionMetadata {
(arg: any): Uint8Array;
}
export interface ModuleStorage {
[key: string]: StorageFunction;
}
@@ -25,7 +21,6 @@ export interface Storage {
// TODO Below is legacy code, used in:
// - api-provider
// - api-format
export type Storage$Key$Value = number | BN | Uint8Array | string;
export type Storages = {
consensus: Section<Storages, any, any>;
@@ -0,0 +1,21 @@
// Copyright 2017-2018 @polkadot/storage authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import hexToU8a from '@polkadot/util/hex/toU8a';
import createFunction from './createFunction';
describe('createFunction', () => {
it('should create timestamp.now correctly', () => {
expect(
createFunction(
'Timestamp',
'Now',
{ type: {} }
)()
).toEqual(
hexToU8a('0x0e4944cfd98d6f4cc374d16f5a4e3f9c')
);
});
});
@@ -2,15 +2,14 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import * as CodecTypes from '@polkadot/api-codec/index';
import { createType } from '@polkadot/api-codec/codec';
import { StorageFunctionMetadata } from '@polkadot/api-codec/Metadata';
import Text from '@polkadot/api-codec/Text';
import U8a from '@polkadot/api-codec/codec/U8a';
import { StorageFunction } from '@polkadot/api-codec/StorageKey';
import { Text } from '@polkadot/api-codec/index';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aFromUtf8 from '@polkadot/util/u8a/fromUtf8';
import xxhash from '@polkadot/util-crypto/xxhash/asU8a';
import { StorageFunction } from '../types';
export interface CreateItemOptions {
isUnhashed?: boolean;
}
@@ -25,40 +24,47 @@ export interface CreateItemOptions {
* are not known at runtime (from state_getMetadata), they need to be supplied
* by us manually at compile time.
*/
export function createFunction (
prefix: Text | U8a,
functionMetadata: StorageFunctionMetadata,
export default function createFunction (
prefix: string | Text,
name: string | Text,
meta: StorageFunctionMetadata,
options: CreateItemOptions = {}
) {
let func: any; // The return value, it's a function that has metadata.
): StorageFunction {
let storageFn: any;
if (options.isUnhashed) {
func = () => prefix.toU8a();
storageFn = (): Uint8Array =>
u8aFromUtf8(name.toString());
} else {
// TODO Find better type than any
// Can only have zero or one argument:
// - storage.balances.freeBalance(address)
// - storage.timestamp.blockPeriod()
func = (arg?: any) => {
if (functionMetadata.type.isMap) {
if (!arg) {
throw new Error(`${functionMetadata.name} expects one argument.`);
}
const argType = functionMetadata.type.asMap.key.toString(); // Argument type, as string
const ArgType = (CodecTypes as any)[argType]; // Argument type, as Class
return xxhash(u8aConcat(prefix.toU8a(), new ArgType(arg).toU8a()), 128);
storageFn = (arg?: any): Uint8Array => {
if (!meta.type.isMap) {
return xxhash(
u8aFromUtf8(`${prefix.toString()} ${name.toString()}`),
128
);
}
return xxhash(prefix.toU8a(), 128);
if (!arg) {
throw new Error(`${meta.name} expects one argument`);
}
const type = meta.type.asMap.key.toString(); // Argument type, as string
return xxhash(
u8aConcat(
u8aFromUtf8(`${prefix.toString()} ${name.toString()}`),
createType(type, arg).toU8a(true)
),
128
);
};
}
// Add metadata to the storage function
Object.assign(func as StorageFunction, {
documentation: functionMetadata.documentation,
type: functionMetadata.type
});
storageFn.meta = meta;
return func as StorageFunction;
return storageFn as StorageFunction;
}
-1
View File
@@ -6,7 +6,6 @@
"paths":
{
"@polkadot/api-codec/*": ["packages/api-codec/src/*"],
"@polkadot/api-format/*": ["packages/api-format/src/*"],
"@polkadot/api-provider/*": ["packages/api-provider/src/*"],
"@polkadot/api-rx/*": ["packages/api-rx/src/*"],
"@polkadot/api/*": ["packages/api/src/*"],
+3
View File
@@ -1,5 +1,8 @@
{
"extends": "@polkadot/dev/config/tslint",
"linterOptions": {
"exclude": "packages/**/src/**/*.json"
},
"rules": {
"completed-docs": false
}
+32 -22
View File
@@ -1219,57 +1219,59 @@
typedoc-plugin-markdown "^1.1.15"
typescript "^3.0.1"
"@polkadot/trie-hash@^0.30.4":
version "0.30.4"
resolved "https://registry.yarnpkg.com/@polkadot/trie-hash/-/trie-hash-0.30.4.tgz#eb2520b45cbb634000319e8420623a992c4fd56a"
"@polkadot/trie-hash@^0.30.7":
version "0.30.7"
resolved "https://registry.yarnpkg.com/@polkadot/trie-hash/-/trie-hash-0.30.7.tgz#b68102736d03a2a4cd673f113a90a7cd2b21bc69"
dependencies:
"@babel/runtime" "^7.0.0"
"@polkadot/util" "^0.30.4"
"@polkadot/util-crypto" "^0.30.4"
"@polkadot/util-rlp" "^0.30.4"
"@polkadot/util" "^0.30.7"
"@polkadot/util-crypto" "^0.30.7"
"@polkadot/util-rlp" "^0.30.7"
"@polkadot/ts@^0.1.30":
version "0.1.30"
resolved "https://registry.yarnpkg.com/@polkadot/ts/-/ts-0.1.30.tgz#d6d1498a5597e09de88f6117663bcf842040c801"
"@polkadot/util-crypto@^0.30.4":
version "0.30.4"
resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.30.4.tgz#d2e23fd1f661200771c10381f4b8ef20d337c1a8"
"@polkadot/util-crypto@^0.30.7":
version "0.30.7"
resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.30.7.tgz#7af110c286164cd4870ba8b499c2601b7181ed4d"
dependencies:
"@babel/runtime" "^7.0.0"
"@polkadot/util" "^0.30.4"
"@polkadot/util" "^0.30.7"
blakejs "^1.1.0"
js-sha3 "^0.8.0"
tweetnacl "^1.0.0"
xxhashjs "^0.2.2"
"@polkadot/util-keyring@^0.30.4":
version "0.30.4"
resolved "https://registry.yarnpkg.com/@polkadot/util-keyring/-/util-keyring-0.30.4.tgz#97aa4e442f38ce0afe7f54b2f0c537b184031b7c"
"@polkadot/util-keyring@^0.30.7":
version "0.30.7"
resolved "https://registry.yarnpkg.com/@polkadot/util-keyring/-/util-keyring-0.30.7.tgz#b98df3430937a441422e1ea788e0115d0e2a9c88"
dependencies:
"@babel/runtime" "^7.0.0"
"@polkadot/util" "^0.30.4"
"@polkadot/util-crypto" "^0.30.4"
"@polkadot/util" "^0.30.7"
"@polkadot/util-crypto" "^0.30.7"
"@types/bs58" "^3.0.30"
bs58 "^4.0.1"
"@polkadot/util-rlp@^0.30.4":
version "0.30.4"
resolved "https://registry.yarnpkg.com/@polkadot/util-rlp/-/util-rlp-0.30.4.tgz#3f08ad08e0f47febeacf9225c4615f18f6e450b7"
"@polkadot/util-rlp@^0.30.7":
version "0.30.7"
resolved "https://registry.yarnpkg.com/@polkadot/util-rlp/-/util-rlp-0.30.7.tgz#bb314ebdbf44803a0575e067ef316f60099c274a"
dependencies:
"@babel/runtime" "^7.0.0"
"@polkadot/util" "^0.30.4"
"@polkadot/util" "^0.30.7"
"@polkadot/util@^0.30.4":
version "0.30.4"
resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.30.4.tgz#f3033b5e7e8a2af5a69b4b9f2ea33287da76d045"
"@polkadot/util@^0.30.7":
version "0.30.7"
resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.30.7.tgz#989e21e5b32f2a505ad0a787ce8b56da94702d32"
dependencies:
"@babel/runtime" "^7.0.0"
"@types/bn.js" "^4.11.1"
"@types/camelcase" "^4.1.0"
"@types/deasync" "^0.1.0"
"@types/ip-regex" "^2.0.0"
"@types/xxhashjs" "^0.1.1"
bn.js "^4.11.8"
camelcase "^5.0.0"
chalk "^2.4.1"
deasync "^0.1.13"
ip-regex "^3.0.0"
@@ -1291,6 +1293,10 @@
dependencies:
"@types/base-x" "*"
"@types/camelcase@^4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@types/camelcase/-/camelcase-4.1.0.tgz#e054f7986f31658d49936261b5cd4588ef29d1ee"
"@types/deasync@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@types/deasync/-/deasync-0.1.0.tgz#b2bd6c3fcde3cf67b8be4c2f70136ba8f157b45a"
@@ -2225,6 +2231,10 @@ camelcase@^4.0.0, camelcase@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
camelcase@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
caniuse-lite@^1.0.30000884:
version "1.0.30000885"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000885.tgz#e889e9f8e7e50e769f2a49634c932b8aee622984"