diff --git a/packages/page-nfts/src/useCollectionInfos.ts b/packages/page-nfts/src/useCollectionInfos.ts index 65e052cabf..6f101e85fd 100644 --- a/packages/page-nfts/src/useCollectionInfos.ts +++ b/packages/page-nfts/src/useCollectionInfos.ts @@ -90,13 +90,12 @@ function useCollectionInfosImpl (ids?: BN[]): CollectionInfo[] | undefined { const details = useCall<[[BN[]], Option[]]>(api.query.uniques.class.multi, [ids], QUERY_OPTS); const [state, setState] = useState(); - 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(ipfsHashes, IPFS_FETCH_OPTIONS); diff --git a/packages/react-components/src/Status/Queue.tsx b/packages/react-components/src/Status/Queue.tsx index 567f4f3072..571f69e6cf 100644 --- a/packages/react-components/src/Status/Queue.tsx +++ b/packages/react-components/src/Status/Queue.tsx @@ -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') { diff --git a/packages/react-components/src/Status/checks.ts b/packages/react-components/src/Status/checks.ts index 7c920cd6ef..65a3354be7 100644 --- a/packages/react-components/src/Status/checks.ts +++ b/packages/react-components/src/Status/checks.ts @@ -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).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).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 = { @@ -43,13 +60,32 @@ const CHECKS: Record> = { 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 (