Adjust contract call result decoding (#3510)

* Adjust types for node/node-template

* Adjust contract call result

* Adjust

* Raw directly

* CHANGELOG
This commit is contained in:
Jaco
2021-05-09 09:46:21 +02:00
committed by GitHub
parent 76363c0142
commit 80ab628643
5 changed files with 29 additions and 57 deletions
+3
View File
@@ -12,6 +12,9 @@ Changes:
- Allow for `Bounded*` type usage (as per latest Substrate) - Allow for `Bounded*` type usage (as per latest Substrate)
- Adjust internal TS definitions for providers - Adjust internal TS definitions for providers
- Fix `ContractRx` query result definitions (no extra Observable) - Fix `ContractRx` query result definitions (no extra Observable)
- Handle contract call RPC result directly as `Raw` (returned as hex)
- Use `BN_*` constants as non-specified defaults in contract interfaces
- Remove all type overrides for node/node-template (API tracks latest)
## 4.9.1 May 6, 2021 ## 4.9.1 May 6, 2021
+22 -48
View File
@@ -4,8 +4,8 @@
import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types'; import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
import type { ApiTypes, DecorateMethod } from '@polkadot/api/types'; import type { ApiTypes, DecorateMethod } from '@polkadot/api/types';
import type { Bytes } from '@polkadot/types'; import type { Bytes } from '@polkadot/types';
import type { AccountId, ContractExecResult, EventRecord, Weight } from '@polkadot/types/interfaces'; import type { AccountId, EventRecord, Weight } from '@polkadot/types/interfaces';
import type { AnyJson, CodecArg, ISubmittableResult, Registry } from '@polkadot/types/types'; import type { AnyJson, CodecArg, ISubmittableResult } from '@polkadot/types/types';
import type { AbiMessage, ContractCallOutcome, ContractOptions, DecodedEvent } from '../types'; import type { AbiMessage, ContractCallOutcome, ContractOptions, DecodedEvent } from '../types';
import type { ContractCallResult, ContractCallSend, ContractQuery, ContractTx, MapMessageQuery, MapMessageTx } from './types'; import type { ContractCallResult, ContractCallSend, ContractQuery, ContractTx, MapMessageQuery, MapMessageTx } from './types';
@@ -13,11 +13,12 @@ import BN from 'bn.js';
import { SubmittableResult } from '@polkadot/api'; import { SubmittableResult } from '@polkadot/api';
import { ApiBase } from '@polkadot/api/base'; import { ApiBase } from '@polkadot/api/base';
import { createTypeUnsafe } from '@polkadot/types';
import { assert, BN_HUNDRED, BN_ONE, BN_ZERO, bnToBn, isFunction, isUndefined, logger } from '@polkadot/util'; import { assert, BN_HUNDRED, BN_ONE, BN_ZERO, bnToBn, isFunction, isUndefined, logger } from '@polkadot/util';
import { map } from '@polkadot/x-rxjs/operators'; import { map } from '@polkadot/x-rxjs/operators';
import { Abi } from '../Abi'; import { Abi } from '../Abi';
import { applyOnEvent, extractOptions, formatData, isOptions } from '../util'; import { applyOnEvent, extractOptions, isOptions } from '../util';
import { Base } from './Base'; import { Base } from './Base';
// As per Rust, 5 * GAS_PER_SEC // As per Rust, 5 * GAS_PER_SEC
@@ -50,33 +51,6 @@ export class ContractSubmittableResult extends SubmittableResult {
} }
} }
// map from a JSON result to current-style ContractExecResult
function mapExecResult (registry: Registry, json: Record<string, AnyJson>): ContractExecResult {
if (!Object.keys(json).some((key) => ['error', 'success'].includes(key))) {
return registry.createType('ContractExecResult', json);
}
const from = registry.createType('ContractExecResultTo260', json);
if (from.isSuccess) {
const s = from.asSuccess;
return registry.createType('ContractExecResult', {
gasConsumed: s.gasConsumed,
result: {
ok: {
data: s.data,
flags: s.flags
}
}
});
}
// in the old format error has no additional information,
// map it as-is with an "unknown" error
return registry.createType('ContractExecResult', { result: { err: { other: 'unknown' } } });
}
export class Contract<ApiType extends ApiTypes> extends Base<ApiType> { export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
/** /**
* @description The on-chain address for this contract * @description The on-chain address for this contract
@@ -159,24 +133,24 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
return { return {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
send: this._decorateMethod((origin: string | AccountId | Uint8Array) => send: this._decorateMethod((origin: string | AccountId | Uint8Array) =>
this.api.rx.rpc.contracts.call.json({ this.api.rx.rpc.contracts
dest: this.address, .call({
gasLimit: this.#getGas(gasLimit, true), dest: this.address,
inputData: message.toU8a(params), gasLimit: this.#getGas(gasLimit, true),
origin, inputData: message.toU8a(params),
value origin,
}).pipe(map((json): ContractCallOutcome => { value
const { debugMessage, gasConsumed, result } = mapExecResult(this.registry, json.toJSON()); })
.pipe(
return { map(({ debugMessage, gasConsumed, result }): ContractCallOutcome => ({
debugMessage, debugMessage,
gasConsumed, gasConsumed,
output: result.isOk && message.returnType output: result.isOk && message.returnType
? formatData(this.registry, result.asOk.data, message.returnType) ? createTypeUnsafe(this.registry, message.returnType.type, [result.asOk.data], { isPedantic: true })
: null, : null,
result result
}; }))
})) )
) )
}; };
} }
+1 -7
View File
@@ -2,24 +2,18 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import type { SubmittableResult } from '@polkadot/api'; import type { SubmittableResult } from '@polkadot/api';
import type { Raw } from '@polkadot/types';
import type { EventRecord } from '@polkadot/types/interfaces'; import type { EventRecord } from '@polkadot/types/interfaces';
import type { Codec, CodecArg, Registry, TypeDef } from '@polkadot/types/types'; import type { CodecArg } from '@polkadot/types/types';
import type { BlueprintOptions, ContractOptions } from './types'; import type { BlueprintOptions, ContractOptions } from './types';
import BN from 'bn.js'; import BN from 'bn.js';
import { createTypeUnsafe } from '@polkadot/types/create';
import { isBigInt, isBn, isNumber, isString } from '@polkadot/util'; import { isBigInt, isBn, isNumber, isString } from '@polkadot/util';
type ContractEvents = 'CodeStored' | 'ContractEmitted' | 'ContractExecution' | 'Instantiated'; type ContractEvents = 'CodeStored' | 'ContractEmitted' | 'ContractExecution' | 'Instantiated';
type TOptions = BlueprintOptions | ContractOptions; type TOptions = BlueprintOptions | ContractOptions;
export function formatData (registry: Registry, data: Raw, { type }: TypeDef): Codec {
return createTypeUnsafe(registry, type, [data], { isPedantic: true });
}
export function applyOnEvent <T> (result: SubmittableResult, types: ContractEvents[], fn: (records: EventRecord[]) => T): T | undefined { export function applyOnEvent <T> (result: SubmittableResult, types: ContractEvents[], fn: (records: EventRecord[]) => T): T | undefined {
if (result.isInBlock || result.isFinalized) { if (result.isInBlock || result.isFinalized) {
const records = result.filterRecords('contracts', types); const records = result.filterRecords('contracts', types);
@@ -133,7 +133,8 @@ export default {
}, },
ContractExecResultOk: { ContractExecResultOk: {
flags: 'u32', flags: 'u32',
data: 'Bytes' // only via RPC, decode hex exactly as received
data: 'Raw'
}, },
ContractExecResultResult: { ContractExecResultResult: {
_enum: { _enum: {
@@ -56,7 +56,7 @@ export interface ContractExecResultErrModule extends Struct {
/** @name ContractExecResultOk */ /** @name ContractExecResultOk */
export interface ContractExecResultOk extends Struct { export interface ContractExecResultOk extends Struct {
readonly flags: u32; readonly flags: u32;
readonly data: Bytes; readonly data: Raw;
} }
/** @name ContractExecResultResult */ /** @name ContractExecResultResult */