diff --git a/packages/connect/src/device/__tests__/resolveDescriptorForTaproot.test.ts b/packages/connect/src/device/__tests__/resolveDescriptorForTaproot.test.ts
index b7e2a936a0..4c3cc60650 100644
--- a/packages/connect/src/device/__tests__/resolveDescriptorForTaproot.test.ts
+++ b/packages/connect/src/device/__tests__/resolveDescriptorForTaproot.test.ts
@@ -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>/*)",
});
});
diff --git a/packages/connect/src/device/resolveDescriptorForTaproot.ts b/packages/connect/src/device/resolveDescriptorForTaproot.ts
index 28bb8ec2e7..67e28dd631 100644
--- a/packages/connect/src/device/resolveDescriptorForTaproot.ts
+++ b/packages/connect/src/device/resolveDescriptorForTaproot.ts
@@ -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 };
}
}
diff --git a/packages/connect/src/exports.ts b/packages/connect/src/exports.ts
index cffd8891f8..4664f6bb43 100644
--- a/packages/connect/src/exports.ts
+++ b/packages/connect/src/exports.ts
@@ -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.
diff --git a/packages/suite/src/components/suite/modals/ReduxModal/ConfirmXpubModal.tsx b/packages/suite/src/components/suite/modals/ReduxModal/ConfirmXpubModal.tsx
index 803c84ea8e..86dfea63d6 100644
--- a/packages/suite/src/components/suite/modals/ReduxModal/ConfirmXpubModal.tsx
+++ b/packages/suite/src/components/suite/modals/ReduxModal/ConfirmXpubModal.tsx
@@ -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 (
}
validateOnDevice={showXpub}
copyButtonText={}
- value={xpub}
+ value={xpubWithReplacedApostropheWithH ?? xpub}
displayMode={DisplayMode.PAGINATED_TEXT}
{...props}
/>
diff --git a/packages/utils/src/convertTaprootXpub.ts b/packages/utils/src/convertTaprootXpub.ts
new file mode 100644
index 0000000000..fd1890d653
--- /dev/null
+++ b/packages/utils/src/convertTaprootXpub.ts
@@ -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;
+};
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index eddf99d124..984ec8ec5a 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -51,3 +51,4 @@ export * from './isFullPath';
export * from './asciiUtils';
export * from './resolveAfter';
export * from './zip';
+export * from './convertTaprootXpub';
diff --git a/packages/utils/src/parseElectrumUrl.ts b/packages/utils/src/parseElectrumUrl.ts
index 9793f273af..d6728849d2 100644
--- a/packages/utils/src/parseElectrumUrl.ts
+++ b/packages/utils/src/parseElectrumUrl.ts
@@ -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])$/;