Expose ABI messages on Contract/Blueprint (#2715)
* Expose ABI messages on Contract/Blueprint * Rename actual files & exports * Adjust .query signature (origin) * Assert contracts.call
This commit is contained in:
@@ -6,10 +6,12 @@ import { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
|
||||
import { AccountId, EventRecord, Hash } from '@polkadot/types/interfaces';
|
||||
import { AnyJson, CodecArg, ISubmittableResult } from '@polkadot/types/types';
|
||||
import { AbiConstructor } from '../types';
|
||||
import { MapConstructorExec } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
import ApiBase from '@polkadot/api/base';
|
||||
import { isUndefined, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import { applyOnEvent, encodeMessage } from '../util';
|
||||
@@ -29,13 +31,28 @@ export class BlueprintSubmittableResult<ApiType extends ApiTypes> extends Submit
|
||||
export default class Blueprint<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
public readonly codeHash: Hash;
|
||||
|
||||
readonly #tx: MapConstructorExec<ApiType> = {};
|
||||
|
||||
constructor (api: ApiBase<ApiType>, abi: AnyJson | Abi, codeHash: string | Hash | Uint8Array, decorateMethod: DecorateMethod<ApiType>) {
|
||||
super(api, abi, decorateMethod);
|
||||
|
||||
this.codeHash = this.registry.createType('Hash', codeHash);
|
||||
|
||||
this.abi.constructors.forEach((c): void => {
|
||||
const messageName = stringCamelCase(c.identifier);
|
||||
|
||||
if (isUndefined(this.#tx[messageName])) {
|
||||
this.#tx[messageName] = (endowment: BigInt | string | number | BN, gasLimit: BigInt | string | number | BN, ...params: CodecArg[]) =>
|
||||
this.#deploy(c, endowment, gasLimit, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public createContract (constructorOrId: AbiConstructor | string| number, endowment: BigInt | string | number | BN, gasLimit: BigInt | string | number | BN, ...params: CodecArg[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> {
|
||||
public get tx (): MapConstructorExec<ApiType> {
|
||||
return this.#tx;
|
||||
}
|
||||
|
||||
#deploy = (constructorOrId: AbiConstructor | string| number, endowment: BigInt | string | number | BN, gasLimit: BigInt | string | number | BN, params: CodecArg[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> => {
|
||||
return this.api.tx.contracts
|
||||
.instantiate(endowment, gasLimit, this.codeHash, encodeMessage(this.registry, this.abi.findConstructor(constructorOrId), params))
|
||||
.withResultTransform((result: ISubmittableResult) =>
|
||||
@@ -44,4 +61,8 @@ export default class Blueprint<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
public createContract (constructorOrId: AbiConstructor | string| number, endowment: BigInt | string | number | BN, gasLimit: BigInt | string | number | BN, ...params: CodecArg[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> {
|
||||
return this.#deploy(constructorOrId, endowment, gasLimit, params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +1,82 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { ApiTypes, DecorateMethod, ObsInnerType } from '@polkadot/api/types';
|
||||
import { ApiTypes, DecorateMethod } from '@polkadot/api/types';
|
||||
import { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
|
||||
import { AccountId, ContractExecResult } from '@polkadot/types/interfaces';
|
||||
import { AnyJson, CodecArg, IKeyringPair } from '@polkadot/types/types';
|
||||
import { AnyJson, CodecArg } from '@polkadot/types/types';
|
||||
import { AbiMessage, ContractCallOutcome } from '../types';
|
||||
import { ContractCallResult, ContractRead, MapMessageExec, MapMessageRead } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
import ApiBase from '@polkadot/api/base';
|
||||
import { assert, isFunction } from '@polkadot/util';
|
||||
import { assert, isFunction, isUndefined, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import { encodeMessage, formatData } from '../util';
|
||||
import Base from './Base';
|
||||
|
||||
type ContractCallTypes = 'tx' | 'rpc';
|
||||
|
||||
type ContractCallResultSubscription<ApiType extends ApiTypes, CallType extends ContractCallTypes> = ApiType extends 'rxjs'
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
? Observable<ContractCallResult<CallType>>
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
: Promise<ObsInnerType<ContractCallResult<CallType>>>;
|
||||
|
||||
export interface ContractRead<ApiType extends ApiTypes> {
|
||||
send (account: IKeyringPair | string | AccountId): ContractCallResultSubscription<ApiType, 'rpc'>;
|
||||
}
|
||||
|
||||
export type ContractCallResult<CallType extends ContractCallTypes> = CallType extends 'rpc'
|
||||
? Observable<ContractCallOutcome>
|
||||
: Observable<SubmittableResult>;
|
||||
const ERROR_NO_CALL = 'Your node does not expose the contracts.call RPC. This is most probably due to a runtime configuration.';
|
||||
|
||||
export default class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
public readonly address: AccountId;
|
||||
|
||||
readonly #tx: MapMessageExec<ApiType> = {};
|
||||
|
||||
readonly #query: MapMessageRead<ApiType> = {};
|
||||
|
||||
constructor (api: ApiBase<ApiType>, abi: AnyJson | Abi, address: string | AccountId, decorateMethod: DecorateMethod<ApiType>) {
|
||||
super(api, abi, decorateMethod);
|
||||
|
||||
this.address = this.registry.createType('AccountId', address);
|
||||
|
||||
this.abi.messages.forEach((m): void => {
|
||||
const messageName = stringCamelCase(m.identifier);
|
||||
|
||||
if (isUndefined(this.#tx[messageName])) {
|
||||
this.#tx[messageName] = (value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]) =>
|
||||
this.#exec(m, value, gasLimit, params);
|
||||
}
|
||||
|
||||
if (isUndefined(this.#query[messageName])) {
|
||||
this.#query[messageName] = (origin: string | AccountId | Uint8Array, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]) =>
|
||||
this.#read(m, value, gasLimit, params).send(origin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public get hasRpcContractsCall (): boolean {
|
||||
return isFunction(this.api.rx.rpc.contracts?.call);
|
||||
}
|
||||
|
||||
public exec (messageOrId: AbiMessage | string | number, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]): SubmittableExtrinsic<ApiType> {
|
||||
public get query (): MapMessageRead<ApiType> {
|
||||
assert(this.hasRpcContractsCall, ERROR_NO_CALL);
|
||||
|
||||
return this.#query;
|
||||
}
|
||||
|
||||
public get tx (): MapMessageExec<ApiType> {
|
||||
return this.#tx;
|
||||
}
|
||||
|
||||
#exec = (messageOrId: AbiMessage | string | number, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, params: CodecArg[]): SubmittableExtrinsic<ApiType> => {
|
||||
return this.api.tx.contracts.call(this.address, value, gasLimit, encodeMessage(this.registry, this.abi.findMessage(messageOrId), params));
|
||||
}
|
||||
|
||||
public read (messageOrId: AbiMessage | string | number, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]): ContractRead<ApiType> {
|
||||
assert(this.hasRpcContractsCall, 'Your node does not support contract RPC read calls');
|
||||
#read = (messageOrId: AbiMessage | string | number, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, params: CodecArg[]): ContractRead<ApiType> => {
|
||||
assert(this.hasRpcContractsCall, ERROR_NO_CALL);
|
||||
|
||||
const message = this.abi.findMessage(messageOrId);
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
send: this._decorateMethod((account: string | AccountId | Uint8Array): ContractCallResult<'rpc'> =>
|
||||
send: this._decorateMethod((origin: string | AccountId | Uint8Array): ContractCallResult<'rpc'> =>
|
||||
this.api.rx.rpc.contracts.call({
|
||||
dest: this.address,
|
||||
gasLimit,
|
||||
inputData: encodeMessage(this.registry, message, params),
|
||||
origin: account,
|
||||
origin,
|
||||
value
|
||||
}).pipe(
|
||||
map((result: ContractExecResult): ContractCallOutcome => ({
|
||||
@@ -76,4 +89,12 @@ export default class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
public exec (messageOrId: AbiMessage | string | number, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]): SubmittableExtrinsic<ApiType> {
|
||||
return this.#exec(messageOrId, value, gasLimit, params);
|
||||
}
|
||||
|
||||
public read (messageOrId: AbiMessage | string | number, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]): ContractRead<ApiType> {
|
||||
return this.#read(messageOrId, value, gasLimit, params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2017-2020 @polkadot/api authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export { default as Blueprint } from './Blueprint';
|
||||
export { default as Code } from './Code';
|
||||
export { default as Blueprint, BlueprintSubmittableResult } from './Blueprint';
|
||||
export { default as Code, CodeSubmittableResult } from './Code';
|
||||
export { default as Contract } from './Contract';
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
import { ApiTypes, ObsInnerType } from '@polkadot/api/types';
|
||||
import { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
|
||||
import { AccountId } from '@polkadot/types/interfaces';
|
||||
import { CodecArg } from '@polkadot/types/types';
|
||||
import { ContractCallOutcome } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
type ContractCallTypes = 'tx' | 'rpc';
|
||||
|
||||
type ContractCallResultSubscription<ApiType extends ApiTypes, CallType extends ContractCallTypes> = ApiType extends 'rxjs'
|
||||
? Observable<ContractCallResult<CallType>>
|
||||
: Promise<ObsInnerType<ContractCallResult<CallType>>>;
|
||||
|
||||
export interface ContractRead<ApiType extends ApiTypes> {
|
||||
send (account: string | AccountId | Uint8Array): ContractCallResultSubscription<ApiType, 'rpc'>;
|
||||
}
|
||||
|
||||
export type ContractCallResult<CallType extends ContractCallTypes> = CallType extends 'rpc'
|
||||
? Observable<ContractCallOutcome>
|
||||
: Observable<SubmittableResult>;
|
||||
|
||||
export interface MapConstructorExec<ApiType extends ApiTypes> {
|
||||
[message: string]: (endowment: BigInt | string | number | BN, gasLimit: BigInt | string | number | BN, ...params: CodecArg[]) => SubmittableExtrinsic<ApiType>;
|
||||
}
|
||||
|
||||
export interface MapMessageExec<ApiType extends ApiTypes> {
|
||||
[message: string]: (value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]) => SubmittableExtrinsic<ApiType>;
|
||||
}
|
||||
|
||||
export interface MapMessageRead<ApiType extends ApiTypes> {
|
||||
[message: string]: (origin: AccountId | string | Uint8Array, value: BigInt | BN | string | number, gasLimit: BigInt | BN | string | number, ...params: CodecArg[]) => ContractCallResultSubscription<ApiType, 'rpc'>;
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export { CodeSubmittableResult } from './base/Code';
|
||||
export { BlueprintSubmittableResult } from './base/Blueprint';
|
||||
|
||||
export { default as Abi } from './Abi';
|
||||
|
||||
export * from './rx';
|
||||
export * from './promise';
|
||||
export { Blueprint as BlueprintRx, Code as CodeRx, Contract as ContractRx } from './rx';
|
||||
export { Blueprint as BlueprintPromise, Code as CodePromise, Contract as ContractPromise } from './promise';
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@ import { ApiPromise } from '@polkadot/api';
|
||||
import { decorateMethod } from '@polkadot/api/promise';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import Blueprint from '../base/Blueprint';
|
||||
import BaseBlueprint from '../base/Blueprint';
|
||||
|
||||
export default class PromiseBlueprint extends Blueprint<'promise'> {
|
||||
export default class Blueprint extends BaseBlueprint<'promise'> {
|
||||
constructor (api: ApiPromise, abi: AnyJson | Abi, codeHash: string | Hash) {
|
||||
super(api, abi, codeHash, decorateMethod);
|
||||
}
|
||||
+2
-2
@@ -6,9 +6,9 @@ import { decorateMethod } from '@polkadot/api/promise';
|
||||
import { AnyJson } from '@polkadot/types/types';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import Code from '../base/Code';
|
||||
import BaseCode from '../base/Code';
|
||||
|
||||
export default class PromiseCode extends Code<'promise'> {
|
||||
export default class Code extends BaseCode<'promise'> {
|
||||
constructor (api: ApiPromise, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer) {
|
||||
super(api, abi, wasm, decorateMethod);
|
||||
}
|
||||
+2
-2
@@ -8,9 +8,9 @@ import { ApiPromise } from '@polkadot/api';
|
||||
import { decorateMethod } from '@polkadot/api/promise';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import Contract from '../base/Contract';
|
||||
import BaseContract from '../base/Contract';
|
||||
|
||||
export default class PromiseContract extends Contract<'promise'> {
|
||||
export default class Contract extends BaseContract<'promise'> {
|
||||
constructor (api: ApiPromise, abi: AnyJson | Abi, address: string | AccountId) {
|
||||
super(api, abi, address, decorateMethod);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export { default as BlueprintPromise } from './PromiseBlueprint';
|
||||
export { default as CodePromise } from './PromiseCode';
|
||||
export { default as ContractPromise } from './PromiseContract';
|
||||
export { default as Blueprint } from './Blueprint';
|
||||
export { default as Code } from './Code';
|
||||
export { default as Contract } from './Contract';
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { BlueprintSubmittableResult as BaseBlueprintSubmittableResult, CodeSubmittableResult as BaseCodeSubmittableResult } from '../base';
|
||||
|
||||
export type BlueprintSubmittableResult = BaseBlueprintSubmittableResult<'promise'>;
|
||||
export type CodeSubmittableResult = BaseCodeSubmittableResult<'promise'>;
|
||||
+2
-2
@@ -8,9 +8,9 @@ import { ApiRx } from '@polkadot/api';
|
||||
import { decorateMethod } from '@polkadot/api/rx';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import Blueprint from '../base/Blueprint';
|
||||
import BaseBlueprint from '../base/Blueprint';
|
||||
|
||||
export default class RxBlueprint extends Blueprint<'rxjs'> {
|
||||
export default class Blueprint extends BaseBlueprint<'rxjs'> {
|
||||
constructor (api: ApiRx, abi: AnyJson | Abi, codeHash: string | Hash) {
|
||||
super(api, abi, codeHash, decorateMethod);
|
||||
}
|
||||
@@ -7,9 +7,9 @@ import { ApiRx } from '@polkadot/api';
|
||||
import { decorateMethod } from '@polkadot/api/rx';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import Code from '../base/Code';
|
||||
import BaseCode from '../base/Code';
|
||||
|
||||
export default class RxCode extends Code<'rxjs'> {
|
||||
export default class Code extends BaseCode<'rxjs'> {
|
||||
constructor (api: ApiRx, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer) {
|
||||
super(api, abi, wasm, decorateMethod);
|
||||
}
|
||||
+2
-2
@@ -8,9 +8,9 @@ import { ApiRx } from '@polkadot/api';
|
||||
import { decorateMethod } from '@polkadot/api/rx';
|
||||
|
||||
import Abi from '../Abi';
|
||||
import Contract from '../base/Contract';
|
||||
import BaseContract from '../base/Contract';
|
||||
|
||||
export default class RxContract extends Contract<'rxjs'> {
|
||||
export default class Contract extends BaseContract<'rxjs'> {
|
||||
constructor (api: ApiRx, abi: AnyJson | Abi, address: string | AccountId) {
|
||||
super(api, abi, address, decorateMethod);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export { default as BlueprintRx } from './RxBlueprint';
|
||||
export { default as CodeRx } from './RxCode';
|
||||
export { default as ContractRx } from './RxContract';
|
||||
export { default as Blueprint } from './Blueprint';
|
||||
export { default as Code } from './Code';
|
||||
export { default as Contract } from './Contract';
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/api-contract authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { BlueprintSubmittableResult as BaseBlueprintSubmittableResult, CodeSubmittableResult as BaseCodeSubmittableResult } from '../base';
|
||||
|
||||
export type BlueprintSubmittableResult = BaseBlueprintSubmittableResult<'promise'>;
|
||||
export type CodeSubmittableResult = BaseCodeSubmittableResult<'promise'>;
|
||||
Reference in New Issue
Block a user