@metamask-previews/eth-qr-keyring 1.0.0-e4f6caa → 1.1.0-9fbf2ff

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/dist/device.cjs +345 -0
  3. package/dist/device.cjs.map +1 -0
  4. package/dist/device.d.cts +175 -0
  5. package/dist/device.d.cts.map +1 -0
  6. package/dist/device.d.mts +175 -0
  7. package/dist/device.d.mts.map +1 -0
  8. package/dist/device.mjs +345 -0
  9. package/dist/device.mjs.map +1 -0
  10. package/dist/index.cjs +9 -16
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +3 -2
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.mts +3 -2
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +3 -2
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/qr-keyring-deferred-promise-bridge.cjs +76 -0
  19. package/dist/qr-keyring-deferred-promise-bridge.cjs.map +1 -0
  20. package/dist/qr-keyring-deferred-promise-bridge.d.cts +46 -0
  21. package/dist/qr-keyring-deferred-promise-bridge.d.cts.map +1 -0
  22. package/dist/qr-keyring-deferred-promise-bridge.d.mts +46 -0
  23. package/dist/qr-keyring-deferred-promise-bridge.d.mts.map +1 -0
  24. package/dist/qr-keyring-deferred-promise-bridge.mjs +72 -0
  25. package/dist/qr-keyring-deferred-promise-bridge.mjs.map +1 -0
  26. package/dist/qr-keyring-scanner-bridge.cjs +2 -2
  27. package/dist/qr-keyring-scanner-bridge.cjs.map +1 -1
  28. package/dist/qr-keyring-scanner-bridge.d.cts +3 -3
  29. package/dist/qr-keyring-scanner-bridge.d.mts +3 -3
  30. package/dist/qr-keyring-scanner-bridge.mjs +2 -2
  31. package/dist/qr-keyring-scanner-bridge.mjs.map +1 -1
  32. package/dist/qr-keyring.cjs +65 -137
  33. package/dist/qr-keyring.cjs.map +1 -1
  34. package/dist/qr-keyring.d.cts +17 -4
  35. package/dist/qr-keyring.d.cts.map +1 -1
  36. package/dist/qr-keyring.d.mts +17 -4
  37. package/dist/qr-keyring.d.mts.map +1 -1
  38. package/dist/qr-keyring.mjs +66 -138
  39. package/dist/qr-keyring.mjs.map +1 -1
  40. package/package.json +6 -5
  41. package/dist/airgapped-signer.cjs +0 -270
  42. package/dist/airgapped-signer.cjs.map +0 -1
  43. package/dist/airgapped-signer.d.cts +0 -140
  44. package/dist/airgapped-signer.d.cts.map +0 -1
  45. package/dist/airgapped-signer.d.mts +0 -140
  46. package/dist/airgapped-signer.d.mts.map +0 -1
  47. package/dist/airgapped-signer.mjs +0 -270
  48. package/dist/airgapped-signer.mjs.map +0 -1
@@ -1,270 +0,0 @@
1
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
- };
6
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
- if (kind === "m") throw new TypeError("Private method is not writable");
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
- };
12
- var _AirgappedSigner_instances, _AirgappedSigner_source, _AirgappedSigner_initFromUR, _AirgappedSigner_decodeUR;
13
- function $importDefault(module) {
14
- if (module?.__esModule) {
15
- return module.default;
16
- }
17
- return module;
18
- }
19
- import { publicToAddress } from "@ethereumjs/util";
20
- import { CryptoAccount, CryptoHDKey, URRegistryDecoder } from "@keystonehq/bc-ur-registry-eth";
21
- import { add0x, getChecksumAddress } from "@metamask/utils";
22
- // eslint-disable-next-line @typescript-eslint/naming-convention
23
- import $HdKey from "hdkey";
24
- const HdKey = $importDefault($HdKey);
25
- export const SUPPORTED_UR_TYPE = {
26
- CRYPTO_HDKEY: 'crypto-hdkey',
27
- CRYPTO_ACCOUNT: 'crypto-account',
28
- ETH_SIGNATURE: 'eth-signature',
29
- };
30
- export var KeyringMode;
31
- (function (KeyringMode) {
32
- KeyringMode["HD"] = "hd";
33
- KeyringMode["ACCOUNT"] = "account";
34
- })(KeyringMode || (KeyringMode = {}));
35
- const DEFAULT_CHILDREN_PATH = '0/*';
36
- const MAX_INDEX = 1000;
37
- /**
38
- * Get the fingerprint of the source CryptoAccount or CryptoHDKey
39
- *
40
- * @param source - The source CryptoAccount or CryptoHDKey
41
- * @returns The fingerprint of the source
42
- */
43
- function getFingerprintFromSource(source) {
44
- return source instanceof CryptoAccount
45
- ? source.getMasterFingerprint()?.toString('hex')
46
- : source.getParentFingerprint()?.toString('hex');
47
- }
48
- /**
49
- * Get fingerprint, account paths and names from the a CryptoAccount
50
- *
51
- * Note: This function emulates the behavior of the `@keystonehq/base-eth-keyring`
52
- * library when dealing with CryptoAccount objects (for backwards compatibility
53
- * reasons). Though, the way it retrieves `name` and `keyringAccount` is questionable,
54
- * as `name` and `keyringAccount` are updated after each descriptor discovery, effectively
55
- * returning the last descriptor's `name` and `keyringAccount`.
56
- *
57
- * @param source - The source CryptoAccount
58
- * @returns The paths
59
- */
60
- function readCryptoAccountOutputDescriptors(source) {
61
- const descriptors = source.getOutputDescriptors();
62
- if (!descriptors || descriptors.length === 0) {
63
- throw new Error('No output descriptors found in CryptoAccount');
64
- }
65
- let name = '';
66
- let keyringAccount = '';
67
- const paths = descriptors.reduce((descriptorsPaths, current) => {
68
- const hdKey = current.getHDKey();
69
- if (hdKey) {
70
- const path = `M/${hdKey.getOrigin().getPath()}`;
71
- const address = getChecksumAddress(add0x(Buffer.from(publicToAddress(hdKey.getKey(), true)).toString('hex')));
72
- descriptorsPaths[address] = path;
73
- name = hdKey.getName();
74
- keyringAccount = hdKey.getNote();
75
- }
76
- return descriptorsPaths;
77
- }, {});
78
- return {
79
- paths,
80
- name,
81
- keyringAccount,
82
- xfp: getFingerprintFromSource(source),
83
- };
84
- }
85
- export class AirgappedSigner {
86
- constructor() {
87
- _AirgappedSigner_instances.add(this);
88
- _AirgappedSigner_source.set(this, void 0);
89
- }
90
- /**
91
- * Initialize the AirgappedSigner with a source.
92
- *
93
- * @param source - The signer source, in the form of details object, or a UR string
94
- */
95
- init(source) {
96
- if (typeof source === 'string' || 'cbor' in source) {
97
- __classPrivateFieldGet(this, _AirgappedSigner_instances, "m", _AirgappedSigner_initFromUR).call(this, source);
98
- }
99
- else {
100
- __classPrivateFieldSet(this, _AirgappedSigner_source, source, "f");
101
- }
102
- }
103
- /**
104
- * Check if the AirgappedSigner is initialized
105
- *
106
- * @returns True if the AirgappedSigner is initialized, false otherwise
107
- */
108
- isInitialized() {
109
- return __classPrivateFieldGet(this, _AirgappedSigner_source, "f") !== undefined;
110
- }
111
- /**
112
- * Derive an address from the source at a given index
113
- *
114
- * @param index - The index to derive the address from
115
- * @returns The derived address in hex format
116
- * @throws Will throw an error if the source is not initialized
117
- */
118
- addressFromIndex(index) {
119
- if (!__classPrivateFieldGet(this, _AirgappedSigner_source, "f")) {
120
- throw new Error('UR not initialized');
121
- }
122
- if (__classPrivateFieldGet(this, _AirgappedSigner_source, "f").keyringMode === KeyringMode.ACCOUNT) {
123
- const address = Object.keys(__classPrivateFieldGet(this, _AirgappedSigner_source, "f").paths)[index];
124
- if (!address) {
125
- throw new Error(`Address not found for index ${index}`);
126
- }
127
- return add0x(address);
128
- }
129
- const childPath = `m/${__classPrivateFieldGet(this, _AirgappedSigner_source, "f").childrenPath.replace('*', index.toString())}`;
130
- const hdKey = HdKey.fromExtendedKey(__classPrivateFieldGet(this, _AirgappedSigner_source, "f").xpub);
131
- const childKey = hdKey.derive(childPath);
132
- const address = Buffer.from(publicToAddress(childKey.publicKey, true)).toString('hex');
133
- const normalizedAddress = getChecksumAddress(add0x(address));
134
- __classPrivateFieldGet(this, _AirgappedSigner_source, "f").indexes[normalizedAddress] = index;
135
- return normalizedAddress;
136
- }
137
- /**
138
- * Retrieve the path of an address derived from the source.
139
- *
140
- * @param address - The address to retrieve the path for
141
- * @returns The path of the address
142
- */
143
- pathFromAddress(address) {
144
- if (!__classPrivateFieldGet(this, _AirgappedSigner_source, "f")) {
145
- throw new Error('UR not initialized');
146
- }
147
- const normalizedAddress = getChecksumAddress(add0x(address));
148
- if (__classPrivateFieldGet(this, _AirgappedSigner_source, "f").keyringMode === KeyringMode.ACCOUNT) {
149
- const path = __classPrivateFieldGet(this, _AirgappedSigner_source, "f").paths[normalizedAddress];
150
- if (path === undefined) {
151
- throw new Error(`Unknown address ${normalizedAddress}`);
152
- }
153
- return path;
154
- }
155
- const index = this.indexFromAddress(normalizedAddress);
156
- return `${__classPrivateFieldGet(this, _AirgappedSigner_source, "f").hdPath}/${__classPrivateFieldGet(this, _AirgappedSigner_source, "f").childrenPath
157
- .replace('*', index.toString())
158
- .replace(/\*/gu, '0')}`;
159
- }
160
- /**
161
- * Retrieve the index of an address from the source
162
- *
163
- * @param address - The normalized address to retrieve the index for
164
- * @returns The index of the address
165
- */
166
- indexFromAddress(address) {
167
- if (!__classPrivateFieldGet(this, _AirgappedSigner_source, "f")) {
168
- throw new Error('UR not initialized');
169
- }
170
- const cachedIndex = __classPrivateFieldGet(this, _AirgappedSigner_source, "f").indexes[address];
171
- if (cachedIndex !== undefined) {
172
- return Number(cachedIndex);
173
- }
174
- if (__classPrivateFieldGet(this, _AirgappedSigner_source, "f").keyringMode === KeyringMode.ACCOUNT) {
175
- const path = __classPrivateFieldGet(this, _AirgappedSigner_source, "f").paths[address];
176
- if (path === undefined) {
177
- throw new Error(`Unknown address`);
178
- }
179
- const index = path.split('/').pop();
180
- if (index === undefined) {
181
- throw new Error(`Invalid path for address ${address}`);
182
- }
183
- return Number(index);
184
- }
185
- for (let i = 0; i < MAX_INDEX; i++) {
186
- const derivedAddress = this.addressFromIndex(i);
187
- if (derivedAddress === address) {
188
- return i;
189
- }
190
- }
191
- throw new Error(`Address ${address} not found`);
192
- }
193
- /**
194
- * Get a page of addresses derived from the source.
195
- *
196
- * @param page - The page number to retrieve
197
- * @param pageSize - The number of addresses per page
198
- * @returns An array of IndexedAddress objects, each containing the address and its index
199
- * @throws Will throw an error if the source is not initialized
200
- */
201
- getAddressesPage(page, pageSize = 5) {
202
- const startIndex = page * pageSize;
203
- const endIndex = startIndex + pageSize;
204
- const addresses = [];
205
- for (let i = startIndex; i < endIndex; i++) {
206
- const address = this.addressFromIndex(i);
207
- addresses.push({ address, index: i });
208
- }
209
- return addresses;
210
- }
211
- /**
212
- * Gets the source details of the AirgappedSigner.
213
- *
214
- * @returns The source details, or undefined if not initialized
215
- */
216
- getSourceDetails() {
217
- return __classPrivateFieldGet(this, _AirgappedSigner_source, "f");
218
- }
219
- /**
220
- * Clear the source details.
221
- */
222
- clear() {
223
- __classPrivateFieldSet(this, _AirgappedSigner_source, undefined, "f");
224
- }
225
- }
226
- _AirgappedSigner_source = new WeakMap(), _AirgappedSigner_instances = new WeakSet(), _AirgappedSigner_initFromUR = function _AirgappedSigner_initFromUR(ur) {
227
- const source = __classPrivateFieldGet(this, _AirgappedSigner_instances, "m", _AirgappedSigner_decodeUR).call(this, ur);
228
- const fingerprint = getFingerprintFromSource(source);
229
- if (source instanceof CryptoAccount) {
230
- const { name, xfp, paths, keyringAccount } = readCryptoAccountOutputDescriptors(source);
231
- __classPrivateFieldSet(this, _AirgappedSigner_source, {
232
- keyringMode: KeyringMode.ACCOUNT,
233
- keyringAccount,
234
- name,
235
- xfp,
236
- paths,
237
- indexes: {},
238
- }, "f");
239
- }
240
- else {
241
- const { getBip32Key, getOrigin, getChildren, getName, getNote } = source;
242
- __classPrivateFieldSet(this, _AirgappedSigner_source, {
243
- keyringMode: KeyringMode.HD,
244
- keyringAccount: getNote(),
245
- name: getName(),
246
- xfp: fingerprint,
247
- hdPath: `m/${getOrigin().getPath()}`,
248
- childrenPath: getChildren()?.getPath() || DEFAULT_CHILDREN_PATH,
249
- xpub: getBip32Key(),
250
- indexes: {},
251
- }, "f");
252
- }
253
- }, _AirgappedSigner_decodeUR = function _AirgappedSigner_decodeUR(ur) {
254
- const decodedUR = typeof ur === 'string'
255
- ? URRegistryDecoder.decode(ur)
256
- : {
257
- type: ur.type,
258
- cbor: Buffer.from(ur.cbor, 'hex'),
259
- };
260
- const { type, cbor } = decodedUR;
261
- switch (type) {
262
- case SUPPORTED_UR_TYPE.CRYPTO_HDKEY:
263
- return CryptoHDKey.fromCBOR(cbor);
264
- case SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT:
265
- return CryptoAccount.fromCBOR(cbor);
266
- default:
267
- throw new Error('Unsupported UR type');
268
- }
269
- };
270
- //# sourceMappingURL=airgapped-signer.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"airgapped-signer.mjs","sourceRoot":"","sources":["../src/airgapped-signer.ts"],"names":[],"mappings":"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","sourcesContent":["import { publicToAddress } from '@ethereumjs/util';\nimport {\n CryptoAccount,\n CryptoHDKey,\n URRegistryDecoder,\n} from '@keystonehq/bc-ur-registry-eth';\nimport { add0x, getChecksumAddress, type Hex } from '@metamask/utils';\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport HdKey from 'hdkey';\n\nimport type { SerializedUR } from './qr-keyring';\n\nexport const SUPPORTED_UR_TYPE = {\n CRYPTO_HDKEY: 'crypto-hdkey',\n CRYPTO_ACCOUNT: 'crypto-account',\n ETH_SIGNATURE: 'eth-signature',\n};\n\nexport enum KeyringMode {\n HD = 'hd',\n ACCOUNT = 'account',\n}\n\nconst DEFAULT_CHILDREN_PATH = '0/*';\n\nconst MAX_INDEX = 1_000;\n\n/**\n * Common details for the signer source, which can be either a CryptoAccount or CryptoHDKey.\n */\nexport type CommonSignerDetails = {\n /**\n * Value take out from the device note field, if available.\n */\n keyringAccount: string;\n /**\n * The name of the device\n */\n name: string;\n /**\n * The device fingerprint, hex-encoded\n */\n xfp: string;\n /**\n * Indexes of the accounts derived from the device\n * in the form of a map from address to index\n */\n indexes: Record<Hex, number>;\n};\n\n/**\n * Details for the HD mode of the AirgappedSigner. This mode derives\n * accounts from a root public key (xpub) and a derivation path.\n */\nexport type HDModeSignerDetails = {\n /**\n * The keyring mode is HD, indicating that it derives accounts from a\n * root public key (xpub) and a derivation path.\n */\n keyringMode: KeyringMode.HD;\n /**\n * The xpub of the HD key\n */\n xpub: string;\n /**\n * The derivation path of the HD key\n */\n hdPath: string;\n /**\n * The path used to derive child accounts\n */\n childrenPath: string;\n};\n\n/**\n * Details for the Account mode of the AirgappedSigner. This mode derives\n * accounts from a set of addresses and their corresponding paths.\n */\nexport type AccountModeSignerDetails = {\n /**\n * The keyring mode is ACCOUNT, indicating that it derives accounts from\n * a set of addresses and their corresponding paths.\n */\n keyringMode: KeyringMode.ACCOUNT;\n /**\n * The derivation paths for each hex-encoded address in the device\n */\n paths: Record<Hex, string>;\n};\n\n/**\n * An address with its corresponding index.\n */\nexport type IndexedAddress = {\n address: Hex;\n index: number;\n};\n\n/**\n * The details of the source CryptoAccount or CryptoHDKey\n * that the AirgappedSigner uses to derive accounts.\n */\nexport type AirgappedSignerDetails = CommonSignerDetails &\n (HDModeSignerDetails | AccountModeSignerDetails);\n\n/**\n * Get the fingerprint of the source CryptoAccount or CryptoHDKey\n *\n * @param source - The source CryptoAccount or CryptoHDKey\n * @returns The fingerprint of the source\n */\nfunction getFingerprintFromSource(source: CryptoAccount | CryptoHDKey): string {\n return source instanceof CryptoAccount\n ? source.getMasterFingerprint()?.toString('hex')\n : source.getParentFingerprint()?.toString('hex');\n}\n\n/**\n * Get fingerprint, account paths and names from the a CryptoAccount\n *\n * Note: This function emulates the behavior of the `@keystonehq/base-eth-keyring`\n * library when dealing with CryptoAccount objects (for backwards compatibility\n * reasons). Though, the way it retrieves `name` and `keyringAccount` is questionable,\n * as `name` and `keyringAccount` are updated after each descriptor discovery, effectively\n * returning the last descriptor's `name` and `keyringAccount`.\n *\n * @param source - The source CryptoAccount\n * @returns The paths\n */\nfunction readCryptoAccountOutputDescriptors(source: CryptoAccount): {\n xfp: string;\n paths: Record<Hex, string>;\n name: string;\n keyringAccount: string;\n} {\n const descriptors = source.getOutputDescriptors();\n\n if (!descriptors || descriptors.length === 0) {\n throw new Error('No output descriptors found in CryptoAccount');\n }\n\n let name = '';\n let keyringAccount = '';\n const paths = descriptors.reduce(\n (descriptorsPaths: Record<Hex, string>, current) => {\n const hdKey = current.getHDKey();\n if (hdKey) {\n const path = `M/${hdKey.getOrigin().getPath()}`;\n const address = getChecksumAddress(\n add0x(\n Buffer.from(publicToAddress(hdKey.getKey(), true)).toString('hex'),\n ),\n );\n descriptorsPaths[address] = path;\n name = hdKey.getName();\n keyringAccount = hdKey.getNote();\n }\n return descriptorsPaths;\n },\n {},\n );\n\n return {\n paths,\n name,\n keyringAccount,\n xfp: getFingerprintFromSource(source),\n };\n}\n\nexport class AirgappedSigner {\n #source?: AirgappedSignerDetails | undefined;\n\n /**\n * Initialize the AirgappedSigner with a source.\n *\n * @param source - The signer source, in the form of details object, or a UR string\n */\n init(source: AirgappedSignerDetails | string | SerializedUR): void {\n if (typeof source === 'string' || 'cbor' in source) {\n this.#initFromUR(source);\n } else {\n this.#source = source;\n }\n }\n\n /**\n * Check if the AirgappedSigner is initialized\n *\n * @returns True if the AirgappedSigner is initialized, false otherwise\n */\n isInitialized(): boolean {\n return this.#source !== undefined;\n }\n\n /**\n * Derive an address from the source at a given index\n *\n * @param index - The index to derive the address from\n * @returns The derived address in hex format\n * @throws Will throw an error if the source is not initialized\n */\n addressFromIndex(index: number): Hex {\n if (!this.#source) {\n throw new Error('UR not initialized');\n }\n\n if (this.#source.keyringMode === KeyringMode.ACCOUNT) {\n const address = Object.keys(this.#source.paths)[index];\n if (!address) {\n throw new Error(`Address not found for index ${index}`);\n }\n return add0x(address);\n }\n const childPath = `m/${this.#source.childrenPath.replace(\n '*',\n index.toString(),\n )}`;\n\n const hdKey = HdKey.fromExtendedKey(this.#source.xpub);\n const childKey = hdKey.derive(childPath);\n\n const address = Buffer.from(\n publicToAddress(childKey.publicKey, true),\n ).toString('hex');\n\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n this.#source.indexes[normalizedAddress] = index;\n\n return normalizedAddress;\n }\n\n /**\n * Retrieve the path of an address derived from the source.\n *\n * @param address - The address to retrieve the path for\n * @returns The path of the address\n */\n pathFromAddress(address: Hex): string {\n if (!this.#source) {\n throw new Error('UR not initialized');\n }\n\n const normalizedAddress = getChecksumAddress(add0x(address));\n\n if (this.#source.keyringMode === KeyringMode.ACCOUNT) {\n const path = this.#source.paths[normalizedAddress];\n if (path === undefined) {\n throw new Error(`Unknown address ${normalizedAddress}`);\n }\n return path;\n }\n\n const index = this.indexFromAddress(normalizedAddress);\n return `${this.#source.hdPath}/${this.#source.childrenPath\n .replace('*', index.toString())\n .replace(/\\*/gu, '0')}`;\n }\n\n /**\n * Retrieve the index of an address from the source\n *\n * @param address - The normalized address to retrieve the index for\n * @returns The index of the address\n */\n indexFromAddress(address: Hex): number {\n if (!this.#source) {\n throw new Error('UR not initialized');\n }\n\n const cachedIndex = this.#source.indexes[address];\n if (cachedIndex !== undefined) {\n return Number(cachedIndex);\n }\n\n if (this.#source.keyringMode === KeyringMode.ACCOUNT) {\n const path = this.#source.paths[address];\n if (path === undefined) {\n throw new Error(`Unknown address`);\n }\n\n const index = path.split('/').pop();\n if (index === undefined) {\n throw new Error(`Invalid path for address ${address}`);\n }\n\n return Number(index);\n }\n\n for (let i = 0; i < MAX_INDEX; i++) {\n const derivedAddress = this.addressFromIndex(i);\n if (derivedAddress === address) {\n return i;\n }\n }\n\n throw new Error(`Address ${address} not found`);\n }\n\n /**\n * Get a page of addresses derived from the source.\n *\n * @param page - The page number to retrieve\n * @param pageSize - The number of addresses per page\n * @returns An array of IndexedAddress objects, each containing the address and its index\n * @throws Will throw an error if the source is not initialized\n */\n getAddressesPage(page: number, pageSize = 5): IndexedAddress[] {\n const startIndex = page * pageSize;\n const endIndex = startIndex + pageSize;\n const addresses: IndexedAddress[] = [];\n\n for (let i = startIndex; i < endIndex; i++) {\n const address = this.addressFromIndex(i);\n addresses.push({ address, index: i });\n }\n\n return addresses;\n }\n\n /**\n * Gets the source details of the AirgappedSigner.\n *\n * @returns The source details, or undefined if not initialized\n */\n getSourceDetails(): AirgappedSignerDetails | undefined {\n return this.#source;\n }\n\n /**\n * Clear the source details.\n */\n clear(): void {\n this.#source = undefined;\n }\n\n /**\n * Set the root account from a UR string\n *\n * @param ur - The UR string to set the root account from\n */\n #initFromUR(ur: string | SerializedUR): void {\n const source = this.#decodeUR(ur);\n const fingerprint = getFingerprintFromSource(source);\n\n if (source instanceof CryptoAccount) {\n const { name, xfp, paths, keyringAccount } =\n readCryptoAccountOutputDescriptors(source);\n this.#source = {\n keyringMode: KeyringMode.ACCOUNT,\n keyringAccount,\n name,\n xfp,\n paths,\n indexes: {},\n };\n } else {\n const { getBip32Key, getOrigin, getChildren, getName, getNote } = source;\n this.#source = {\n keyringMode: KeyringMode.HD,\n keyringAccount: getNote(),\n name: getName(),\n xfp: fingerprint,\n hdPath: `m/${getOrigin().getPath()}`,\n childrenPath: getChildren()?.getPath() || DEFAULT_CHILDREN_PATH,\n xpub: getBip32Key(),\n indexes: {},\n };\n }\n }\n\n /**\n * Decodes a UR\n *\n * @param ur - The UR to decode\n * @returns The decoded CryptoAccount or CryptoHDKey\n * @throws Will throw an error if the UR type is not supported\n */\n #decodeUR(ur: string | SerializedUR): CryptoAccount | CryptoHDKey {\n const decodedUR =\n typeof ur === 'string'\n ? URRegistryDecoder.decode(ur)\n : {\n type: ur.type,\n cbor: Buffer.from(ur.cbor, 'hex'),\n };\n\n const { type, cbor } = decodedUR;\n\n switch (type) {\n case SUPPORTED_UR_TYPE.CRYPTO_HDKEY:\n return CryptoHDKey.fromCBOR(cbor);\n case SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT:\n return CryptoAccount.fromCBOR(cbor);\n default:\n throw new Error('Unsupported UR type');\n }\n }\n}\n"]}