Decode contract events (#2763)

* Decode contract events

* Untable marker
This commit is contained in:
Jaco Greeff
2020-10-22 15:01:09 +02:00
committed by GitHub
parent 93fbd6e13f
commit 45a895b64f
2 changed files with 62 additions and 12 deletions
+48 -10
View File
@@ -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
};
+14 -2
View File
@@ -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;