Decode contract events (#2763)
* Decode contract events * Untable marker
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { AnyJson } from '@polkadot/types/types';
|
||||
import { ChainProperties, ContractConstructorSpec, ContractMessageSpec, ContractProject } from '@polkadot/types/interfaces';
|
||||
import { AbiConstructor, AbiMessage, AbiMessageParam } from './types';
|
||||
import { AnyJson, Codec } from '@polkadot/types/types';
|
||||
import { ChainProperties, ContractConstructorSpec, ContractEventSpec, ContractMessageSpec, ContractMessageParamSpec, ContractProject } from '@polkadot/types/interfaces';
|
||||
import { AbiConstructor, AbiEvent, AbiMessage, AbiParam, DecodedEvent } from './types';
|
||||
|
||||
import { assert, isNumber, isObject, isString, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
@@ -22,6 +22,8 @@ function findMessage <T extends AbiMessage> (list: T[], messageOrId: T | string
|
||||
}
|
||||
|
||||
export default class Abi {
|
||||
readonly #events: AbiEvent[];
|
||||
|
||||
public readonly constructors: AbiConstructor[];
|
||||
|
||||
public readonly json: AnyJson;
|
||||
@@ -47,14 +49,17 @@ export default class Abi {
|
||||
|
||||
this.project.types.forEach((_, index) => this.registry.getMetaTypeDef(this.registry.createType('SiLookupTypeId', index + 1)));
|
||||
this.constructors = this.project.spec.constructors.map((spec: ContractConstructorSpec, index) =>
|
||||
this.#createBase(spec, index, {
|
||||
this.#createMessage(spec, index, {
|
||||
isConstructor: true
|
||||
})
|
||||
);
|
||||
this.#events = this.project.spec.events.map((spec: ContractEventSpec, index) =>
|
||||
this.#createEvent(spec, index)
|
||||
);
|
||||
this.messages = this.project.spec.messages.map((spec: ContractMessageSpec, index): AbiMessage => {
|
||||
const typeSpec = spec.returnType.unwrapOr(null);
|
||||
|
||||
return this.#createBase(spec, index, {
|
||||
return this.#createMessage(spec, index, {
|
||||
isMutating: spec.mutates.isTrue,
|
||||
isPayable: spec.payable.isTrue,
|
||||
returnType: typeSpec
|
||||
@@ -64,6 +69,29 @@ export default class Abi {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning: Unstable API, bound to change
|
||||
*/
|
||||
public decodeEvent (eventU8a: Uint8Array): DecodedEvent {
|
||||
const index = eventU8a[0];
|
||||
const event = this.#events[index];
|
||||
|
||||
assert(event, `Unable to find event with index ${index}`);
|
||||
|
||||
let offset = 1;
|
||||
|
||||
return {
|
||||
args: event.args.map(({ type }): Codec => {
|
||||
const value = this.registry.createType(type.type as 'Text', eventU8a.subarray(offset));
|
||||
|
||||
offset += value.encodedLength;
|
||||
|
||||
return value;
|
||||
}),
|
||||
event
|
||||
};
|
||||
}
|
||||
|
||||
public findConstructor (constructorOrId: AbiConstructor | string | number): AbiConstructor {
|
||||
return findMessage(this.constructors, constructorOrId);
|
||||
}
|
||||
@@ -72,9 +100,8 @@ export default class Abi {
|
||||
return findMessage(this.messages, messageOrId);
|
||||
}
|
||||
|
||||
#createBase = (spec: ContractMessageSpec | ContractConstructorSpec, index: number, add: Partial<AbiMessage> = {}): AbiMessage => {
|
||||
const identifier = spec.name.toString();
|
||||
const args = spec.args.map((arg, index): AbiMessageParam => {
|
||||
#createArgs = (args: ContractMessageParamSpec[], spec: unknown): AbiParam[] => {
|
||||
return args.map((arg, index): AbiParam => {
|
||||
try {
|
||||
assert(isObject(arg.type), 'Invalid type definition found');
|
||||
|
||||
@@ -88,12 +115,23 @@ export default class Abi {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#createEvent = (spec: ContractEventSpec, index: number): AbiEvent => {
|
||||
return {
|
||||
args: this.#createArgs(spec.args, spec),
|
||||
docs: spec.docs.map((doc) => doc.toString()),
|
||||
identifier: spec.name.toString(),
|
||||
index
|
||||
};
|
||||
}
|
||||
|
||||
#createMessage = (spec: ContractMessageSpec | ContractConstructorSpec, index: number, add: Partial<AbiMessage> = {}): AbiMessage => {
|
||||
return {
|
||||
...add,
|
||||
args,
|
||||
args: this.#createArgs(spec.args, spec),
|
||||
docs: spec.docs.map((doc) => doc.toString()),
|
||||
identifier,
|
||||
identifier: spec.name.toString(),
|
||||
index,
|
||||
selector: spec.selector
|
||||
};
|
||||
|
||||
@@ -16,13 +16,25 @@ export interface ContractBase<ApiType extends ApiTypes> {
|
||||
messages: AbiMessage[];
|
||||
}
|
||||
|
||||
export interface AbiMessageParam {
|
||||
export interface AbiParam {
|
||||
name: string;
|
||||
type: TypeDef;
|
||||
}
|
||||
|
||||
export interface AbiEvent {
|
||||
args: AbiParam[];
|
||||
docs: string[];
|
||||
identifier: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface DecodedEvent {
|
||||
args: Codec[];
|
||||
event: AbiEvent;
|
||||
}
|
||||
|
||||
export interface AbiMessage {
|
||||
args: AbiMessageParam[];
|
||||
args: AbiParam[];
|
||||
docs: string[];
|
||||
identifier: string;
|
||||
index: number;
|
||||
|
||||
Reference in New Issue
Block a user