Tie account to genesis (#355)
* Tie account to genesis * Allow (faster) partial retrieval * Edit toggles menu
This commit is contained in:
parent
d521d5780b
commit
f773342343
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import { MetadataDef } from '@polkadot/extension-inject/types';
|
import { MetadataDef } from '@polkadot/extension-inject/types';
|
||||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||||
import { AccountJson, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountCreateExternal, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountShow, RequestAccountValidate, RequestAuthorizeApprove, RequestAuthorizeReject, RequestDeriveCreate, ResponseDeriveValidate, RequestMetadataApprove, RequestMetadataReject, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSeedCreate, RequestTypes, ResponseAccountExport, RequestAccountForget, ResponseSeedCreate, RequestSeedValidate, RequestDeriveValidate, ResponseSeedValidate, ResponseType, SigningRequest, RequestJsonRestore, ResponseJsonRestore } from '../types';
|
import { AccountJson, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountCreateExternal, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeApprove, RequestAuthorizeReject, RequestDeriveCreate, ResponseDeriveValidate, RequestMetadataApprove, RequestMetadataReject, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSeedCreate, RequestTypes, ResponseAccountExport, RequestAccountForget, ResponseSeedCreate, RequestSeedValidate, RequestDeriveValidate, ResponseSeedValidate, ResponseType, SigningRequest, RequestJsonRestore, ResponseJsonRestore } from '../types';
|
||||||
|
|
||||||
import chrome from '@polkadot/extension-inject/chrome';
|
import chrome from '@polkadot/extension-inject/chrome';
|
||||||
import keyring from '@polkadot/ui-keyring';
|
import keyring from '@polkadot/ui-keyring';
|
||||||
@ -79,6 +79,16 @@ export default class Extension {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private accountsTie ({ address, genesisHash }: RequestAccountTie): boolean {
|
||||||
|
const pair = keyring.getPair(address);
|
||||||
|
|
||||||
|
assert(pair, 'Unable to find pair');
|
||||||
|
|
||||||
|
keyring.saveAccountMeta(pair, { ...pair.meta, genesisHash });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private accountsValidate ({ address, password }: RequestAccountValidate): boolean {
|
private accountsValidate ({ address, password }: RequestAccountValidate): boolean {
|
||||||
try {
|
try {
|
||||||
keyring.backupAccount(keyring.getPair(address), password);
|
keyring.backupAccount(keyring.getPair(address), password);
|
||||||
@ -157,6 +167,10 @@ export default class Extension {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private metadataGet (genesisHash: string | null): MetadataDef | null {
|
||||||
|
return this.#state.knownMetadata.find((result) => result.genesisHash === genesisHash) || null;
|
||||||
|
}
|
||||||
|
|
||||||
private metadataList (): MetadataDef[] {
|
private metadataList (): MetadataDef[] {
|
||||||
return this.#state.knownMetadata;
|
return this.#state.knownMetadata;
|
||||||
}
|
}
|
||||||
@ -394,15 +408,21 @@ export default class Extension {
|
|||||||
case 'pri(accounts.show)':
|
case 'pri(accounts.show)':
|
||||||
return this.accountsShow(request as RequestAccountShow);
|
return this.accountsShow(request as RequestAccountShow);
|
||||||
|
|
||||||
case 'pri(accounts.validate)':
|
|
||||||
return this.accountsValidate(request as RequestAccountValidate);
|
|
||||||
|
|
||||||
case 'pri(accounts.subscribe)':
|
case 'pri(accounts.subscribe)':
|
||||||
return this.accountsSubscribe(id, port);
|
return this.accountsSubscribe(id, port);
|
||||||
|
|
||||||
|
case 'pri(accounts.tie)':
|
||||||
|
return this.accountsTie(request as RequestAccountTie);
|
||||||
|
|
||||||
|
case 'pri(accounts.validate)':
|
||||||
|
return this.accountsValidate(request as RequestAccountValidate);
|
||||||
|
|
||||||
case 'pri(metadata.approve)':
|
case 'pri(metadata.approve)':
|
||||||
return this.metadataApprove(request as RequestMetadataApprove);
|
return this.metadataApprove(request as RequestMetadataApprove);
|
||||||
|
|
||||||
|
case 'pri(metadata.get)':
|
||||||
|
return this.metadataGet(request as string);
|
||||||
|
|
||||||
case 'pri(metadata.list)':
|
case 'pri(metadata.list)':
|
||||||
return this.metadataList();
|
return this.metadataList();
|
||||||
|
|
||||||
|
|||||||
@ -72,6 +72,7 @@ export interface RequestSignatures {
|
|||||||
'pri(accounts.export)': [RequestAccountExport, ResponseAccountExport];
|
'pri(accounts.export)': [RequestAccountExport, ResponseAccountExport];
|
||||||
'pri(accounts.forget)': [RequestAccountForget, boolean];
|
'pri(accounts.forget)': [RequestAccountForget, boolean];
|
||||||
'pri(accounts.show)': [RequestAccountShow, boolean];
|
'pri(accounts.show)': [RequestAccountShow, boolean];
|
||||||
|
'pri(accounts.tie)': [RequestAccountTie, boolean];
|
||||||
'pri(accounts.subscribe)': [RequestAccountSubscribe, boolean, AccountJson[]];
|
'pri(accounts.subscribe)': [RequestAccountSubscribe, boolean, AccountJson[]];
|
||||||
'pri(accounts.validate)': [RequestAccountValidate, boolean];
|
'pri(accounts.validate)': [RequestAccountValidate, boolean];
|
||||||
'pri(authorize.approve)': [RequestAuthorizeApprove, boolean];
|
'pri(authorize.approve)': [RequestAuthorizeApprove, boolean];
|
||||||
@ -83,6 +84,7 @@ export interface RequestSignatures {
|
|||||||
'pri(json.verify.file)': [RequestJsonRestore, boolean];
|
'pri(json.verify.file)': [RequestJsonRestore, boolean];
|
||||||
'pri(json.verify.password)': [string, boolean];
|
'pri(json.verify.password)': [string, boolean];
|
||||||
'pri(metadata.approve)': [RequestMetadataApprove, boolean];
|
'pri(metadata.approve)': [RequestMetadataApprove, boolean];
|
||||||
|
'pri(metadata.get)': [string | null, MetadataDef | null];
|
||||||
'pri(metadata.reject)': [RequestMetadataReject, boolean];
|
'pri(metadata.reject)': [RequestMetadataReject, boolean];
|
||||||
'pri(metadata.requests)': [RequestMetadataSubscribe, boolean, MetadataRequest[]];
|
'pri(metadata.requests)': [RequestMetadataSubscribe, boolean, MetadataRequest[]];
|
||||||
'pri(metadata.list)': [null, MetadataDef[]];
|
'pri(metadata.list)': [null, MetadataDef[]];
|
||||||
@ -180,6 +182,11 @@ export interface RequestAccountShow {
|
|||||||
isShowing: boolean;
|
isShowing: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RequestAccountTie {
|
||||||
|
address: string;
|
||||||
|
genesisHash: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RequestAccountValidate {
|
export interface RequestAccountValidate {
|
||||||
address: string;
|
address: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
|||||||
29
packages/extension-chains/src/genesisHashes.ts
Normal file
29
packages/extension-chains/src/genesisHashes.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2019-2020 @polkadot/extension-chains authors & contributors
|
||||||
|
// This software may be modified and distributed under the terms
|
||||||
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
interface Option {
|
||||||
|
text: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashes: Option[] = [
|
||||||
|
{
|
||||||
|
text: 'Allow use on any chain',
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Polkadot CC1 (live)',
|
||||||
|
value: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Kusama (canary)',
|
||||||
|
value: '0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Edgeware (live)',
|
||||||
|
value: '0x742a2ca70c2fda6cee4f8df98d64c4c670a052d9568058982dad9d5a7a135c5b'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default hashes;
|
||||||
@ -11,20 +11,27 @@ import { Metadata, TypeRegistry } from '@polkadot/types';
|
|||||||
// inside the api, run `yarn chain:info --ws <url>`
|
// inside the api, run `yarn chain:info --ws <url>`
|
||||||
import kusama from './kusama';
|
import kusama from './kusama';
|
||||||
|
|
||||||
const definitions: Map<string, MetadataDef> = new Map(
|
const definitions = new Map<string, MetadataDef>(
|
||||||
[kusama].map((def) => [def.genesisHash, def])
|
[kusama].map((def) => [def.genesisHash, def])
|
||||||
);
|
);
|
||||||
|
|
||||||
function metadataExpand (definition: MetadataDef): Chain {
|
const expanded = new Map<string, Chain>();
|
||||||
|
|
||||||
|
export function metadataExpand (definition: MetadataDef, isPartial = false): Chain {
|
||||||
|
const cached = expanded.get(definition.genesisHash);
|
||||||
|
|
||||||
|
if (cached && cached.specVersion === definition.specVersion) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
const { chain, genesisHash, icon, metaCalls, specVersion, ss58Format, tokenDecimals, tokenSymbol, types } = definition;
|
const { chain, genesisHash, icon, metaCalls, specVersion, ss58Format, tokenDecimals, tokenSymbol, types } = definition;
|
||||||
const registry = new TypeRegistry();
|
const registry = new TypeRegistry();
|
||||||
|
|
||||||
registry.register(types);
|
if (!isPartial) {
|
||||||
|
registry.register(types);
|
||||||
|
}
|
||||||
|
|
||||||
const isUnknown = genesisHash === '0x';
|
const isUnknown = genesisHash === '0x';
|
||||||
const metadata = metaCalls
|
|
||||||
? new Metadata(registry, Buffer.from(metaCalls, 'base64'))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
registry.setChainProperties(registry.createType('ChainProperties', {
|
registry.setChainProperties(registry.createType('ChainProperties', {
|
||||||
ss58Format,
|
ss58Format,
|
||||||
@ -32,7 +39,11 @@ function metadataExpand (definition: MetadataDef): Chain {
|
|||||||
tokenSymbol
|
tokenSymbol
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return {
|
const metadata = metaCalls && !isPartial
|
||||||
|
? new Metadata(registry, Buffer.from(metaCalls, 'base64'))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const result = {
|
||||||
definition,
|
definition,
|
||||||
genesisHash: isUnknown
|
genesisHash: isUnknown
|
||||||
? undefined
|
? undefined
|
||||||
@ -47,6 +58,12 @@ function metadataExpand (definition: MetadataDef): Chain {
|
|||||||
tokenDecimals,
|
tokenDecimals,
|
||||||
tokenSymbol
|
tokenSymbol
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (result.genesisHash && !isPartial) {
|
||||||
|
expanded.set(result.genesisHash, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findChain (definitions: MetadataDef[], genesisHash?: string | null): Chain | null {
|
export function findChain (definitions: MetadataDef[], genesisHash?: string | null): Chain | null {
|
||||||
|
|||||||
@ -7,9 +7,10 @@ import { ThemeProps } from '../../types';
|
|||||||
|
|
||||||
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import genesisOptions from '@polkadot/extension-chains/genesisHashes';
|
||||||
|
|
||||||
import { ActionContext, Address, Checkbox, Link } from '../../components';
|
import { ActionContext, Address, Checkbox, Dropdown, Link } from '../../components';
|
||||||
import { editAccount, showAccount } from '../../messaging';
|
import { editAccount, showAccount, tieAccount } from '../../messaging';
|
||||||
import { Name } from '../../partials';
|
import { Name } from '../../partials';
|
||||||
|
|
||||||
interface Props extends AccountJson {
|
interface Props extends AccountJson {
|
||||||
@ -17,13 +18,26 @@ interface Props extends AccountJson {
|
|||||||
parentName?: string;
|
parentName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Account ({ address, className, isExternal, isHidden, parentName, suri }: Props): React.ReactElement<Props> {
|
interface EditState {
|
||||||
|
isEditing: boolean;
|
||||||
|
toggleActions: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Account ({ address, className, genesisHash, isExternal, isHidden, parentName, suri }: Props): React.ReactElement<Props> {
|
||||||
const onAction = useContext(ActionContext);
|
const onAction = useContext(ActionContext);
|
||||||
const [isEditing, setEditing] = useState(false);
|
const [{ isEditing, toggleActions }, setEditing] = useState<EditState>({ isEditing: false, toggleActions: 0 });
|
||||||
const [editedName, setName] = useState<string | null>(null);
|
const [editedName, setName] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const _onChangeGenesis = useCallback(
|
||||||
|
(genesisHash?: string | null): void => {
|
||||||
|
tieAccount(address, genesisHash || null)
|
||||||
|
.catch(console.error);
|
||||||
|
},
|
||||||
|
[address]
|
||||||
|
);
|
||||||
|
|
||||||
const _toggleEdit = useCallback(
|
const _toggleEdit = useCallback(
|
||||||
(): void => setEditing(!isEditing),
|
(): void => setEditing(({ toggleActions }) => ({ isEditing: !isEditing, toggleActions: ++toggleActions })),
|
||||||
[isEditing]
|
[isEditing]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -39,6 +53,7 @@ function Account ({ address, className, isExternal, isHidden, parentName, suri }
|
|||||||
},
|
},
|
||||||
[editedName, address, _toggleEdit, onAction]
|
[editedName, address, _toggleEdit, onAction]
|
||||||
);
|
);
|
||||||
|
|
||||||
const _toggleVisibility = useCallback(
|
const _toggleVisibility = useCallback(
|
||||||
(): void => {
|
(): void => {
|
||||||
showAccount(address, isHidden || false)
|
showAccount(address, isHidden || false)
|
||||||
@ -87,8 +102,15 @@ function Account ({ address, className, isExternal, isHidden, parentName, suri }
|
|||||||
label='Visible (always inject)'
|
label='Visible (always inject)'
|
||||||
onClick={_toggleVisibility}
|
onClick={_toggleVisibility}
|
||||||
/>
|
/>
|
||||||
|
<Dropdown
|
||||||
|
className='menuItem'
|
||||||
|
label=''
|
||||||
|
onChange={_onChangeGenesis}
|
||||||
|
options={genesisOptions}
|
||||||
|
value={genesisHash || ''}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
), [_toggleEdit, _toggleVisibility, address, isExternal, isHidden]);
|
), [_onChangeGenesis, _toggleEdit, _toggleVisibility, address, genesisHash, isExternal, isHidden]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
@ -96,9 +118,11 @@ function Account ({ address, className, isExternal, isHidden, parentName, suri }
|
|||||||
actions={_actions}
|
actions={_actions}
|
||||||
address={address}
|
address={address}
|
||||||
className='address'
|
className='address'
|
||||||
|
genesisHash={genesisHash}
|
||||||
name={editedName}
|
name={editedName}
|
||||||
parentName={parentName}
|
parentName={parentName}
|
||||||
suri={suri}
|
suri={suri}
|
||||||
|
toggleActions={toggleActions}
|
||||||
>
|
>
|
||||||
{isEditing && (
|
{isEditing && (
|
||||||
<Name
|
<Name
|
||||||
@ -141,6 +165,7 @@ export default styled(Account)(({ theme }: ThemeProps) => `
|
|||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
min-width: 13rem;
|
||||||
padding: 4px 16px;
|
padding: 4px 16px;
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|||||||
@ -33,6 +33,7 @@ interface Props {
|
|||||||
actions?: React.ReactNode;
|
actions?: React.ReactNode;
|
||||||
parentName?: string | null;
|
parentName?: string | null;
|
||||||
suri?: string;
|
suri?: string;
|
||||||
|
toggleActions?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Recoded {
|
interface Recoded {
|
||||||
@ -67,12 +68,12 @@ function recodeAddress (address: string, accounts: AccountWithChildren[], chain:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ACCOUNTS_SCREEN_HEIGHT = 500;
|
const ACCOUNTS_SCREEN_HEIGHT = 550;
|
||||||
|
|
||||||
function Address ({ actions, address, children, className, genesisHash, name, parentName, suri }: Props): React.ReactElement<Props> {
|
function Address ({ actions, address, children, className, genesisHash, name, parentName, suri, toggleActions }: Props): React.ReactElement<Props> {
|
||||||
const { accounts } = useContext(AccountContext);
|
const { accounts } = useContext(AccountContext);
|
||||||
const settings = useContext(SettingsContext);
|
const settings = useContext(SettingsContext);
|
||||||
const chain = useMetadata(genesisHash);
|
const chain = useMetadata(genesisHash, true);
|
||||||
const [{ account, formatted, prefix }, setRecoded] = useState<Recoded>({ account: null, formatted: null, prefix: 42 });
|
const [{ account, formatted, prefix }, setRecoded] = useState<Recoded>({ account: null, formatted: null, prefix: 42 });
|
||||||
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
||||||
const [moveMenuUp, setIsMovedMenu] = useState(false);
|
const [moveMenuUp, setIsMovedMenu] = useState(false);
|
||||||
@ -99,6 +100,10 @@ function Address ({ actions, address, children, className, genesisHash, name, pa
|
|||||||
}
|
}
|
||||||
}, [showActionsMenu]);
|
}, [showActionsMenu]);
|
||||||
|
|
||||||
|
useEffect((): void => {
|
||||||
|
setShowActionsMenu(false);
|
||||||
|
}, [toggleActions]);
|
||||||
|
|
||||||
const theme = ((chain && chain.icon) || 'polkadot') as 'polkadot';
|
const theme = ((chain && chain.icon) || 'polkadot') as 'polkadot';
|
||||||
const _onClick = useCallback((): void => setShowActionsMenu(!showActionsMenu), [showActionsMenu]);
|
const _onClick = useCallback((): void => setShowActionsMenu(!showActionsMenu), [showActionsMenu]);
|
||||||
const _onCopy = useCallback((): void => show('Copied'), [show]);
|
const _onCopy = useCallback((): void => show('Copied'), [show]);
|
||||||
@ -125,7 +130,7 @@ function Address ({ actions, address, children, className, genesisHash, name, pa
|
|||||||
className='parentName'
|
className='parentName'
|
||||||
data-field='parent'
|
data-field='parent'
|
||||||
>
|
>
|
||||||
{parentName}{suri || ''}
|
{parentName} {suri || ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='name displaced'>{displayedName}</div>
|
<div className='name displaced'>{displayedName}</div>
|
||||||
@ -182,18 +187,18 @@ function Address ({ actions, address, children, className, genesisHash, name, pa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FullAddress = styled.div`
|
const FullAddress = styled.div(({ theme }: ThemeProps) => `
|
||||||
width: 270px;
|
width: 270px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
color: ${({ theme }: ThemeProps): string => theme.labelColor};
|
color: ${theme.labelColor};
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
`;
|
`);
|
||||||
|
|
||||||
FullAddress.displayName = 'FullAddress';
|
FullAddress.displayName = 'FullAddress';
|
||||||
|
|
||||||
const Settings = styled.div`
|
const Settings = styled.div(({ theme }: ThemeProps) => `
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -213,14 +218,14 @@ const Settings = styled.div`
|
|||||||
top: 25%;
|
top: 25%;
|
||||||
bottom: 25%;
|
bottom: 25%;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
background: ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
background: ${theme.boxBorderColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: ${({ theme }: ThemeProps): string => theme.readonlyInputBackground};
|
background: ${theme.readonlyInputBackground};
|
||||||
}
|
}
|
||||||
`;
|
`);
|
||||||
|
|
||||||
Settings.displayName = 'Details';
|
Settings.displayName = 'Details';
|
||||||
|
|
||||||
|
|||||||
@ -8,14 +8,18 @@ import { useEffect, useState } from 'react';
|
|||||||
|
|
||||||
import { getMetadata } from '../messaging';
|
import { getMetadata } from '../messaging';
|
||||||
|
|
||||||
export default function useMetadata (genesisHash?: string | null): Chain | null {
|
export default function useMetadata (genesisHash?: string | null, isPartial?: boolean): Chain | null {
|
||||||
const [chain, setChain] = useState<Chain | null>(null);
|
const [chain, setChain] = useState<Chain | null>(null);
|
||||||
|
|
||||||
useEffect((): void => {
|
useEffect((): void => {
|
||||||
getMetadata(genesisHash)
|
if (genesisHash) {
|
||||||
.then(setChain)
|
getMetadata(genesisHash, isPartial)
|
||||||
.catch(console.error);
|
.then(setChain)
|
||||||
}, [genesisHash]);
|
.catch(console.error);
|
||||||
|
} else {
|
||||||
|
setChain(null);
|
||||||
|
}
|
||||||
|
}, [genesisHash, isPartial]);
|
||||||
|
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,12 @@
|
|||||||
import { Message } from '@polkadot/extension-base/types';
|
import { Message } from '@polkadot/extension-base/types';
|
||||||
import { AccountJson, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MetadataRequest, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions, ResponseDeriveValidate, ResponseJsonRestore } from '@polkadot/extension-base/background/types';
|
import { AccountJson, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MetadataRequest, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions, ResponseDeriveValidate, ResponseJsonRestore } from '@polkadot/extension-base/background/types';
|
||||||
import { Chain } from '@polkadot/extension-chains/types';
|
import { Chain } from '@polkadot/extension-chains/types';
|
||||||
|
import { MetadataDef } from '@polkadot/extension-inject/types';
|
||||||
import { KeypairType } from '@polkadot/util-crypto/types';
|
import { KeypairType } from '@polkadot/util-crypto/types';
|
||||||
|
|
||||||
import { PORT_EXTENSION } from '@polkadot/extension-base/defaults';
|
import { PORT_EXTENSION } from '@polkadot/extension-base/defaults';
|
||||||
import chrome from '@polkadot/extension-inject/chrome';
|
import chrome from '@polkadot/extension-inject/chrome';
|
||||||
import { findChain } from '@polkadot/extension-chains';
|
import { metadataExpand } from '@polkadot/extension-chains';
|
||||||
import { KeyringPair$Json } from '@polkadot/keyring/types';
|
import { KeyringPair$Json } from '@polkadot/keyring/types';
|
||||||
|
|
||||||
interface Handler {
|
interface Handler {
|
||||||
@ -22,6 +23,7 @@ interface Handler {
|
|||||||
|
|
||||||
type Handlers = Record<string, Handler>;
|
type Handlers = Record<string, Handler>;
|
||||||
|
|
||||||
|
const metadataGets = new Map<string, Promise<MetadataDef | null>>();
|
||||||
const port = chrome.runtime.connect({ name: PORT_EXTENSION });
|
const port = chrome.runtime.connect({ name: PORT_EXTENSION });
|
||||||
const handlers: Handlers = {};
|
const handlers: Handlers = {};
|
||||||
let idCounter = 0;
|
let idCounter = 0;
|
||||||
@ -71,6 +73,10 @@ export async function showAccount (address: string, isShowing: boolean): Promise
|
|||||||
return sendMessage('pri(accounts.show)', { address, isShowing });
|
return sendMessage('pri(accounts.show)', { address, isShowing });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function tieAccount (address: string, genesisHash: string | null): Promise<boolean> {
|
||||||
|
return sendMessage('pri(accounts.tie)', { address, genesisHash });
|
||||||
|
}
|
||||||
|
|
||||||
export async function exportAccount (address: string, password: string): Promise<{ exportedJson: string }> {
|
export async function exportAccount (address: string, password: string): Promise<{ exportedJson: string }> {
|
||||||
return sendMessage('pri(accounts.export)', { address, password });
|
return sendMessage('pri(accounts.export)', { address, password });
|
||||||
}
|
}
|
||||||
@ -115,10 +121,23 @@ export async function createSeed (length?: SeedLengths, type?: KeypairType): Pro
|
|||||||
return sendMessage('pri(seed.create)', { length, type });
|
return sendMessage('pri(seed.create)', { length, type });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMetadata (genesisHash?: string | null): Promise<Chain | null> {
|
export async function getMetadata (genesisHash?: string | null, isPartial = false): Promise<Chain | null> {
|
||||||
const definitions = await sendMessage('pri(metadata.list)');
|
if (!genesisHash) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return findChain(definitions || [], genesisHash);
|
let request = metadataGets.get(genesisHash);
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
request = sendMessage('pri(metadata.get)', genesisHash || null);
|
||||||
|
metadataGets.set(genesisHash, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
const def = await request;
|
||||||
|
|
||||||
|
return def
|
||||||
|
? metadataExpand(def, isPartial)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function rejectAuthRequest (id: string): Promise<boolean> {
|
export async function rejectAuthRequest (id: string): Promise<boolean> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user