diff --git a/packages/extension-chains/src/index.ts b/packages/extension-chains/src/index.ts index 1e569215..7c874458 100644 --- a/packages/extension-chains/src/index.ts +++ b/packages/extension-chains/src/index.ts @@ -31,12 +31,15 @@ const chains: Map = new Map( ); const UNKNOWN_CHAIN: Chain = { - name: 'Any', + isUnknown: true, + name: 'Unknown chain', specVersion: 0, ss58Format: 42, tokenDecimals: 0, tokenSymbol: 'UNIT', - types: {} + types: { + Keys: 'SessionKeysSubstrate' + } }; export default function findChain (genesisHash?: string | null): Chain { diff --git a/packages/extension-chains/src/types.ts b/packages/extension-chains/src/types.ts index 96be1a0c..35b7f75b 100644 --- a/packages/extension-chains/src/types.ts +++ b/packages/extension-chains/src/types.ts @@ -5,9 +5,10 @@ import { Metadata } from '@polkadot/types'; export interface Chain { - name: string; + isUnknown?: boolean; genesisHash?: string; meta?: Metadata; + name: string; specVersion: number; ss58Format: number; tokenDecimals: number; diff --git a/packages/extension-ui/src/Popup/Signing/Details.tsx b/packages/extension-ui/src/Popup/Signing/Details.tsx index 154fd609..52eb7e29 100644 --- a/packages/extension-ui/src/Popup/Signing/Details.tsx +++ b/packages/extension-ui/src/Popup/Signing/Details.tsx @@ -3,19 +3,24 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { Chain } from '@polkadot/extension-chains/types'; -import { BlockNumber, ExtrinsicEra, ExtrinsicPayload } from '@polkadot/types/interfaces'; +import { ExtrinsicEra, ExtrinsicPayload } from '@polkadot/types/interfaces'; import { SignerPayloadJSON } from '@polkadot/types/types'; -import React from 'react'; +import BN from 'bn.js'; +import React, { useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import fromMetadata from '@polkadot/api-metadata/extrinsics/fromMetadata'; import findChain from '@polkadot/extension-chains'; -import { createType, GenericCall, getTypeRegistry } from '@polkadot/types'; -import { formatNumber } from '@polkadot/util'; +import { GenericCall, getTypeRegistry } from '@polkadot/types'; +import { formatNumber, bnToBn } from '@polkadot/util'; + +interface Decoded { + json: MethodJson | null; + method: GenericCall | null; +} interface MethodJson { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - args: Record; + args: Record; } interface Props { @@ -26,29 +31,34 @@ interface Props { url: string; } -function renderMethod (data: string, isDecoded: boolean, chain?: Chain): React.ReactNode { - const base = ( - - method data - {data} - - ); - - if (!isDecoded || !chain || !chain.meta) { - return base; - } - - let json: MethodJson; - let method: GenericCall; +function decodeMethod (data: string, isDecoded: boolean, chain: Chain, specVersion: BN): Decoded { + let json: MethodJson | null = null; + let method: GenericCall | null = null; try { - getTypeRegistry().register(chain.types); - GenericCall.injectMethods(fromMetadata(chain.meta)); + if (isDecoded && chain.meta && specVersion.eqn(chain.specVersion)) { + getTypeRegistry().register(chain.types); + GenericCall.injectMethods(fromMetadata(chain.meta)); - method = new GenericCall(data); - json = method.toJSON() as unknown as MethodJson; + method = new GenericCall(data); + json = method.toJSON() as unknown as MethodJson; + } } catch (error) { - return base; + json = null; + method = null; + } + + return { json, method }; +} + +function renderMethod (data: string, { json, method }: Decoded): React.ReactNode { + if (!json || !method) { + return ( + + method data + {data} + + ); } return ( @@ -75,21 +85,25 @@ function renderMethod (data: string, isDecoded: boolean, chain?: Chain): React.R ); } -function renderMortality (era: ExtrinsicEra, blockNumber: BlockNumber): string { +function mortalityAsString (era: ExtrinsicEra, hexBlockNumber: string): string { if (era.isImmortalEra) { return 'immortal'; } + const blockNumber = bnToBn(hexBlockNumber); const mortal = era.asMortalEra; return `mortal, valid from #${formatNumber(mortal.birth(blockNumber))} to #${formatNumber(mortal.death(blockNumber))}`; } -function Details ({ className, isDecoded, payload, request, url }: Props): React.ReactElement { - const blockNumber = createType('BlockNumber', request.blockNumber); - const { genesisHash, method } = request; - const { era, nonce, tip } = payload; - const chain = findChain(genesisHash); +function Details ({ className, isDecoded, payload: { era, nonce, tip }, request: { blockNumber, genesisHash, method, specVersion: hexSpec }, url }: Props): React.ReactElement { + const chain = useRef(findChain(genesisHash)).current; + const specVersion = useRef(bnToBn(hexSpec)).current; + const [decoded, setDecoded] = useState({ json: null, method: null }); + + useEffect((): void => { + setDecoded(decodeMethod(method, isDecoded, chain, specVersion)); + }, [isDecoded]); return ( @@ -99,8 +113,12 @@ function Details ({ className, isDecoded, payload, request, url }: Props): React - - + + + + + + @@ -112,10 +130,10 @@ function Details ({ className, isDecoded, payload, request, url }: Props): React )} - {renderMethod(method, isDecoded, chain)} + {renderMethod(method, decoded)} - +
{url}
{chain ? 'chain' : 'genesis'}{chain ? chain.name : genesisHash}{chain.isUnknown ? 'genesis' : 'chain'}{chain.isUnknown ? genesisHash : chain.name}
version{specVersion.toNumber()}
nonce{formatNumber(tip)}
lifetime{renderMortality(era, blockNumber)}{mortalityAsString(era, blockNumber)}
diff --git a/packages/extension-ui/src/Popup/Signing/Request.tsx b/packages/extension-ui/src/Popup/Signing/Request.tsx index 282e4982..0f1da473 100644 --- a/packages/extension-ui/src/Popup/Signing/Request.tsx +++ b/packages/extension-ui/src/Popup/Signing/Request.tsx @@ -48,7 +48,10 @@ export default function Request ({ account: { isExternal }, isFirst, request, si .catch((error: Error) => console.error(error)); return ( -
+
{isExternal && isFirst ?