Enable "Chain Specific App" setting (#1445)

* Allow for use of chain specific app

* Cleanup ordering of metadata check

* Update ui to 3.9.1

* Add error for when chain is null

* Add setbusy
This commit is contained in:
Tarik Gul 2024-08-13 11:22:17 -07:00 committed by GitHub
parent c5d0fc1b7d
commit 61060c669d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 140 additions and 98 deletions

View File

@ -30,8 +30,8 @@
"@polkadot/phishing": "^0.23.3",
"@polkadot/rpc-provider": "^12.3.1",
"@polkadot/types": "^12.3.1",
"@polkadot/ui-keyring": "^3.8.3",
"@polkadot/ui-settings": "^3.8.3",
"@polkadot/ui-keyring": "^3.9.1",
"@polkadot/ui-settings": "^3.9.1",
"@polkadot/util": "^13.0.2",
"@polkadot/util-crypto": "^13.0.2",
"eventemitter3": "^5.0.1",

View File

@ -32,12 +32,12 @@
"@polkadot/hw-ledger": "^13.0.2",
"@polkadot/keyring": "^13.0.2",
"@polkadot/networks": "^13.0.2",
"@polkadot/react-identicon": "^3.8.3",
"@polkadot/react-qr": "^3.8.3",
"@polkadot/react-identicon": "^3.9.1",
"@polkadot/react-qr": "^3.9.1",
"@polkadot/types": "^12.3.1",
"@polkadot/types-augment": "^12.3.1",
"@polkadot/ui-keyring": "^3.8.3",
"@polkadot/ui-settings": "^3.8.3",
"@polkadot/ui-keyring": "^3.9.1",
"@polkadot/ui-settings": "^3.9.1",
"@polkadot/util": "^13.0.2",
"@polkadot/util-crypto": "^13.0.2",
"file-saver": "^2.0.5",

View File

@ -1,7 +1,11 @@
// Copyright 2019-2024 @polkadot/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
/* eslint-disable deprecation/deprecation */
import type { Chain } from '@polkadot/extension-chains/types';
import type { Ledger, LedgerGeneric } from '@polkadot/hw-ledger';
import type { ExtrinsicPayload } from '@polkadot/types/interfaces';
import type { SignerPayloadJSON } from '@polkadot/types/types';
import type { HexString } from '@polkadot/util/types';
@ -23,8 +27,9 @@ interface Props {
className?: string;
error: string | null;
genesisHash?: string;
onSignature?: ({ signature }: { signature: HexString }, signedTransaction: HexString) => void;
payload?: SignerPayloadJSON;
onSignature?: ({ signature }: { signature: HexString }, signedTransaction?: HexString) => void;
payloadJson?: SignerPayloadJSON;
payloadExt?: ExtrinsicPayload
setError: (value: string | null) => void;
}
@ -50,7 +55,7 @@ function getMetadataProof (chain: Chain, payload: SignerPayloadJSON) {
};
}
function LedgerSign ({ accountIndex, addressOffset, className, error, genesisHash, onSignature, payload, setError }: Props): React.ReactElement<Props> {
function LedgerSign ({ accountIndex, addressOffset, className, error, genesisHash, onSignature, payloadExt, payloadJson, setError }: Props): React.ReactElement<Props> {
const [isBusy, setIsBusy] = useState(false);
const { t } = useTranslation();
const chain = useMetadata(genesisHash);
@ -69,43 +74,61 @@ function LedgerSign ({ accountIndex, addressOffset, className, error, genesisHas
const _onSignLedger = useCallback(
(): void => {
if (!ledger || !payload || !onSignature || !chain) {
if (!ledger || !payloadJson || !onSignature || !chain || !payloadExt) {
if (!chain) {
setError('No chain information found. You may need to update/upload the metadata.');
setIsBusy(false);
}
return;
}
if (!chain?.definition.rawMetadata) {
setError('No metadata found for this chain. You must upload the metadata to the extension in order to use Ledger.');
}
const { raw, txMetadata } = getMetadataProof(chain, payload);
const metaBuff = Buffer.from(txMetadata);
setError(null);
setIsBusy(true);
ledger.signWithMetadata(raw.toU8a(true), accountIndex, addressOffset, { metadata: metaBuff })
.then((signature) => {
const extrinsic = chain.registry.createType(
'Extrinsic',
{ method: raw.method },
{ version: 4 }
);
ledger.getAddress(chain.ss58Format, false, accountIndex, addressOffset)
.then(({ address }) => {
extrinsic.addSignature(address, signature.signature, raw.toHex());
onSignature(signature, extrinsic.toHex());
})
.catch((e: Error) => {
setError(e.message);
setIsBusy(false);
});
}).catch((e: Error) => {
setError(e.message);
setIsBusy(false);
});
const currApp = settings.get().ledgerApp;
if (currApp === 'generic' || currApp === 'migration') {
if (!chain?.definition.rawMetadata) {
setError('No metadata found for this chain. You must upload the metadata to the extension in order to use Ledger.');
}
const { raw, txMetadata } = getMetadataProof(chain, payloadJson);
const metaBuff = Buffer.from(txMetadata);
(ledger as LedgerGeneric).signWithMetadata(raw.toU8a(true), accountIndex, addressOffset, { metadata: metaBuff })
.then((signature) => {
const extrinsic = chain.registry.createType(
'Extrinsic',
{ method: raw.method },
{ version: 4 }
);
(ledger as LedgerGeneric).getAddress(chain.ss58Format, false, accountIndex, addressOffset)
.then(({ address }) => {
extrinsic.addSignature(address, signature.signature, raw.toHex());
onSignature(signature, extrinsic.toHex());
})
.catch((e: Error) => {
setError(e.message);
setIsBusy(false);
});
}).catch((e: Error) => {
setError(e.message);
setIsBusy(false);
});
} else if (currApp === 'chainSpecific') {
(ledger as Ledger).sign(payloadExt.toU8a(true), accountIndex, addressOffset)
.then((signature) => {
onSignature(signature);
}).catch((e: Error) => {
setError(e.message);
setIsBusy(false);
});
}
},
[accountIndex, addressOffset, chain, ledger, onSignature, payload, setError]
[accountIndex, addressOffset, chain, ledger, onSignature, payloadJson, payloadExt, setError]
);
return (

View File

@ -117,7 +117,8 @@ export default function Request ({ account: { accountIndex, addressOffset, genes
error={error}
genesisHash={json.genesisHash}
onSignature={_onSignature}
payload={json}
payloadExt={payload}
payloadJson={json}
setError={setError}
/>
)}

View File

@ -10,7 +10,7 @@ import type { HexString } from '@polkadot/util/types';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { LedgerGeneric } from '@polkadot/hw-ledger';
import { Ledger, LedgerGeneric } from '@polkadot/hw-ledger';
import { knownLedger } from '@polkadot/networks/defaults';
import { settings } from '@polkadot/ui-settings';
import { assert } from '@polkadot/util';
@ -29,7 +29,7 @@ interface State extends StateBase {
error: string | null;
isLoading: boolean;
isLocked: boolean;
ledger: LedgerGeneric | null;
ledger: LedgerGeneric | Ledger | null;
refresh: () => void;
warning: string | null;
}
@ -47,8 +47,8 @@ function getState (): StateBase {
};
}
function retrieveLedger (genesis: string): LedgerGeneric {
let ledger: LedgerGeneric | null = null;
function retrieveLedger (genesis: string): LedgerGeneric | Ledger {
let ledger: LedgerGeneric | Ledger | null = null;
const currApp = settings.get().ledgerApp;
@ -72,6 +72,8 @@ function retrieveLedger (genesis: string): LedgerGeneric {
ledger = new LedgerGeneric('webusb', def.network, knownLedger['polkadot']);
} else if (currApp === 'migration') {
ledger = new LedgerGeneric('webusb', def.network, knownLedger[def.network]);
} else if (currApp === 'chainSpecific') {
ledger = new Ledger('webusb', def.network);
} else {
// This will never get touched since it will always hit the above two. This satisfies the compiler.
ledger = new LedgerGeneric('webusb', def.network, knownLedger['polkadot']);
@ -89,6 +91,28 @@ export default function useLedger (genesis?: string | null, accountIndex = 0, ad
const [address, setAddress] = useState<string | null>(null);
const { t } = useTranslation();
const handleGetAddressError = (e: Error, genesis: string) => {
setIsLoading(false);
const { network } = getNetwork(genesis) || { network: 'unknown network' };
const warningMessage = e.message.includes('Code: 26628')
? t('Is your ledger locked?')
: null;
const errorMessage = e.message.includes('App does not seem to be open')
? t('App "{{network}}" does not seem to be open', { replace: { network } })
: e.message;
setIsLocked(true);
setWarning(warningMessage);
setError(t(
'Ledger error: {{errorMessage}}',
{ replace: { errorMessage } }
));
console.error(e);
setAddress(null);
};
const ledger = useMemo(() => {
setError(null);
setIsLocked(false);
@ -131,31 +155,25 @@ export default function useLedger (genesis?: string | null, accountIndex = 0, ad
// Just in case, but this shouldn't be triggered
assert(chosenNetwork, t('This network is not available, please report an issue to update the known chains'));
ledger.getAddress(chosenNetwork.ss58Format, false, accountIndex, addressOffset)
.then((res) => {
setIsLoading(false);
setAddress(res.address);
}).catch((e: Error) => {
setIsLoading(false);
const { network } = getNetwork(genesis) || { network: 'unknown network' };
const currApp = settings.get().ledgerApp;
const warningMessage = e.message.includes('Code: 26628')
? t('Is your ledger locked?')
: null;
const errorMessage = e.message.includes('App does not seem to be open')
? t('App "{{network}}" does not seem to be open', { replace: { network } })
: e.message;
setIsLocked(true);
setWarning(warningMessage);
setError(t(
'Ledger error: {{errorMessage}}',
{ replace: { errorMessage } }
));
console.error(e);
setAddress(null);
});
if (currApp === 'generic' || currApp === 'migration') {
(ledger as LedgerGeneric).getAddress(chosenNetwork.ss58Format, false, accountIndex, addressOffset)
.then((res) => {
setIsLoading(false);
setAddress(res.address);
}).catch((e: Error) => {
handleGetAddressError(e, genesis);
});
} else if (currApp === 'chainSpecific') {
(ledger as Ledger).getAddress(false, accountIndex, addressOffset)
.then((res) => {
setIsLoading(false);
setAddress(res.address);
}).catch((e: Error) => {
handleGetAddressError(e, genesis);
});
}
// If the dependency array is exhaustive, with t, the translation function, it
// triggers a useless re-render when ledger device is connected.
// eslint-disable-next-line react-hooks/exhaustive-deps

View File

@ -929,8 +929,8 @@ __metadata:
"@polkadot/phishing": "npm:^0.23.3"
"@polkadot/rpc-provider": "npm:^12.3.1"
"@polkadot/types": "npm:^12.3.1"
"@polkadot/ui-keyring": "npm:^3.8.3"
"@polkadot/ui-settings": "npm:^3.8.3"
"@polkadot/ui-keyring": "npm:^3.9.1"
"@polkadot/ui-settings": "npm:^3.9.1"
"@polkadot/util": "npm:^13.0.2"
"@polkadot/util-crypto": "npm:^13.0.2"
eventemitter3: "npm:^5.0.1"
@ -1036,12 +1036,12 @@ __metadata:
"@polkadot/hw-ledger": "npm:^13.0.2"
"@polkadot/keyring": "npm:^13.0.2"
"@polkadot/networks": "npm:^13.0.2"
"@polkadot/react-identicon": "npm:^3.8.3"
"@polkadot/react-qr": "npm:^3.8.3"
"@polkadot/react-identicon": "npm:^3.9.1"
"@polkadot/react-qr": "npm:^3.9.1"
"@polkadot/types": "npm:^12.3.1"
"@polkadot/types-augment": "npm:^12.3.1"
"@polkadot/ui-keyring": "npm:^3.8.3"
"@polkadot/ui-settings": "npm:^3.8.3"
"@polkadot/ui-keyring": "npm:^3.9.1"
"@polkadot/ui-settings": "npm:^3.9.1"
"@polkadot/util": "npm:^13.0.2"
"@polkadot/util-crypto": "npm:^13.0.2"
"@types/enzyme": "npm:^3.10.18"
@ -1165,13 +1165,13 @@ __metadata:
languageName: node
linkType: hard
"@polkadot/react-identicon@npm:^3.8.3":
version: 3.8.3
resolution: "@polkadot/react-identicon@npm:3.8.3"
"@polkadot/react-identicon@npm:^3.9.1":
version: 3.9.1
resolution: "@polkadot/react-identicon@npm:3.9.1"
dependencies:
"@polkadot/keyring": "npm:^13.0.2"
"@polkadot/ui-settings": "npm:3.8.3"
"@polkadot/ui-shared": "npm:3.8.3"
"@polkadot/ui-settings": "npm:3.9.1"
"@polkadot/ui-shared": "npm:3.9.1"
"@polkadot/util": "npm:^13.0.2"
"@polkadot/util-crypto": "npm:^13.0.2"
ethereum-blockies-base64: "npm:^1.0.2"
@ -1186,15 +1186,15 @@ __metadata:
react: "*"
react-dom: "*"
react-is: "*"
checksum: 10/6dddfca42732d141acd2e460d25635845287e0e8bfae6c170f72a691c49b1f34d08e1e975d1a2c2216e1814f1928a29982b806d6bc30f3f08ddddad214b91867
checksum: 10/6a3ad4e129af15e2d6833def626085e392c960211935cf901560f434247560ae6dcfb8d8ecde38b56f317ac3e0d84653ef9c5b68e258c2791467b1339b595bef
languageName: node
linkType: hard
"@polkadot/react-qr@npm:^3.8.3":
version: 3.8.3
resolution: "@polkadot/react-qr@npm:3.8.3"
"@polkadot/react-qr@npm:^3.9.1":
version: 3.9.1
resolution: "@polkadot/react-qr@npm:3.9.1"
dependencies:
"@polkadot/ui-settings": "npm:3.8.3"
"@polkadot/ui-settings": "npm:3.9.1"
"@polkadot/util": "npm:^13.0.2"
"@polkadot/util-crypto": "npm:^13.0.2"
"@zxing/browser": "npm:^0.1.5"
@ -1208,7 +1208,7 @@ __metadata:
react: "*"
react-dom: "*"
react-is: "*"
checksum: 10/1afb77b45a4b6bf0cb110dbf405bfd8a1edbabb9e4639e3b34f0f7f0c1c706799f462b1590e18da8d8de369172f075bdbc9800e7d54e9b48041724203294c600
checksum: 10/f196e19e6d5c11ef7f7824fa67ad41fcde790ad6505113a2e8383c4c79c5c2a8947a619c0513709d9983679ff60af7f8c0811e1a232772fb5438dcbecd442e21
languageName: node
linkType: hard
@ -1337,12 +1337,12 @@ __metadata:
languageName: node
linkType: hard
"@polkadot/ui-keyring@npm:^3.8.3":
version: 3.8.3
resolution: "@polkadot/ui-keyring@npm:3.8.3"
"@polkadot/ui-keyring@npm:^3.9.1":
version: 3.9.1
resolution: "@polkadot/ui-keyring@npm:3.9.1"
dependencies:
"@polkadot/keyring": "npm:^13.0.2"
"@polkadot/ui-settings": "npm:3.8.3"
"@polkadot/ui-settings": "npm:3.9.1"
"@polkadot/util": "npm:^13.0.2"
"@polkadot/util-crypto": "npm:^13.0.2"
mkdirp: "npm:^3.0.1"
@ -1353,13 +1353,13 @@ __metadata:
"@polkadot/keyring": "*"
"@polkadot/ui-settings": "*"
"@polkadot/util": "*"
checksum: 10/d8b3ebf3da39ebbcabe1e0c41c9ed731a14c186c1698c598b4aac6217162c7174453860d06582200b10bc687fc75ec713238ce1687efb4672de989ab728ee99f
checksum: 10/eec438ef2ad9363d77f51d60df9802f1cad3379661883a9412f9ca1af44e31444fc7c04eec1ec7ecf2ae76af1718ffce8e335dcf572d89a6ffc6403bf6c36423
languageName: node
linkType: hard
"@polkadot/ui-settings@npm:3.8.3, @polkadot/ui-settings@npm:^3.8.3":
version: 3.8.3
resolution: "@polkadot/ui-settings@npm:3.8.3"
"@polkadot/ui-settings@npm:3.9.1, @polkadot/ui-settings@npm:^3.9.1":
version: 3.9.1
resolution: "@polkadot/ui-settings@npm:3.9.1"
dependencies:
"@polkadot/networks": "npm:^13.0.2"
"@polkadot/util": "npm:^13.0.2"
@ -1369,20 +1369,20 @@ __metadata:
peerDependencies:
"@polkadot/networks": "*"
"@polkadot/util": "*"
checksum: 10/be6d9f5111ba94b9e86b3348bd0f7e68008611b54fcc159b3a163d7331b345f1552b2d1ba7b6b763387607110e06eecd799b7ad61ee4d5847056b128a85bfdcf
checksum: 10/d3a28af0233f2ee9a8453501de3dd2fabc46bc98cb4c0e46a79654c87a0a41f3148dd6949b796932a4c12fc974b2b924d9eb0e76f91f7ce9ea27e5012e1e606a
languageName: node
linkType: hard
"@polkadot/ui-shared@npm:3.8.3":
version: 3.8.3
resolution: "@polkadot/ui-shared@npm:3.8.3"
"@polkadot/ui-shared@npm:3.9.1":
version: 3.9.1
resolution: "@polkadot/ui-shared@npm:3.9.1"
dependencies:
colord: "npm:^2.9.3"
tslib: "npm:^2.6.2"
peerDependencies:
"@polkadot/util": "*"
"@polkadot/util-crypto": "*"
checksum: 10/a7cbeed7ccbe2f3212d20155787d3a7f4ec2a5662dfb950d965a1ac8ea05fd380f3b9456147cf2e15dc5adbf0df71eedfd94c0707db44a16f1bf2f84c0ebf01c
checksum: 10/80a3a59ca25ed0e572a2eb85533f54f9714c6fd21f85fcf46775fc57c5d55c048049378c94372260df9d860569197ea38dbf3a24cc8ed1e416f67c69408f3789
languageName: node
linkType: hard