Extend ApiRx from abstract Base (prepare for promise) (#243)

* Extend ApiRx from abstract Base (prepare for promise)

* Update Metadata parsing

* Update Base.ts

* Update types.d.ts

* Cleanup base

* Cleanup linting (renamed imports)

* PR comments

* Update decoded Metadata.json
This commit is contained in:
Jaco Greeff
2018-10-11 10:20:54 +02:00
committed by GitHub
parent 05da1ee8c8
commit 27b2885722
13 changed files with 719 additions and 608 deletions
+216
View File
@@ -0,0 +1,216 @@
// Copyright 2017-2018 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { ApiBaseInterface } from './types';
import E3 from 'eventemitter3';
import WsProvider from '@polkadot/rpc-provider/ws';
import Rpc from '@polkadot/rpc-core/index';
import { Extrinsics } from '@polkadot/extrinsics/types';
import extrinsicsFromMeta from '@polkadot/extrinsics/fromMetadata';
import { Storage } from '@polkadot/storage/types';
import storageFromMeta from '@polkadot/storage/fromMetadata';
import { Hash, Method, RuntimeVersion } from '@polkadot/types/index';
import RuntimeMetadata from '@polkadot/types/Metadata';
import assert from '@polkadot/util/assert';
import isUndefined from '@polkadot/util/is/undefined';
import logger from '@polkadot/util/logger';
type MetaDecoration = {
callIndex?: Uint8Array,
meta: any,
method: string,
section: string,
toJSON: () => any
};
const l = logger('api');
const INIT_ERROR = `Api needs to be initialised before using, listen on 'ready'`;
export default abstract class ApiBase<R, S, E> extends E3.EventEmitter implements ApiBaseInterface<R, S, E> {
protected _extrinsics?: E;
protected _genesisHash?: Hash;
protected _storage?: S;
protected _rpc: R;
protected _rpcBase: Rpc;
protected _runtimeMetadata?: RuntimeMetadata;
protected _runtimeVersion?: RuntimeVersion;
/**
* @param wsProvider An optional WebSocket provider from rpc-provider/ws. If not specified, it will default to connecting to the localhost with the default port
* @example
* <BR>
*
* ```javascript
* import Api from '@polkadot/api/rx';
*
* new Api().isReady.subscribe((api) => {
* api.rpc.newHead().subscribe((header) => {
* console.log(`new block #${header.blockNumber.toNumber()}`);
* });
* });
* ```
*/
constructor (wsProvider?: WsProvider) {
super();
this._rpcBase = new Rpc(wsProvider);
this._rpc = this.decorateRpc(this._rpcBase);
this.init();
}
/**
* @description Contains the genesis Hash of the attached chain. Apart from being useful to determine the actual chain, it can also be used to sign immortal transactions.
*/
get genesisHash (): Hash {
assert(!isUndefined(this._genesisHash), INIT_ERROR);
return this._genesisHash as Hash;
}
/**
* @description Yields the current attached runtime metadata. Generally this is only used to construct extrinsics & storage, but is useful for current runtime inspection.
*/
get runtimeMetadata (): RuntimeMetadata {
assert(!isUndefined(this._runtimeMetadata), INIT_ERROR);
return this._runtimeMetadata as RuntimeMetadata;
}
/**
* @description Contains the version information for the current runtime.
*/
get runtimeVersion (): RuntimeVersion {
assert(!isUndefined(this._runtimeVersion), INIT_ERROR);
return this._runtimeVersion as RuntimeVersion;
}
/**
* @description Contains all the raw rpc sections and their subsequent methods in the API as defined by the jsonrpc interface definitions.
* @example
* <BR>
*
* ```javascript
* api.rpc.chain
* .newHead()
* .subscribe((header) => {
* console.log('new header', header);
* });
* ```
*/
get rpc (): R {
return this._rpc;
}
/**
* @description Contains all the chain state modules and their subsequent methods in the API. These are attached dynamically from the runtime metadata.
* @example
* <BR>
*
* ```javascript
* api.st.balances
* .freeBalance(<accountId>)
* .subscribe((balance) => {
* console.log('new balance', balance);
* });
* ```
*/
get st (): S {
assert(!isUndefined(this._storage), INIT_ERROR);
return this._storage as S;
}
/**
* @description Contains all the extrinsic modules and their subsequent methods in the API. It allows for the construction of transactions and the submission thereof. These are attached dynamically from the runtime metadata.
* @example
* <BR>
*
* ```javascript
* api.tx.balances
* .transfer(<recipientId>, <balance>)
* .sign(<keyPair>, <accountNonce>, <blockHash (optional)>)
* .send()
* .subscribe((status) => {
* console.log('tx status', status);
* });
* ```
*/
get tx (): E {
assert(!isUndefined(this._extrinsics), INIT_ERROR);
return this._extrinsics as E;
}
private init (): void {
let isReady: boolean = false;
this._rpcBase._provider.on('disconnected', () => {
this.emit('disconnected');
});
this._rpcBase._provider.on('connected', async () => {
this.emit('connected');
// TODO When re-connected (i.e. disconnected and then connected), we want to do a couple of things
// - refresh metadata as needed, decorating again
// - re-create storage subscriptions for those we already have
// - re-watch extrinsics where we have subscriptions already
// - need to refresh genesisHash, extrinsic resub only when it matches
if (isReady) {
return;
}
const hasMeta = await this.loadMeta();
if (hasMeta && !isReady) {
isReady = true;
this.emit('ready', this);
}
});
}
private async loadMeta (): Promise<boolean> {
try {
this._runtimeMetadata = await this._rpcBase.state.getMetadata();
this._runtimeVersion = await this._rpcBase.chain.getRuntimeVersion();
this._genesisHash = await this._rpcBase.chain.getBlockHash(0);
const extrinsics = extrinsicsFromMeta(this.runtimeMetadata);
const storage = storageFromMeta(this.runtimeMetadata);
this._extrinsics = this.decorateExtrinsics(extrinsics);
this._storage = this.decorateStorage(storage);
Method.injectExtrinsics(extrinsics);
return true;
} catch (error) {
l.error('loadMeta', error);
return false;
}
}
protected decorateFunctionMeta (input: MetaDecoration, output: MetaDecoration): MetaDecoration {
output.meta = input.meta;
output.method = input.method;
output.section = input.section;
output.toJSON = input.toJSON;
if (input.callIndex) {
output.callIndex = input.callIndex;
}
return output;
}
protected abstract decorateRpc (rpc: Rpc): R;
protected abstract decorateExtrinsics (extrinsics: Extrinsics): E;
protected abstract decorateStorage (storage: Storage): S;
}
+3 -3
View File
@@ -4,15 +4,15 @@
import { KeyringPair } from '@polkadot/util-keyring/types';
import { AnyNumber, AnyU8a } from '@polkadot/types/types';
import { RxApiInterface } from './types';
import { ApiRxInterface } from './types';
import { Observable } from 'rxjs';
import { Extrinsic } from '@polkadot/types/index';
export default class SubmittableExtrinsic extends Extrinsic {
private _api: RxApiInterface;
private _api: ApiRxInterface;
constructor (api: RxApiInterface, extrinsic: Extrinsic) {
constructor (api: ApiRxInterface, extrinsic: Extrinsic) {
super({
method: extrinsic.method,
signature: extrinsic.signature
+24 -170
View File
@@ -2,41 +2,26 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { RxApiInterface, QueryableStorageFunction, QueryableModuleStorage, QueryableStorage, SubmittableExtrinsics, SubmittableModuleExtrinsics, SubmittableExtrinsicFunction } from './types';
import { ApiRxInterface, QueryableStorageFunction, QueryableModuleStorage, QueryableStorage, SubmittableExtrinsics, SubmittableModuleExtrinsics, SubmittableExtrinsicFunction } from './types';
import E3 from 'eventemitter3';
import { EMPTY, Observable, from } from 'rxjs';
import { defaultIfEmpty, map } from 'rxjs/operators';
import WsProvider from '@polkadot/rpc-provider/ws';
import Rpc from '@polkadot/rpc-core/index';
import RpcRx from '@polkadot/rpc-rx/index';
import { Extrinsics, ExtrinsicFunction } from '@polkadot/extrinsics/types';
import extrinsicsFromMeta from '@polkadot/extrinsics/fromMetadata';
import { Storage } from '@polkadot/storage/types';
import storageFromMeta from '@polkadot/storage/fromMetadata';
import { Base } from '@polkadot/types/codec';
import { Hash, Method, RuntimeVersion } from '@polkadot/types/index';
import RuntimeMetadata from '@polkadot/types/Metadata';
import assert from '@polkadot/util/assert';
import isUndefined from '@polkadot/util/is/undefined';
import logger from '@polkadot/util/logger';
import ApiBase from '../Base';
import SubmittableExtrinsic from './SubmittableExtrinsic';
import { StorageFunction } from '@polkadot/types/StorageKey';
const l = logger('api');
const l = logger('api-rx');
const INIT_ERROR = `Api needs to be initialised before using, listen on 'whenReady'`;
export default class ApiRx extends E3.EventEmitter implements RxApiInterface {
private _extrinsics?: SubmittableExtrinsics;
private _genesisHash?: Hash;
private _storage?: QueryableStorage;
private _rpc: RpcRx;
private _runtimeMetadata?: RuntimeMetadata;
private _runtimeVersion?: RuntimeVersion;
// Observable that returns the first time we are connected and loaded
readonly isReady: Observable<ApiRx>;
export default class ApiRx extends ApiBase<RpcRx, QueryableStorage, SubmittableExtrinsics> implements ApiRxInterface {
private _isReady: Observable<ApiRx>;
/**
* @description Creates an ApiRx instance using the supplied provider. Returns an Observable containing the actual Api instance.
@@ -74,11 +59,16 @@ export default class ApiRx extends E3.EventEmitter implements RxApiInterface {
* ```
*/
constructor (wsProvider?: WsProvider) {
super();
super(wsProvider);
this._rpc = new RpcRx(wsProvider);
this.isReady = from(this.init());
this._isReady = from(
// convinced you can observable from an event, however my mind groks this form better
new Promise((resolveReady) =>
super.on('ready', () =>
resolveReady(this)
)
)
);
}
/**
@@ -89,142 +79,17 @@ export default class ApiRx extends E3.EventEmitter implements RxApiInterface {
}
/**
* @description Contains the genesis Hash of the attached chain. Apart from being useful to determine the actual chain, it can also be used to sign immortal transactions.
* @description Observable that returns the first time we are connected and loaded
*/
get genesisHash (): Hash {
assert(!isUndefined(this._genesisHash), INIT_ERROR);
return this._genesisHash as Hash;
get isReady (): Observable<ApiRx> {
return this._isReady;
}
/**
* @description Contains all the raw rpc sections and their subsequent methods in the API as defined by the jsonrpc interface definitions.
* @example
* <BR>
*
* ```javascript
* api.rpc.chain
* .newHead()
* .subscribe((header) => {
* console.log('new header', header);
* });
* ```
*/
get rpc (): RpcRx {
return this._rpc;
protected decorateRpc (rpc: Rpc): RpcRx {
return new RpcRx(rpc);
}
/**
* @description Yields the current attached runtime metadata. Generally this is only used to construct extrinsics & storage, but is useful for current runtime inspection.
*/
get runtimeMetadata (): RuntimeMetadata {
assert(!isUndefined(this._runtimeMetadata), INIT_ERROR);
return this._runtimeMetadata as RuntimeMetadata;
}
/**
* @description Contains the version information for the current runtime.
*/
get runtimeVersion (): RuntimeVersion {
assert(!isUndefined(this._runtimeVersion), INIT_ERROR);
return this._runtimeVersion as RuntimeVersion;
}
/**
* @description Contains all the chain state modules and their subsequent methods in the API. These are attached dynamically from the runtime metadata.
* @example
* <BR>
*
* ```javascript
* api.st.balances
* .freeBalance(<accountId>)
* .subscribe((balance) => {
* console.log('new balance', balance);
* });
* ```
*/
get st (): QueryableStorage {
assert(!isUndefined(this._storage), INIT_ERROR);
return this._storage as QueryableStorage;
}
/**
* @description Contains all the extrinsic modules and their subsequent methods in the API. It allows for the construction of transactions and the submission thereof. These are attached dynamically from the runtime metadata.
* @example
* <BR>
*
* ```javascript
* api.tx.balances
* .transfer(<recipientId>, <balance>)
* .sign(<keyPair>, <accountNonce>, <blockHash (optional)>)
* .send()
* .subscribe((status) => {
* console.log('tx status', status);
* });
* ```
*/
get tx (): SubmittableExtrinsics {
assert(!isUndefined(this._extrinsics), INIT_ERROR);
return this._extrinsics as SubmittableExtrinsics;
}
private init (): Promise<ApiRx> {
let isReady: boolean = false;
this.initEmitters();
return new Promise((resolveReady) => {
this.isConnected.subscribe(async (isConnected) => {
// TODO When re-connected (i.e. disconnected and then connected), we want to do a couple of things
// - refresh metadata as needed, decorating again
// - re-create storage subscriptions for those we already have
// - re-watch extrinsics where we have subscriptions already
// - need to refresh genesisHash, extrinsic resub only when it matches
if (isReady || !isConnected) {
return;
}
try {
this._runtimeMetadata = await this.rpc.state.getMetadata().toPromise();
this._runtimeVersion = await this.rpc.chain.getRuntimeVersion().toPromise();
this._genesisHash = await this.rpc.chain.getBlockHash(0).toPromise();
const extrinsics = extrinsicsFromMeta(this.runtimeMetadata);
const storage = storageFromMeta(this.runtimeMetadata);
this._extrinsics = this.decorateExtrinsics(extrinsics);
this._storage = this.decorateStorage(storage);
Method.injectExtrinsics(extrinsics);
if (!isReady) {
isReady = true;
resolveReady(this);
this.emit('ready', this);
}
} catch (error) {
l.error('init', error);
}
});
});
}
private initEmitters (): void {
this.rpc.on('connected', () => {
this.emit('connected');
});
this.rpc.on('disconnected', () => {
this.emit('disconnected');
});
}
private decorateExtrinsics (extrinsics: Extrinsics): SubmittableExtrinsics {
protected decorateExtrinsics (extrinsics: Extrinsics): SubmittableExtrinsics {
return Object.keys(extrinsics).reduce((result, sectionName) => {
const section = extrinsics[sectionName];
@@ -242,16 +107,10 @@ export default class ApiRx extends E3.EventEmitter implements RxApiInterface {
const decorated: any = (...args: Array<any>): SubmittableExtrinsic =>
new SubmittableExtrinsic(this, method(...args));
decorated.callIndex = method.callIndex;
decorated.meta = method.meta;
decorated.method = method.method;
decorated.section = method.section;
decorated.toJSON = method.toJSON;
return decorated as SubmittableExtrinsicFunction;
return this.decorateFunctionMeta(method, decorated) as SubmittableExtrinsicFunction;
}
private decorateStorage (storage: Storage): QueryableStorage {
protected decorateStorage (storage: Storage): QueryableStorage {
return Object.keys(storage).reduce((result, sectionName) => {
const section = storage[sectionName];
@@ -287,11 +146,6 @@ export default class ApiRx extends E3.EventEmitter implements RxApiInterface {
);
};
decorated.meta = method.meta;
decorated.method = method.method;
decorated.section = method.section;
decorated.toJSON = method.toJSON;
return decorated as QueryableStorageFunction;
return this.decorateFunctionMeta(method, decorated) as QueryableStorageFunction;
}
}
+4 -13
View File
@@ -2,10 +2,11 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { ApiBaseInterface } from '../types';
import { Observable } from 'rxjs';
import { ExtrinsicFunction } from '@polkadot/extrinsics/types';
import RpcRx from '@polkadot/rpc-rx/index';
import { RpcRxInterface$Events } from '@polkadot/rpc-rx/types';
import { Base } from '@polkadot/types/codec';
import { Hash, RuntimeVersion } from '@polkadot/types/index';
import RuntimeMetadata, { FunctionMetadata } from '@polkadot/types/Metadata';
@@ -37,17 +38,7 @@ export interface SubmittableExtrinsics {
[index: string]: SubmittableModuleExtrinsics;
}
export type RxApiInterface$Events = RpcRxInterface$Events | 'ready';
export interface RxApiInterface {
readonly genesisHash: Hash;
export interface ApiRxInterface extends ApiBaseInterface<RpcRx, QueryableStorage, SubmittableExtrinsics> {
readonly isConnected: Observable<boolean>;
readonly isReady: Observable<RxApiInterface>;
readonly rpc: RpcRx;
readonly runtimeMetadata: RuntimeMetadata;
readonly runtimeVersion: RuntimeVersion;
readonly st: QueryableStorage;
readonly tx: SubmittableExtrinsics
on: (type: RxApiInterface$Events, handler: (...args: Array<any>) => any) => void;
readonly isReady: Observable<ApiRxInterface>;
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2017-2018 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import RpcRx from '@polkadot/rpc-rx/index';
import { RpcRxInterface$Events } from '@polkadot/rpc-rx/types';
import { Base } from '@polkadot/types/codec';
import { Hash, RuntimeVersion } from '@polkadot/types/index';
import RuntimeMetadata, { FunctionMetadata } from '@polkadot/types/Metadata';
import { ExtrinsicFunction } from '@polkadot/extrinsics/types';
import { StorageFunction } from '@polkadot/types/StorageKey';
export type ApiInterface$Events = RpcRxInterface$Events | 'ready';
export interface ApiBaseInterface <R, S, E> {
readonly genesisHash: Hash;
readonly runtimeMetadata: RuntimeMetadata;
readonly runtimeVersion: RuntimeVersion;
readonly rpc: R;
readonly st: S;
readonly tx: E
on: (type: ApiInterface$Events, handler: (...args: Array<any>) => any) => void;
}
+2
View File
@@ -13,6 +13,8 @@ describe.skip('e2e queries', () => {
beforeEach(async () => {
api = await Api.create().toPromise();
console.error(api);
});
it('makes the runtime, rpc, state & extrinsics available', () => {
@@ -1,4 +1,4 @@
// Copyright 2017-2018 @polkadot/rpc-rx authors & contributors
// Copyright 2017-2018 @polkadot/rpc-core authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
+5 -2
View File
@@ -7,12 +7,15 @@ import { RpcSection, RpcMethod } from '@polkadot/jsonrpc/types';
import { RpcInterface, RpcInterface$Section, RpcInterface$Section$Method } from './types';
import interfaces from '@polkadot/jsonrpc/index';
import WsProvider from '@polkadot/rpc-provider/ws';
import { Base, Vector, createType } from '@polkadot/types/codec';
import { StorageChangeSet, StorageKey } from '@polkadot/types/index';
import assert from '@polkadot/util/assert';
import ExtError from '@polkadot/util/ext/error';
import isFunction from '@polkadot/util/is/function';
import defaults from './defaults';
/**
* @name Rpc
* @summary The API may use a HTTP or WebSockets provider.
@@ -37,7 +40,7 @@ import isFunction from '@polkadot/util/is/function';
* ```
*/
export default class Rpc implements RpcInterface {
private _provider: ProviderInterface;
readonly _provider: ProviderInterface;
readonly author: RpcInterface$Section;
readonly chain: RpcInterface$Section;
readonly state: RpcInterface$Section;
@@ -48,7 +51,7 @@ export default class Rpc implements RpcInterface {
* Default constructor for the Api Object
* @param {ProviderInterface} provider An API provider using HTTP or WebSocket
*/
constructor (provider: ProviderInterface) {
constructor (provider: ProviderInterface = new WsProvider(defaults.WS_URL)) {
assert(provider && isFunction(provider.send), 'Expected Provider to API create');
this._provider = provider;
+8 -9
View File
@@ -2,19 +2,16 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { RpcInterface, RpcInterface$Section } from '@polkadot/rpc-core/types';
import { RpcInterface$Section } from '@polkadot/rpc-core/types';
import { ProviderInterface } from '@polkadot/rpc-provider/types';
import { RpcRxInterface, RpcRxInterface$Section } from './types';
import E3 from 'eventemitter3';
import { BehaviorSubject, ReplaySubject, Observable, Subscriber, from } from 'rxjs';
import Rpc from '@polkadot/rpc-core/index';
import Ws from '@polkadot/rpc-provider/ws';
import isFunction from '@polkadot/util/is/function';
import isUndefined from '@polkadot/util/is/undefined';
import defaults from './defaults';
type CachedMap = {
[index: string]: {
[index: string]: ReplaySubject<any>
@@ -38,7 +35,7 @@ type CachedMap = {
* ```
*/
export default class RpcRx extends E3.EventEmitter implements RpcRxInterface {
private _api: RpcInterface;
private _api: Rpc;
private _cacheMap: CachedMap;
private _isConnected: BehaviorSubject<boolean>;
readonly author: RpcRxInterface$Section;
@@ -49,14 +46,16 @@ export default class RpcRx extends E3.EventEmitter implements RpcRxInterface {
/**
* @param {ProviderInterface} provider An API provider using HTTP or WebSocket
*/
constructor (provider: ProviderInterface = new Ws(defaults.WS_URL)) {
constructor (providerOrRpc?: Rpc | ProviderInterface) {
super();
this._api = new Rpc(provider);
this._api = providerOrRpc instanceof Rpc
? providerOrRpc
: new Rpc(providerOrRpc);
this._cacheMap = {};
this._isConnected = new BehaviorSubject(provider.isConnected());
this._isConnected = new BehaviorSubject(this._api._provider.isConnected());
this.initEmitters(provider);
this.initEmitters(this._api._provider);
this.author = this.createInterface('author', this._api.author);
this.chain = this.createInterface('chain', this._api.chain);
+13 -5
View File
@@ -17,6 +17,18 @@ import extrinsics from './index';
* @param metadata - The metadata to extend the storage object against.
*/
export default function fromMetadata (metadata: Metadata): Extrinsics {
const findIndex = (prefix: string): number => {
const mod = metadata.calls.find((item) =>
item.prefix.toString() === prefix
);
if (!mod) {
throw new Error(`Unable to find module index for '${prefix}'`);
}
return mod.index.toNumber();
};
// Dont' clobber the input, create new
const result = Object.keys(extrinsics).reduce((result, key) => {
result[key] = extrinsics[key];
@@ -24,15 +36,13 @@ export default function fromMetadata (metadata: Metadata): Extrinsics {
return result;
}, {} as Extrinsics);
// Only increment indexes (starting at 0), for modules with actual functions
let index = 0;
return metadata.modules.reduce((result, meta: RuntimeModuleMetadata) => {
if (!meta.module.call || !meta.module.call.functions.length) {
return result;
}
const prefix = camelCase(meta.prefix.toString());
const index = findIndex(meta.prefix.toString());
result[prefix] = meta.module.call.functions.reduce((newModule, funcMeta) => {
// extrinsics.balances.set_balance -> extrinsics.balances.setBalance
@@ -43,8 +53,6 @@ export default function fromMetadata (metadata: Metadata): Extrinsics {
return newModule;
}, {} as ModuleExtrinsics);
index++;
return result;
}, result);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+61 -6
View File
@@ -6,12 +6,14 @@ import { AnyNumber } from './types';
import toU8a from '@polkadot/util/u8a/toU8a';
import Vector from './codec/Vector';
import Base from './codec/Base';
import Compact, { DEFAULT_LENGTH_BITS } from './codec/Compact';
import Enum from './codec/Enum';
import EnumType from './codec/EnumType';
import Option from './codec/Option';
import Struct from './codec/Struct';
import Tuple from './codec/Tuple';
import Vector from './codec/Vector';
import Text from './Text';
import Type from './Type';
import U16 from './U16';
@@ -20,6 +22,45 @@ import U16 from './U16';
// file is probably best understood from the bottom-up, i.e. start reading right at the
// end and work up. (Just so we don't use before definition)
export class OuterDispatchCall extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
index: U16
}, value);
}
get index (): U16 {
return this.raw.index as U16;
}
get name (): Text {
return this.raw.name as Text;
}
get prefix (): Text {
return this.raw.prefix as Text;
}
}
export class OuterDispatchMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
calls: Vector.with(OuterDispatchCall)
}, value);
}
get calls (): Vector<OuterDispatchCall> {
return this.raw.calls as Vector<OuterDispatchCall>;
}
get name (): Text {
return this.raw.name as Text;
}
}
export class EventMetadata extends Struct {
constructor (value?: any) {
super({
@@ -42,7 +83,7 @@ export class EventMetadata extends Struct {
}
}
export class OuterEventMetadataEvent extends Struct {
export class OuterEventMetadataEvent extends Tuple {
constructor (value?: any) {
super({
name: Text,
@@ -51,11 +92,11 @@ export class OuterEventMetadataEvent extends Struct {
}
get events (): Vector<EventMetadata> {
return this.raw.events as Vector<EventMetadata>;
return this.get(1) as Vector<EventMetadata>;
}
get name (): Text {
return this.raw.name as Text;
return this.get(0) as Text;
}
}
@@ -281,7 +322,8 @@ export default class RuntimeMetadata extends Struct {
constructor (value?: any) {
super({
outerEvent: OuterEventMetadata,
modules: Vector.with(RuntimeModuleMetadata)
modules: Vector.with(RuntimeModuleMetadata),
outerDispatch: OuterDispatchMetadata
}, value);
}
@@ -290,7 +332,16 @@ export default class RuntimeMetadata extends Struct {
fromJSON (input: Uint8Array | string | Array<number>): RuntimeMetadata {
return this.fromU8a(
toU8a(input)
) as RuntimeMetadata;
);
}
fromU8a (input: Uint8Array): RuntimeMetadata {
// this does not look correct, metadata now has a length prefix. Strip, move on.
const [offset] = Compact.decodeU8a(input, DEFAULT_LENGTH_BITS);
super.fromU8a(input.subarray(offset));
return this;
}
// FIXME Currently toJSON creates a struct, so it is not a one-to-one mapping
@@ -300,6 +351,10 @@ export default class RuntimeMetadata extends Struct {
return super.toJSON();
}
get calls (): Vector<OuterDispatchCall> {
return (this.raw.outerDispatch as OuterDispatchMetadata).calls;
}
get events (): Vector<OuterEventMetadataEvent> {
return (this.raw.outerEvent as OuterEventMetadata).events;
}