fix: show h instead of apostrophe in taproot xpub to be consistent with firmware

This commit is contained in:
Peter Sanderson
2024-12-20 01:17:15 +01:00
committed by Peter Sanderson
parent 258803528a
commit 82e7d84f8c
7 changed files with 54 additions and 19 deletions

View File

@@ -85,7 +85,7 @@ describe(resolveDescriptorForTaproot.name, () => {
});
expect(response).toEqual({
checksum: undefined, // code is defensive, it will work but it wont provide checksum
checksum: undefined, // code is defensive, it will work but it won't provide checksum
xpub: "tr([71d98c03/86'/0'/0']xpub6CXYpDGLuWpjqFXRTbo8LMYVsiiRjwWiDY7iwDkq1mk4GDYE7TWmSBCnNmbcVYQK4T56RZRRwhCAG7ucTBHAG2rhWHpXdMQtkZVDeVuv33p/<0;1>/*)",
});
});

View File

@@ -1,32 +1,26 @@
import { MessagesSchema as Messages } from '@trezor/protobuf';
import { convertTaprootXpub } from '@trezor/utils';
import { HDNodeResponse } from '../types/api/getPublicKey';
interface Params {
interface ResolveDescriptorForTaprootParams {
response: HDNodeResponse;
publicKey: Messages.PublicKey;
}
export const resolveDescriptorForTaproot = ({ response, publicKey }: Params) => {
export const resolveDescriptorForTaproot = ({
response,
publicKey,
}: ResolveDescriptorForTaprootParams) => {
if (publicKey.descriptor !== null && publicKey.descriptor !== undefined) {
const [xpub, checksum] = publicKey.descriptor.split('#');
// This is here to keep backwards compatibility, suite and blockbooks are still using `'` over `h`
const openingSquareBracketSplit = xpub.split('[');
if (openingSquareBracketSplit.length === 2) {
const [beforeOpeningBracket, afterOpeningBracket] = openingSquareBracketSplit;
// This is here to keep backwards compatibility, suite and block-books
// are still using `'` over `h`.
const correctedXpub = convertTaprootXpub({ xpub, direction: 'h-to-apostrophe' });
const closingSquareBracketSplit = afterOpeningBracket.split(']');
if (closingSquareBracketSplit.length === 2) {
const [path, afterClosingBracket] = closingSquareBracketSplit;
const correctedPath = path.replace(/h/g, "'"); // .replaceAll()
return {
xpub: `${beforeOpeningBracket}[${correctedPath}]${afterClosingBracket}`,
checksum,
};
}
if (correctedXpub !== null) {
return { xpub: correctedXpub, checksum };
}
}

View File

@@ -3,3 +3,6 @@ export * from './events';
export * from './types';
export { parseConnectSettings } from './data/connectSettings';
// Do NOT add any code exports here. Only TrezorConnect and types shall be exported from
// `@trezor/connect` package.

View File

@@ -1,4 +1,5 @@
import { selectSelectedDevice } from '@suite-common/wallet-core';
import { convertTaprootXpub } from '@trezor/utils';
import { getNetworkDisplaySymbol } from '@suite-common/wallet-config';
import { Translation } from 'src/components/suite';
@@ -27,6 +28,13 @@ export const ConfirmXpubModal = (
? `${account.descriptor}#${account.descriptorChecksum}`
: account.descriptor;
// Suite internally uses apostrophe, but FW uses 'h' for taproot descriptors,
// and we want to show it correctly to the user
const xpubWithReplacedApostropheWithH = convertTaprootXpub({
xpub,
direction: 'apostrophe-to-h',
});
return (
<ConfirmValueModal
account={account}
@@ -47,7 +55,7 @@ export const ConfirmXpubModal = (
confirmStepLabel={<Translation id="TR_XPUB_MATCH" />}
validateOnDevice={showXpub}
copyButtonText={<Translation id="TR_XPUB_MODAL_CLIPBOARD" />}
value={xpub}
value={xpubWithReplacedApostropheWithH ?? xpub}
displayMode={DisplayMode.PAGINATED_TEXT}
{...props}
/>

View File

@@ -0,0 +1,27 @@
// Todo: one day, we shall purify the @trezor/utils and remove domain-specific stuff from it
export type ConvertTaprootXpubParams = {
xpub: string;
direction: 'h-to-apostrophe' | 'apostrophe-to-h';
};
export const convertTaprootXpub = ({ xpub, direction }: ConvertTaprootXpubParams) => {
const find = direction === 'h-to-apostrophe' ? 'h' : "'";
const replace = direction === 'h-to-apostrophe' ? "'" : 'h';
const openingSquareBracketSplit = xpub.split('[');
if (openingSquareBracketSplit.length === 2) {
const [beforeOpeningBracket, afterOpeningBracket] = openingSquareBracketSplit;
const closingSquareBracketSplit = afterOpeningBracket.split(']');
if (closingSquareBracketSplit.length === 2) {
const [path, afterClosingBracket] = closingSquareBracketSplit;
const correctedPath = path.replace(new RegExp(find, 'g'), replace); // .replaceAll()
return `${beforeOpeningBracket}[${correctedPath}]${afterClosingBracket}`;
}
}
return null;
};

View File

@@ -51,3 +51,4 @@ export * from './isFullPath';
export * from './asciiUtils';
export * from './resolveAfter';
export * from './zip';
export * from './convertTaprootXpub';

View File

@@ -1,3 +1,5 @@
// Todo: one day, we shall purify the @trezor/utils and remove domain-specific stuff from it
// URL is in format host:port:[t|s] (t for tcp, s for ssl)
const ELECTRUM_URL_REGEX = /^(?:([a-zA-Z0-9.-]+)|\[([a-f0-9:]+)\]):([0-9]{1,5}):([ts])$/;