Extract DispatchError on incomplete (#7213)

* Extract DispatchError on incomplete

* Mark error appropriately

* Apply suggestions from code review
This commit is contained in:
Jaco 2022-03-23 08:20:17 +01:00 committed by GitHub
parent 19b6d47f01
commit 97ca1cc85e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 40 deletions

View File

@ -90,13 +90,12 @@ function useCollectionInfosImpl (ids?: BN[]): CollectionInfo[] | undefined {
const details = useCall<[[BN[]], Option<PalletUniquesClassDetails>[]]>(api.query.uniques.class.multi, [ids], QUERY_OPTS);
const [state, setState] = useState<CollectionInfo[] | undefined>();
const ipfsHashes = useMemo((): string[] | undefined => {
if (metadata && metadata[1].length) {
return metadata[1].map((metadataItem) => metadataItem.toHuman()?.data?.toString() || '');
}
return undefined;
}, [metadata]);
const ipfsHashes = useMemo(
() => metadata && metadata[1].length
? metadata[1].map((m) => m.toHuman()?.data?.toString() || '')
: [],
[metadata]
);
const ipfsData = useIpfsFetch<CollectionSupportedIpfsData | null>(ipfsHashes, IPFS_FETCH_OPTIONS);

View File

@ -13,7 +13,7 @@ import { SubmittableResult } from '@polkadot/api';
import jsonrpc from '@polkadot/types/interfaces/jsonrpc';
import { getContractAbi } from '../util';
import { isIncompleteEvent } from './checks';
import { getDispatchError, getIncompleteMessage } from './checks';
import { STATUS_COMPLETE } from './constants';
import { QueueProvider } from './Context';
@ -95,30 +95,20 @@ function extractEvents (result?: SubmittableResult): ActionStatus[] {
if (section === 'system' && method === 'ExtrinsicFailed') {
const [dispatchError] = data as unknown as ITuple<[DispatchError]>;
let message = dispatchError.type;
if (dispatchError.isModule) {
try {
const mod = dispatchError.asModule;
const error = dispatchError.registry.findMetaError(mod);
message = `${error.section}.${error.name}` as unknown as 'Other';
} catch (error) {
// swallow
}
} else if (dispatchError.isToken) {
message = `${dispatchError.type}.${dispatchError.asToken.type}` as unknown as 'Other';
}
return {
action: `${section}.${method}`,
message,
message: getDispatchError(dispatchError),
status: 'error'
};
} else if (isIncompleteEvent(record)) {
}
const incomplete = getIncompleteMessage(record);
if (incomplete) {
return {
action: `${section}.${method}`,
message: 'imcomplete execution',
message: incomplete,
status: 'eventWarn'
};
} else if (section === 'contracts') {

View File

@ -1,29 +1,46 @@
// Copyright 2017-2022 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Result } from '@polkadot/types';
import type { Event, EventRecord } from '@polkadot/types/interfaces';
import type { DispatchError, DispatchResult, Event, EventRecord } from '@polkadot/types/interfaces';
import type { XcmV2TraitsOutcome } from '@polkadot/types/lookup';
import type { Codec } from '@polkadot/types/types';
type EventCheck = (event: Event) => boolean;
type EventCheck = (event: Event) => string | null;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function acceptAll (_: Event): boolean {
return true;
const INCOMPLETE = 'incomplete execution';
function extractError (result: DispatchResult): string | null {
if (!result) {
return INCOMPLETE;
} else if (result.isErr) {
return `error: ${getDispatchError(result.asErr)}`;
}
return null;
}
function dispatchResult ({ data: [result] }: Event): boolean {
return !result || (result as Result<Codec, Codec>).isErr;
function batchInterrupted ({ data: [index, error] }: Event): string | null {
return `error: ${index.toString()}: ${getDispatchError(error as DispatchError)}`;
}
function dispatchResult ({ data: [result] }: Event): string | null {
return extractError(result as DispatchResult);
}
// [approving, timepoint, multisig, callHash, result]
function dispatchResultMulti ({ data: [,,,, result] }: Event): boolean {
return !result || (result as Result<Codec, Codec>).isErr;
function dispatchResultMulti ({ data: [,,,, result] }: Event): string | null {
return extractError(result as DispatchResult);
}
function xcmAttempted ({ data: [outcome] }: Event): boolean {
return !outcome || (outcome as XcmV2TraitsOutcome).isIncomplete;
function xcmAttempted ({ data: [outcome] }: Event): string | null {
if (!outcome) {
return INCOMPLETE;
} else if ((outcome as XcmV2TraitsOutcome).isIncomplete) {
const [index, error] = (outcome as XcmV2TraitsOutcome).asIncomplete;
return `error: ${index.toString()}: ${error.type}`;
}
return null;
}
const xcmPallet: Record<string, EventCheck> = {
@ -43,13 +60,32 @@ const CHECKS: Record<string, Record<string, EventCheck>> = {
SudoAsDone: dispatchResult
},
utility: {
BatchInterrupted: acceptAll,
BatchInterrupted: batchInterrupted,
DispatchedAs: dispatchResult
},
xcmPallet
};
export function isIncompleteEvent ({ event }: EventRecord): boolean {
export function getDispatchError (dispatchError: DispatchError): string {
let message: string = dispatchError.type;
if (dispatchError.isModule) {
try {
const mod = dispatchError.asModule;
const error = dispatchError.registry.findMetaError(mod);
message = `${error.section}.${error.name}`;
} catch (error) {
// swallow
}
} else if (dispatchError.isToken) {
message = `${dispatchError.type}.${dispatchError.asToken.type}`;
}
return message;
}
export function getIncompleteMessage ({ event }: EventRecord): string | null {
const { method, section } = event;
return (