@metamask-previews/eth-trezor-keyring 9.0.0-ca7f2af → 9.0.0-cd75414

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add `TrezorKeyringV2` and `OneKeyKeyringV2` classes implementing `KeyringV2` interface ([#412](https://github.com/MetaMask/accounts/pull/412)), ([#451](https://github.com/MetaMask/accounts/pull/451)), ([#453](https://github.com/MetaMask/accounts/pull/453))
13
+ - Wraps legacy `TrezorKeyring` and `OneKeyKeyring` to expose accounts via the unified `KeyringV2` API and the `KeyringAccount` type.
14
+ - Extends `EthKeyringWrapper` for common Ethereum logic.
15
+
10
16
  ## [9.0.0]
11
17
 
12
18
  ### Changed
package/dist/index.cjs CHANGED
@@ -15,6 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./trezor-keyring.cjs"), exports);
18
+ __exportStar(require("./trezor-keyring-v2.cjs"), exports);
18
19
  __exportStar(require("./onekey-keyring.cjs"), exports);
20
+ __exportStar(require("./onekey-keyring-v2.cjs"), exports);
19
21
  __exportStar(require("./trezor-connect-bridge.cjs"), exports);
20
22
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAiC;AACjC,uDAAiC;AAEjC,8DAAwC","sourcesContent":["export * from './trezor-keyring';\nexport * from './onekey-keyring';\nexport type * from './trezor-bridge';\nexport * from './trezor-connect-bridge';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAiC;AACjC,0DAAoC;AACpC,uDAAiC;AACjC,0DAAoC;AAEpC,8DAAwC","sourcesContent":["export * from './trezor-keyring';\nexport * from './trezor-keyring-v2';\nexport * from './onekey-keyring';\nexport * from './onekey-keyring-v2';\nexport type * from './trezor-bridge';\nexport * from './trezor-connect-bridge';\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from "./trezor-keyring.cjs";
2
+ export * from "./trezor-keyring-v2.cjs";
2
3
  export * from "./onekey-keyring.cjs";
4
+ export * from "./onekey-keyring-v2.cjs";
3
5
  export type * from "./trezor-bridge.cjs";
4
6
  export * from "./trezor-connect-bridge.cjs";
5
7
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,qCAAiC;AACjC,yCAAqC;AACrC,4CAAwC"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,wCAAoC;AACpC,qCAAiC;AACjC,wCAAoC;AACpC,yCAAqC;AACrC,4CAAwC"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from "./trezor-keyring.mjs";
2
+ export * from "./trezor-keyring-v2.mjs";
2
3
  export * from "./onekey-keyring.mjs";
4
+ export * from "./onekey-keyring-v2.mjs";
3
5
  export type * from "./trezor-bridge.mjs";
4
6
  export * from "./trezor-connect-bridge.mjs";
5
7
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,qCAAiC;AACjC,yCAAqC;AACrC,4CAAwC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,wCAAoC;AACpC,qCAAiC;AACjC,wCAAoC;AACpC,yCAAqC;AACrC,4CAAwC"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./trezor-keyring.mjs";
2
+ export * from "./trezor-keyring-v2.mjs";
2
3
  export * from "./onekey-keyring.mjs";
4
+ export * from "./onekey-keyring-v2.mjs";
3
5
  export * from "./trezor-connect-bridge.mjs";
4
6
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,qCAAiC;AAEjC,4CAAwC","sourcesContent":["export * from './trezor-keyring';\nexport * from './onekey-keyring';\nexport type * from './trezor-bridge';\nexport * from './trezor-connect-bridge';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,wCAAoC;AACpC,qCAAiC;AACjC,wCAAoC;AAEpC,4CAAwC","sourcesContent":["export * from './trezor-keyring';\nexport * from './trezor-keyring-v2';\nexport * from './onekey-keyring';\nexport * from './onekey-keyring-v2';\nexport type * from './trezor-bridge';\nexport * from './trezor-connect-bridge';\n"]}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OneKeyKeyringV2 = void 0;
4
+ const keyring_api_1 = require("@metamask/keyring-api");
5
+ const trezor_keyring_v2_1 = require("./trezor-keyring-v2.cjs");
6
+ /**
7
+ * Concrete {@link KeyringV2} adapter for {@link OneKeyKeyring}.
8
+ *
9
+ * This wrapper extends {@link TrezorKeyringV2} since OneKeyKeyring extends
10
+ * TrezorKeyring. The only difference is the keyring type identifier.
11
+ */
12
+ class OneKeyKeyringV2 extends trezor_keyring_v2_1.TrezorKeyringV2 {
13
+ constructor(options) {
14
+ super({
15
+ legacyKeyring: options.legacyKeyring,
16
+ entropySource: options.entropySource,
17
+ type: keyring_api_1.KeyringType.OneKey,
18
+ });
19
+ }
20
+ }
21
+ exports.OneKeyKeyringV2 = OneKeyKeyringV2;
22
+ //# sourceMappingURL=onekey-keyring-v2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onekey-keyring-v2.cjs","sourceRoot":"","sources":["../src/onekey-keyring-v2.ts"],"names":[],"mappings":";;;AAAA,uDAA0E;AAG1E,+DAAsD;AAUtD;;;;;GAKG;AACH,MAAa,eAAgB,SAAQ,mCAAe;IAClD,YAAY,OAA+B;QACzC,KAAK,CAAC;YACJ,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,IAAI,EAAE,yBAAW,CAAC,MAAM;SACzB,CAAC,CAAC;IACL,CAAC;CACF;AARD,0CAQC","sourcesContent":["import { KeyringType, type EntropySourceId } from '@metamask/keyring-api';\n\nimport type { OneKeyKeyring } from './onekey-keyring';\nimport { TrezorKeyringV2 } from './trezor-keyring-v2';\n\n/**\n * Options for creating a OneKeyKeyringV2 instance.\n */\nexport type OneKeyKeyringV2Options = {\n legacyKeyring: OneKeyKeyring;\n entropySource: EntropySourceId;\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link OneKeyKeyring}.\n *\n * This wrapper extends {@link TrezorKeyringV2} since OneKeyKeyring extends\n * TrezorKeyring. The only difference is the keyring type identifier.\n */\nexport class OneKeyKeyringV2 extends TrezorKeyringV2 {\n constructor(options: OneKeyKeyringV2Options) {\n super({\n legacyKeyring: options.legacyKeyring,\n entropySource: options.entropySource,\n type: KeyringType.OneKey,\n });\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { type EntropySourceId } from "@metamask/keyring-api";
2
+ import type { OneKeyKeyring } from "./onekey-keyring.cjs";
3
+ import { TrezorKeyringV2 } from "./trezor-keyring-v2.cjs";
4
+ /**
5
+ * Options for creating a OneKeyKeyringV2 instance.
6
+ */
7
+ export type OneKeyKeyringV2Options = {
8
+ legacyKeyring: OneKeyKeyring;
9
+ entropySource: EntropySourceId;
10
+ };
11
+ /**
12
+ * Concrete {@link KeyringV2} adapter for {@link OneKeyKeyring}.
13
+ *
14
+ * This wrapper extends {@link TrezorKeyringV2} since OneKeyKeyring extends
15
+ * TrezorKeyring. The only difference is the keyring type identifier.
16
+ */
17
+ export declare class OneKeyKeyringV2 extends TrezorKeyringV2 {
18
+ constructor(options: OneKeyKeyringV2Options);
19
+ }
20
+ //# sourceMappingURL=onekey-keyring-v2.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onekey-keyring-v2.d.cts","sourceRoot":"","sources":["../src/onekey-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,eAAe,EAAE,8BAA8B;AAE1E,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AACtD,OAAO,EAAE,eAAe,EAAE,gCAA4B;AAEtD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,eAAe;gBACtC,OAAO,EAAE,sBAAsB;CAO5C"}
@@ -0,0 +1,20 @@
1
+ import { type EntropySourceId } from "@metamask/keyring-api";
2
+ import type { OneKeyKeyring } from "./onekey-keyring.mjs";
3
+ import { TrezorKeyringV2 } from "./trezor-keyring-v2.mjs";
4
+ /**
5
+ * Options for creating a OneKeyKeyringV2 instance.
6
+ */
7
+ export type OneKeyKeyringV2Options = {
8
+ legacyKeyring: OneKeyKeyring;
9
+ entropySource: EntropySourceId;
10
+ };
11
+ /**
12
+ * Concrete {@link KeyringV2} adapter for {@link OneKeyKeyring}.
13
+ *
14
+ * This wrapper extends {@link TrezorKeyringV2} since OneKeyKeyring extends
15
+ * TrezorKeyring. The only difference is the keyring type identifier.
16
+ */
17
+ export declare class OneKeyKeyringV2 extends TrezorKeyringV2 {
18
+ constructor(options: OneKeyKeyringV2Options);
19
+ }
20
+ //# sourceMappingURL=onekey-keyring-v2.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onekey-keyring-v2.d.mts","sourceRoot":"","sources":["../src/onekey-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,eAAe,EAAE,8BAA8B;AAE1E,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AACtD,OAAO,EAAE,eAAe,EAAE,gCAA4B;AAEtD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,eAAe;gBACtC,OAAO,EAAE,sBAAsB;CAO5C"}
@@ -0,0 +1,18 @@
1
+ import { KeyringType } from "@metamask/keyring-api";
2
+ import { TrezorKeyringV2 } from "./trezor-keyring-v2.mjs";
3
+ /**
4
+ * Concrete {@link KeyringV2} adapter for {@link OneKeyKeyring}.
5
+ *
6
+ * This wrapper extends {@link TrezorKeyringV2} since OneKeyKeyring extends
7
+ * TrezorKeyring. The only difference is the keyring type identifier.
8
+ */
9
+ export class OneKeyKeyringV2 extends TrezorKeyringV2 {
10
+ constructor(options) {
11
+ super({
12
+ legacyKeyring: options.legacyKeyring,
13
+ entropySource: options.entropySource,
14
+ type: KeyringType.OneKey,
15
+ });
16
+ }
17
+ }
18
+ //# sourceMappingURL=onekey-keyring-v2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onekey-keyring-v2.mjs","sourceRoot":"","sources":["../src/onekey-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAwB,8BAA8B;AAG1E,OAAO,EAAE,eAAe,EAAE,gCAA4B;AAUtD;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,eAAe;IAClD,YAAY,OAA+B;QACzC,KAAK,CAAC;YACJ,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,IAAI,EAAE,WAAW,CAAC,MAAM;SACzB,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["import { KeyringType, type EntropySourceId } from '@metamask/keyring-api';\n\nimport type { OneKeyKeyring } from './onekey-keyring';\nimport { TrezorKeyringV2 } from './trezor-keyring-v2';\n\n/**\n * Options for creating a OneKeyKeyringV2 instance.\n */\nexport type OneKeyKeyringV2Options = {\n legacyKeyring: OneKeyKeyring;\n entropySource: EntropySourceId;\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link OneKeyKeyring}.\n *\n * This wrapper extends {@link TrezorKeyringV2} since OneKeyKeyring extends\n * TrezorKeyring. The only difference is the keyring type identifier.\n */\nexport class OneKeyKeyringV2 extends TrezorKeyringV2 {\n constructor(options: OneKeyKeyringV2Options) {\n super({\n legacyKeyring: options.legacyKeyring,\n entropySource: options.entropySource,\n type: KeyringType.OneKey,\n });\n }\n}\n"]}
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ 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");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _TrezorKeyringV2_instances, _TrezorKeyringV2_parseDerivationPath, _TrezorKeyringV2_createKeyringAccount;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TrezorKeyringV2 = exports.LEGACY_MEW_PATH_PREFIX = exports.SLIP0044_TESTNET_PATH_PREFIX = exports.BIP44_HD_PATH_PREFIX = void 0;
10
+ const keyring_api_1 = require("@metamask/keyring-api");
11
+ /**
12
+ * Methods supported by Trezor keyring EOA accounts.
13
+ * Trezor keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).
14
+ */
15
+ const TREZOR_KEYRING_METHODS = [
16
+ keyring_api_1.EthMethod.SignTransaction,
17
+ keyring_api_1.EthMethod.PersonalSign,
18
+ keyring_api_1.EthMethod.SignTypedDataV3,
19
+ keyring_api_1.EthMethod.SignTypedDataV4,
20
+ ];
21
+ const trezorKeyringV2Capabilities = {
22
+ scopes: [keyring_api_1.EthScope.Eoa],
23
+ bip44: {
24
+ deriveIndex: true,
25
+ derivePath: true,
26
+ },
27
+ };
28
+ /**
29
+ * BIP-44 standard HD path prefix constant for Ethereum.
30
+ * Used as default for derive-index operations.
31
+ */
32
+ exports.BIP44_HD_PATH_PREFIX = `m/44'/60'/0'/0`;
33
+ /**
34
+ * SLIP-0044 testnet HD path prefix constant.
35
+ */
36
+ exports.SLIP0044_TESTNET_PATH_PREFIX = `m/44'/1'/0'/0`;
37
+ /**
38
+ * Legacy MEW (MyEtherWallet) HD path prefix constant.
39
+ */
40
+ exports.LEGACY_MEW_PATH_PREFIX = `m/44'/60'/0'`;
41
+ /**
42
+ * Allowed HD paths for Trezor keyring.
43
+ * These must match the keys in ALLOWED_HD_PATHS from trezor-keyring.ts.
44
+ */
45
+ const ALLOWED_HD_PATHS = [
46
+ exports.BIP44_HD_PATH_PREFIX,
47
+ exports.SLIP0044_TESTNET_PATH_PREFIX,
48
+ exports.LEGACY_MEW_PATH_PREFIX,
49
+ ];
50
+ /**
51
+ * Regex pattern for validating and parsing Trezor derivation paths.
52
+ * Matches BIP-44 style paths: m/44'/{coin}'/{segments}/{index}
53
+ * where coin is 60' (Ethereum) or 1' (testnet).
54
+ * Captures: [1] = base path prefix, [2] = index
55
+ * The prefix is then validated against ALLOWED_HD_PATHS.
56
+ */
57
+ const DERIVATION_PATH_PATTERN = /^(m\/44'\/(?:60'|1')(?:\/\d+'?)*)\/(\d+)$/u;
58
+ class TrezorKeyringV2 extends keyring_api_1.EthKeyringWrapper {
59
+ constructor(options) {
60
+ var _a;
61
+ super({
62
+ type: (_a = options.type) !== null && _a !== void 0 ? _a : keyring_api_1.KeyringType.Trezor,
63
+ inner: options.legacyKeyring,
64
+ capabilities: trezorKeyringV2Capabilities,
65
+ });
66
+ _TrezorKeyringV2_instances.add(this);
67
+ this.entropySource = options.entropySource;
68
+ }
69
+ /**
70
+ * Hydrate the underlying keyring from a previously serialized state.
71
+ *
72
+ * Overrides the base class implementation to avoid calling `getAccounts()`
73
+ * when the Trezor device is locked. The base class calls `getAccounts()` to
74
+ * rebuild the registry, but for Trezor keyrings this requires the HDKey to
75
+ * be initialized (via `unlock()`). Since the device may not be connected
76
+ * during deserialization, we skip the registry rebuild here. The registry
77
+ * will be populated on the first call to `getAccounts()` after the device
78
+ * is unlocked.
79
+ *
80
+ * @param state - The serialized keyring state.
81
+ */
82
+ async deserialize(state) {
83
+ await this.withLock(async () => {
84
+ // Clear the registry when deserializing
85
+ this.registry.clear();
86
+ // Deserialize the legacy keyring state only.
87
+ // We intentionally skip calling getAccounts() here because the Trezor
88
+ // device may be locked (HDKey not initialized). The TrezorKeyring's
89
+ // deserialize restores the accounts array, but not the paths map, so
90
+ // getIndexForAddress would need to derive addresses which requires an
91
+ // initialized HDKey. The registry will be populated lazily when
92
+ // getAccounts() is called after the device is unlocked.
93
+ await this.inner.deserialize(state);
94
+ });
95
+ }
96
+ async getAccounts() {
97
+ const addresses = await this.inner.getAccounts();
98
+ if (addresses.length === 0) {
99
+ return [];
100
+ }
101
+ // If the device is locked, we cannot derive addresses to find indices.
102
+ // Return cached accounts if available, otherwise throw a clear error.
103
+ if (!this.inner.isUnlocked()) {
104
+ const cachedAccounts = addresses
105
+ .map((address) => {
106
+ const existingId = this.registry.getAccountId(address);
107
+ return existingId ? this.registry.get(existingId) : undefined;
108
+ })
109
+ .filter((account) => account !== undefined);
110
+ // If we have all accounts cached, return them
111
+ if (cachedAccounts.length === addresses.length) {
112
+ return cachedAccounts;
113
+ }
114
+ // Some accounts are not cached and device is locked
115
+ throw new Error('Trezor device is locked. Please unlock the device to access accounts.');
116
+ }
117
+ return addresses.map((address) => {
118
+ // Check if we already have this account in the registry
119
+ const existingId = this.registry.getAccountId(address);
120
+ if (existingId) {
121
+ const cached = this.registry.get(existingId);
122
+ if (cached) {
123
+ return cached;
124
+ }
125
+ }
126
+ const addressIndex = this.inner.getIndexForAddress(address);
127
+ return __classPrivateFieldGet(this, _TrezorKeyringV2_instances, "m", _TrezorKeyringV2_createKeyringAccount).call(this, address, addressIndex);
128
+ });
129
+ }
130
+ async createAccounts(options) {
131
+ return this.withLock(async () => {
132
+ if (options.type === 'bip44:derive-path' ||
133
+ options.type === 'bip44:derive-index') {
134
+ // Validate that the entropy source matches this keyring's entropy source
135
+ if (options.entropySource !== this.entropySource) {
136
+ throw new Error(`Entropy source mismatch: expected '${this.entropySource}', got '${options.entropySource}'`);
137
+ }
138
+ }
139
+ else {
140
+ throw new Error(`Unsupported account creation type for TrezorKeyring: ${String(options.type)}`);
141
+ }
142
+ // Check if an account at this index already exists with the same derivation path
143
+ const currentAccounts = await this.getAccounts();
144
+ let targetIndex;
145
+ let basePath;
146
+ let derivationPath;
147
+ if (options.type === 'bip44:derive-path') {
148
+ // Parse the derivation path to extract base path and index
149
+ const parsed = __classPrivateFieldGet(this, _TrezorKeyringV2_instances, "m", _TrezorKeyringV2_parseDerivationPath).call(this, options.derivationPath);
150
+ targetIndex = parsed.index;
151
+ basePath = parsed.basePath;
152
+ // Use the normalized path to avoid mismatches with leading zeros
153
+ // (e.g., "m/44'/60'/0'/0/007" becomes "m/44'/60'/0'/0/7")
154
+ derivationPath = `${basePath}/${targetIndex}`;
155
+ }
156
+ else {
157
+ // derive-index uses BIP-44 standard path by default
158
+ if (options.groupIndex < 0) {
159
+ throw new Error(`Invalid groupIndex: ${options.groupIndex}. Must be a non-negative integer.`);
160
+ }
161
+ targetIndex = options.groupIndex;
162
+ basePath = exports.BIP44_HD_PATH_PREFIX;
163
+ derivationPath = `${basePath}/${targetIndex}`;
164
+ }
165
+ const existingAccount = currentAccounts.find((account) => {
166
+ return (account.options.entropy.groupIndex === targetIndex &&
167
+ account.options.entropy.derivationPath === derivationPath);
168
+ });
169
+ if (existingAccount) {
170
+ return [existingAccount];
171
+ }
172
+ // Derive the account at the specified index.
173
+ // If the HD path is changing, clear the registry to avoid stale accounts.
174
+ // The TrezorKeyring operates on a single path at a time - accounts from
175
+ // different paths cannot coexist in the inner keyring.
176
+ if (basePath !== this.inner.hdPath) {
177
+ this.registry.clear();
178
+ }
179
+ this.inner.setHdPath(basePath);
180
+ this.inner.setAccountToUnlock(targetIndex);
181
+ const [newAddress] = await this.inner.addAccounts(1);
182
+ if (!newAddress) {
183
+ throw new Error('Failed to create new account');
184
+ }
185
+ const newAccount = __classPrivateFieldGet(this, _TrezorKeyringV2_instances, "m", _TrezorKeyringV2_createKeyringAccount).call(this, newAddress, targetIndex);
186
+ return [newAccount];
187
+ });
188
+ }
189
+ /**
190
+ * Delete an account from the keyring.
191
+ *
192
+ * @param accountId - The account ID to delete.
193
+ */
194
+ async deleteAccount(accountId) {
195
+ await this.withLock(async () => {
196
+ const { address } = await this.getAccount(accountId);
197
+ const hexAddress = this.toHexAddress(address);
198
+ // Remove from the legacy keyring
199
+ this.inner.removeAccount(hexAddress);
200
+ // Remove from the registry
201
+ this.registry.delete(accountId);
202
+ });
203
+ }
204
+ }
205
+ exports.TrezorKeyringV2 = TrezorKeyringV2;
206
+ _TrezorKeyringV2_instances = new WeakSet(), _TrezorKeyringV2_parseDerivationPath = function _TrezorKeyringV2_parseDerivationPath(derivationPath) {
207
+ const match = derivationPath.match(DERIVATION_PATH_PATTERN);
208
+ if (!(match === null || match === void 0 ? void 0 : match[1]) || !match[2]) {
209
+ throw new Error(`Invalid derivation path: ${derivationPath}. ` +
210
+ `Expected format: {base}/{index} where base is one of: ` +
211
+ `${ALLOWED_HD_PATHS.join(', ')}.`);
212
+ }
213
+ const basePath = match[1];
214
+ const index = parseInt(match[2], 10);
215
+ // Validate the base path is one of the allowed paths
216
+ if (!ALLOWED_HD_PATHS.includes(basePath)) {
217
+ throw new Error(`Invalid derivation path: ${derivationPath}. ` +
218
+ `Expected format: {base}/{index} where base is one of: ` +
219
+ `${ALLOWED_HD_PATHS.join(', ')}.`);
220
+ }
221
+ return {
222
+ basePath: basePath,
223
+ index,
224
+ };
225
+ }, _TrezorKeyringV2_createKeyringAccount = function _TrezorKeyringV2_createKeyringAccount(address, addressIndex) {
226
+ const id = this.registry.register(address);
227
+ const derivationPath = `${this.inner.hdPath}/${addressIndex}`;
228
+ const account = {
229
+ id,
230
+ type: keyring_api_1.EthAccountType.Eoa,
231
+ address,
232
+ scopes: [...this.capabilities.scopes],
233
+ methods: [...TREZOR_KEYRING_METHODS],
234
+ options: {
235
+ entropy: {
236
+ type: keyring_api_1.KeyringAccountEntropyTypeOption.Mnemonic,
237
+ id: this.entropySource,
238
+ groupIndex: addressIndex,
239
+ derivationPath,
240
+ },
241
+ },
242
+ };
243
+ this.registry.set(account);
244
+ return account;
245
+ };
246
+ //# sourceMappingURL=trezor-keyring-v2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trezor-keyring-v2.cjs","sourceRoot":"","sources":["../src/trezor-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport type { Hex, Json } from '@metamask/utils';\n\nimport type { TrezorKeyring } from './trezor-keyring';\n\n/**\n * Methods supported by Trezor keyring EOA accounts.\n * Trezor keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).\n */\nconst TREZOR_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n];\n\nconst trezorKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n bip44: {\n deriveIndex: true,\n derivePath: true,\n },\n};\n\n/**\n * BIP-44 standard HD path prefix constant for Ethereum.\n * Used as default for derive-index operations.\n */\nexport const BIP44_HD_PATH_PREFIX = `m/44'/60'/0'/0`;\n\n/**\n * SLIP-0044 testnet HD path prefix constant.\n */\nexport const SLIP0044_TESTNET_PATH_PREFIX = `m/44'/1'/0'/0`;\n\n/**\n * Legacy MEW (MyEtherWallet) HD path prefix constant.\n */\nexport const LEGACY_MEW_PATH_PREFIX = `m/44'/60'/0'`;\n\n/**\n * Allowed HD paths for Trezor keyring.\n * These must match the keys in ALLOWED_HD_PATHS from trezor-keyring.ts.\n */\nconst ALLOWED_HD_PATHS = [\n BIP44_HD_PATH_PREFIX,\n SLIP0044_TESTNET_PATH_PREFIX,\n LEGACY_MEW_PATH_PREFIX,\n] as const;\n\n/**\n * Type representing one of the allowed Trezor HD paths.\n * Used by inner.setHdPath which expects one of these specific paths.\n */\ntype AllowedHdPath = (typeof ALLOWED_HD_PATHS)[number];\n\n/**\n * Regex pattern for validating and parsing Trezor derivation paths.\n * Matches BIP-44 style paths: m/44'/{coin}'/{segments}/{index}\n * where coin is 60' (Ethereum) or 1' (testnet).\n * Captures: [1] = base path prefix, [2] = index\n * The prefix is then validated against ALLOWED_HD_PATHS.\n */\nconst DERIVATION_PATH_PATTERN = /^(m\\/44'\\/(?:60'|1')(?:\\/\\d+'?)*)\\/(\\d+)$/u;\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link TrezorKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * Trezor keyring via the unified V2 interface.\n *\n * All Trezor keyring accounts are BIP-44 derived from the device.\n */\nexport type TrezorKeyringV2Options = {\n legacyKeyring: TrezorKeyring;\n entropySource: EntropySourceId;\n type?: KeyringType.Trezor | KeyringType.OneKey;\n};\n\n// TrezorKeyring.signTransaction returns `TypedTransaction | OldEthJsTransaction` for\n// backwards compatibility with old ethereumjs-tx, but EthKeyring expects `TypedTxData`.\n// The runtime behavior is correct - we cast the type to satisfy the constraint.\ntype TrezorKeyringAsEthKeyring = TrezorKeyring & EthKeyring;\n\nexport class TrezorKeyringV2\n extends EthKeyringWrapper<\n TrezorKeyringAsEthKeyring,\n Bip44Account<KeyringAccount>\n >\n implements KeyringV2\n{\n readonly entropySource: EntropySourceId;\n\n constructor(options: TrezorKeyringV2Options) {\n super({\n type: options.type ?? KeyringType.Trezor,\n inner: options.legacyKeyring as TrezorKeyringAsEthKeyring,\n capabilities: trezorKeyringV2Capabilities,\n });\n this.entropySource = options.entropySource;\n }\n\n /**\n * Hydrate the underlying keyring from a previously serialized state.\n *\n * Overrides the base class implementation to avoid calling `getAccounts()`\n * when the Trezor device is locked. The base class calls `getAccounts()` to\n * rebuild the registry, but for Trezor keyrings this requires the HDKey to\n * be initialized (via `unlock()`). Since the device may not be connected\n * during deserialization, we skip the registry rebuild here. The registry\n * will be populated on the first call to `getAccounts()` after the device\n * is unlocked.\n *\n * @param state - The serialized keyring state.\n */\n async deserialize(state: Json): Promise<void> {\n await this.withLock(async () => {\n // Clear the registry when deserializing\n this.registry.clear();\n\n // Deserialize the legacy keyring state only.\n // We intentionally skip calling getAccounts() here because the Trezor\n // device may be locked (HDKey not initialized). The TrezorKeyring's\n // deserialize restores the accounts array, but not the paths map, so\n // getIndexForAddress would need to derive addresses which requires an\n // initialized HDKey. The registry will be populated lazily when\n // getAccounts() is called after the device is unlocked.\n await this.inner.deserialize(state);\n });\n }\n\n /**\n * Parses a derivation path to extract the base HD path and account index.\n *\n * Supports the allowed Trezor paths:\n * - m/44'/60'/0'/0/{index} (BIP44 standard)\n * - m/44'/60'/0'/{index} (legacy MEW)\n * - m/44'/1'/0'/0/{index} (SLIP0044 testnet)\n *\n * @param derivationPath - The full derivation path (e.g., m/44'/60'/0'/0/5).\n * @returns The base HD path and account index.\n * @throws If the path format is invalid or not an allowed Trezor path.\n */\n #parseDerivationPath(derivationPath: string): {\n basePath: AllowedHdPath;\n index: number;\n } {\n const match = derivationPath.match(DERIVATION_PATH_PATTERN);\n if (!match?.[1] || !match[2]) {\n throw new Error(\n `Invalid derivation path: ${derivationPath}. ` +\n `Expected format: {base}/{index} where base is one of: ` +\n `${ALLOWED_HD_PATHS.join(', ')}.`,\n );\n }\n\n const basePath = match[1];\n const index = parseInt(match[2], 10);\n\n // Validate the base path is one of the allowed paths\n if (!ALLOWED_HD_PATHS.includes(basePath as AllowedHdPath)) {\n throw new Error(\n `Invalid derivation path: ${derivationPath}. ` +\n `Expected format: {base}/{index} where base is one of: ` +\n `${ALLOWED_HD_PATHS.join(', ')}.`,\n );\n }\n\n return {\n basePath: basePath as AllowedHdPath,\n index,\n };\n }\n\n /**\n * Creates a Bip44Account object for the given address.\n *\n * @param address - The account address.\n * @param addressIndex - The account index in the derivation path.\n * @returns The created Bip44Account.\n */\n #createKeyringAccount(\n address: Hex,\n addressIndex: number,\n ): Bip44Account<KeyringAccount> {\n const id = this.registry.register(address);\n const derivationPath = `${this.inner.hdPath}/${addressIndex}`;\n\n const account: Bip44Account<KeyringAccount> = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...TREZOR_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.Mnemonic,\n id: this.entropySource,\n groupIndex: addressIndex,\n derivationPath,\n },\n },\n };\n\n this.registry.set(account);\n return account;\n }\n\n async getAccounts(): Promise<Bip44Account<KeyringAccount>[]> {\n const addresses = await this.inner.getAccounts();\n\n if (addresses.length === 0) {\n return [];\n }\n\n // If the device is locked, we cannot derive addresses to find indices.\n // Return cached accounts if available, otherwise throw a clear error.\n if (!this.inner.isUnlocked()) {\n const cachedAccounts = addresses\n .map((address) => {\n const existingId = this.registry.getAccountId(address);\n return existingId ? this.registry.get(existingId) : undefined;\n })\n .filter(\n (account): account is Bip44Account<KeyringAccount> =>\n account !== undefined,\n );\n\n // If we have all accounts cached, return them\n if (cachedAccounts.length === addresses.length) {\n return cachedAccounts;\n }\n\n // Some accounts are not cached and device is locked\n throw new Error(\n 'Trezor device is locked. Please unlock the device to access accounts.',\n );\n }\n\n return addresses.map((address) => {\n // Check if we already have this account in the registry\n const existingId = this.registry.getAccountId(address);\n if (existingId) {\n const cached = this.registry.get(existingId);\n if (cached) {\n return cached;\n }\n }\n\n const addressIndex = this.inner.getIndexForAddress(address);\n return this.#createKeyringAccount(address, addressIndex);\n });\n }\n\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<Bip44Account<KeyringAccount>[]> {\n return this.withLock(async () => {\n if (\n options.type === 'bip44:derive-path' ||\n options.type === 'bip44:derive-index'\n ) {\n // Validate that the entropy source matches this keyring's entropy source\n if (options.entropySource !== this.entropySource) {\n throw new Error(\n `Entropy source mismatch: expected '${this.entropySource}', got '${options.entropySource}'`,\n );\n }\n } else {\n throw new Error(\n `Unsupported account creation type for TrezorKeyring: ${String(\n options.type,\n )}`,\n );\n }\n\n // Check if an account at this index already exists with the same derivation path\n const currentAccounts = await this.getAccounts();\n\n let targetIndex: number;\n let basePath: AllowedHdPath;\n let derivationPath: string;\n\n if (options.type === 'bip44:derive-path') {\n // Parse the derivation path to extract base path and index\n const parsed = this.#parseDerivationPath(options.derivationPath);\n targetIndex = parsed.index;\n basePath = parsed.basePath;\n // Use the normalized path to avoid mismatches with leading zeros\n // (e.g., \"m/44'/60'/0'/0/007\" becomes \"m/44'/60'/0'/0/7\")\n derivationPath = `${basePath}/${targetIndex}`;\n } else {\n // derive-index uses BIP-44 standard path by default\n if (options.groupIndex < 0) {\n throw new Error(\n `Invalid groupIndex: ${options.groupIndex}. Must be a non-negative integer.`,\n );\n }\n targetIndex = options.groupIndex;\n basePath = BIP44_HD_PATH_PREFIX;\n derivationPath = `${basePath}/${targetIndex}`;\n }\n\n const existingAccount = currentAccounts.find((account) => {\n return (\n account.options.entropy.groupIndex === targetIndex &&\n account.options.entropy.derivationPath === derivationPath\n );\n });\n\n if (existingAccount) {\n return [existingAccount];\n }\n\n // Derive the account at the specified index.\n // If the HD path is changing, clear the registry to avoid stale accounts.\n // The TrezorKeyring operates on a single path at a time - accounts from\n // different paths cannot coexist in the inner keyring.\n if (basePath !== this.inner.hdPath) {\n this.registry.clear();\n }\n\n this.inner.setHdPath(basePath);\n this.inner.setAccountToUnlock(targetIndex);\n const [newAddress] = await this.inner.addAccounts(1);\n\n if (!newAddress) {\n throw new Error('Failed to create new account');\n }\n\n const newAccount = this.#createKeyringAccount(newAddress, targetIndex);\n\n return [newAccount];\n });\n }\n\n /**\n * Delete an account from the keyring.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n const { address } = await this.getAccount(accountId);\n const hexAddress = this.toHexAddress(address);\n\n // Remove from the legacy keyring\n this.inner.removeAccount(hexAddress);\n\n // Remove from the registry\n this.registry.delete(accountId);\n });\n }\n}\n"]}
@@ -0,0 +1,61 @@
1
+ import type { Bip44Account } from "@metamask/account-api";
2
+ import { type CreateAccountOptions, EthKeyringWrapper, type KeyringAccount, type KeyringV2, KeyringType, type EntropySourceId } from "@metamask/keyring-api";
3
+ import type { AccountId, EthKeyring } from "@metamask/keyring-utils";
4
+ import type { Json } from "@metamask/utils";
5
+ import type { TrezorKeyring } from "./trezor-keyring.cjs";
6
+ /**
7
+ * BIP-44 standard HD path prefix constant for Ethereum.
8
+ * Used as default for derive-index operations.
9
+ */
10
+ export declare const BIP44_HD_PATH_PREFIX = "m/44'/60'/0'/0";
11
+ /**
12
+ * SLIP-0044 testnet HD path prefix constant.
13
+ */
14
+ export declare const SLIP0044_TESTNET_PATH_PREFIX = "m/44'/1'/0'/0";
15
+ /**
16
+ * Legacy MEW (MyEtherWallet) HD path prefix constant.
17
+ */
18
+ export declare const LEGACY_MEW_PATH_PREFIX = "m/44'/60'/0'";
19
+ /**
20
+ * Concrete {@link KeyringV2} adapter for {@link TrezorKeyring}.
21
+ *
22
+ * This wrapper exposes the accounts and signing capabilities of the legacy
23
+ * Trezor keyring via the unified V2 interface.
24
+ *
25
+ * All Trezor keyring accounts are BIP-44 derived from the device.
26
+ */
27
+ export type TrezorKeyringV2Options = {
28
+ legacyKeyring: TrezorKeyring;
29
+ entropySource: EntropySourceId;
30
+ type?: KeyringType.Trezor | KeyringType.OneKey;
31
+ };
32
+ type TrezorKeyringAsEthKeyring = TrezorKeyring & EthKeyring;
33
+ export declare class TrezorKeyringV2 extends EthKeyringWrapper<TrezorKeyringAsEthKeyring, Bip44Account<KeyringAccount>> implements KeyringV2 {
34
+ #private;
35
+ readonly entropySource: EntropySourceId;
36
+ constructor(options: TrezorKeyringV2Options);
37
+ /**
38
+ * Hydrate the underlying keyring from a previously serialized state.
39
+ *
40
+ * Overrides the base class implementation to avoid calling `getAccounts()`
41
+ * when the Trezor device is locked. The base class calls `getAccounts()` to
42
+ * rebuild the registry, but for Trezor keyrings this requires the HDKey to
43
+ * be initialized (via `unlock()`). Since the device may not be connected
44
+ * during deserialization, we skip the registry rebuild here. The registry
45
+ * will be populated on the first call to `getAccounts()` after the device
46
+ * is unlocked.
47
+ *
48
+ * @param state - The serialized keyring state.
49
+ */
50
+ deserialize(state: Json): Promise<void>;
51
+ getAccounts(): Promise<Bip44Account<KeyringAccount>[]>;
52
+ createAccounts(options: CreateAccountOptions): Promise<Bip44Account<KeyringAccount>[]>;
53
+ /**
54
+ * Delete an account from the keyring.
55
+ *
56
+ * @param accountId - The account ID to delete.
57
+ */
58
+ deleteAccount(accountId: AccountId): Promise<void>;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=trezor-keyring-v2.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trezor-keyring-v2.d.cts","sourceRoot":"","sources":["../src/trezor-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAEzB,iBAAiB,EAGjB,KAAK,cAAc,EAGnB,KAAK,SAAS,EACd,WAAW,EACX,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AACrE,OAAO,KAAK,EAAO,IAAI,EAAE,wBAAwB;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AAqBtD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,sBAAsB,iBAAiB,CAAC;AA2BrD;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;IAC/B,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;CAChD,CAAC;AAKF,KAAK,yBAAyB,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5D,qBAAa,eACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,SAAS;;IAEpB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,sBAAsB;IAS3C;;;;;;;;;;;;OAYG;IACG,WAAW,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA6FvC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IA8CtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAgF1C;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAYzD"}
@@ -0,0 +1,61 @@
1
+ import type { Bip44Account } from "@metamask/account-api";
2
+ import { type CreateAccountOptions, EthKeyringWrapper, type KeyringAccount, type KeyringV2, KeyringType, type EntropySourceId } from "@metamask/keyring-api";
3
+ import type { AccountId, EthKeyring } from "@metamask/keyring-utils";
4
+ import type { Json } from "@metamask/utils";
5
+ import type { TrezorKeyring } from "./trezor-keyring.mjs";
6
+ /**
7
+ * BIP-44 standard HD path prefix constant for Ethereum.
8
+ * Used as default for derive-index operations.
9
+ */
10
+ export declare const BIP44_HD_PATH_PREFIX = "m/44'/60'/0'/0";
11
+ /**
12
+ * SLIP-0044 testnet HD path prefix constant.
13
+ */
14
+ export declare const SLIP0044_TESTNET_PATH_PREFIX = "m/44'/1'/0'/0";
15
+ /**
16
+ * Legacy MEW (MyEtherWallet) HD path prefix constant.
17
+ */
18
+ export declare const LEGACY_MEW_PATH_PREFIX = "m/44'/60'/0'";
19
+ /**
20
+ * Concrete {@link KeyringV2} adapter for {@link TrezorKeyring}.
21
+ *
22
+ * This wrapper exposes the accounts and signing capabilities of the legacy
23
+ * Trezor keyring via the unified V2 interface.
24
+ *
25
+ * All Trezor keyring accounts are BIP-44 derived from the device.
26
+ */
27
+ export type TrezorKeyringV2Options = {
28
+ legacyKeyring: TrezorKeyring;
29
+ entropySource: EntropySourceId;
30
+ type?: KeyringType.Trezor | KeyringType.OneKey;
31
+ };
32
+ type TrezorKeyringAsEthKeyring = TrezorKeyring & EthKeyring;
33
+ export declare class TrezorKeyringV2 extends EthKeyringWrapper<TrezorKeyringAsEthKeyring, Bip44Account<KeyringAccount>> implements KeyringV2 {
34
+ #private;
35
+ readonly entropySource: EntropySourceId;
36
+ constructor(options: TrezorKeyringV2Options);
37
+ /**
38
+ * Hydrate the underlying keyring from a previously serialized state.
39
+ *
40
+ * Overrides the base class implementation to avoid calling `getAccounts()`
41
+ * when the Trezor device is locked. The base class calls `getAccounts()` to
42
+ * rebuild the registry, but for Trezor keyrings this requires the HDKey to
43
+ * be initialized (via `unlock()`). Since the device may not be connected
44
+ * during deserialization, we skip the registry rebuild here. The registry
45
+ * will be populated on the first call to `getAccounts()` after the device
46
+ * is unlocked.
47
+ *
48
+ * @param state - The serialized keyring state.
49
+ */
50
+ deserialize(state: Json): Promise<void>;
51
+ getAccounts(): Promise<Bip44Account<KeyringAccount>[]>;
52
+ createAccounts(options: CreateAccountOptions): Promise<Bip44Account<KeyringAccount>[]>;
53
+ /**
54
+ * Delete an account from the keyring.
55
+ *
56
+ * @param accountId - The account ID to delete.
57
+ */
58
+ deleteAccount(accountId: AccountId): Promise<void>;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=trezor-keyring-v2.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trezor-keyring-v2.d.mts","sourceRoot":"","sources":["../src/trezor-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAEzB,iBAAiB,EAGjB,KAAK,cAAc,EAGnB,KAAK,SAAS,EACd,WAAW,EACX,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AACrE,OAAO,KAAK,EAAO,IAAI,EAAE,wBAAwB;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AAqBtD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,sBAAsB,iBAAiB,CAAC;AA2BrD;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;IAC/B,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;CAChD,CAAC;AAKF,KAAK,yBAAyB,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5D,qBAAa,eACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,SAAS;;IAEpB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,sBAAsB;IAS3C;;;;;;;;;;;;OAYG;IACG,WAAW,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA6FvC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IA8CtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAgF1C;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAYzD"}