@onekeyfe/hwk-keystone-adapter 1.2.2-alpha.100 → 1.2.3-alpha.2

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/dist/index.d.mts CHANGED
@@ -1,4 +1,10 @@
1
- import { ChainCapability, IHardwareWallet, IConnector, TransportType, SearchDevicesOptions, DeviceInfo, Response, ChainForFingerprint, UiResponseEvent, HardwareEventMap, DeviceEventListener, AllNetworkGetAddressParams, AllNetworkAddressResponse, NullableCallArg, IHardwareCallParams, EvmGetAddressParams, EvmAddress, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature } from '@onekeyfe/hwk-adapter-core';
1
+ import { ChainCapability, DeviceInfo, IHardwareWallet, IConnector, TransportType, SearchDevicesOptions, DeviceSearchTarget, ConnectionTarget, Response, ChainForFingerprint, UiResponseEvent, HardwareEventMap, DeviceEventListener, AllNetworkGetAddressParams, AllNetworkAddressResponse, NullableCallArg, IHardwareCallParams, EvmGetAddressParams, EvmAddress, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, IHardwareCommonCallParams, SolGetAddressParams, SolAddress, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature } from '@onekeyfe/hwk-adapter-core';
2
+
3
+ /** Keystone `DataType`: 1 = transaction, 2 = personal message. */
4
+ declare enum TronSignType {
5
+ Transaction = 1,
6
+ PersonalMessage = 2
7
+ }
2
8
 
3
9
  /**
4
10
  * A UR payload in the wire shape the reserved `QrDisplayData`/`QrResponseData`
@@ -25,7 +31,7 @@ interface KeystoneParsedAccount {
25
31
  name?: string;
26
32
  }
27
33
  interface KeystoneParsedMultiAccounts {
28
- /** BIP32 master fingerprint of the seed (lowercase hex, 8 chars) the cross-channel wallet identity. */
34
+ /** BIP32 master fingerprint of the seed (lowercase hex, 8 chars) used as BC-UR xfp metadata. */
29
35
  masterFingerprint: string;
30
36
  /** Model string (e.g. "Keystone 3 Pro"), present on both channels but not unique per unit. */
31
37
  device?: string;
@@ -102,13 +108,16 @@ interface KeystoneKeyDerivationRequestInput {
102
108
  interface KeystoneTronSignRequestInput {
103
109
  requestId: string;
104
110
  /**
105
- * Hex, no 0x prefix a standard TRON protobuf `Transaction.raw` message
106
- * (the same bytes `TronSignTxParams.rawTxHex` already carries for Ledger).
111
+ * Hex, no 0x prefix. For a transaction: the TRON protobuf `Transaction.raw`
112
+ * bytes (same as `TronSignTxParams.rawTxHex`). For a personal message:
113
+ * the raw message bytes; the device applies the TIP-191 prefix itself.
107
114
  */
108
115
  rawTxHex: string;
109
116
  path: string;
110
117
  xfp: string;
111
118
  origin?: string;
119
+ /** Defaults to Transaction. */
120
+ signType?: TronSignType;
112
121
  }
113
122
  interface KeystoneTronSignatureResult {
114
123
  requestId?: string;
@@ -117,15 +126,9 @@ interface KeystoneTronSignatureResult {
117
126
  }
118
127
 
119
128
  /**
120
- * Thin wrapper around `@keystonehq/keystone-sdk`. Owns every touch point with the
121
- * vendor SDK so the rest of the adapter never imports it directly: same UR
122
- * construction/parsing serves both the QR and USB channels (USB carries the
123
- * identical UR payloads inside EAPDU framing — see the Keystone USB SDK's
124
- * `sendURRequest`), so this engine has no channel awareness at all.
125
- *
126
- * Deliberately uses the bare constructor, never `KeystoneSDK.create()` — `create()`
127
- * fetches remote fragment-size config from keyst.one at call time, which this SDK
128
- * must not depend on.
129
+ * Single touch point with `@keystonehq/keystone-sdk`; the same UR building
130
+ * and parsing serves QR and USB. Uses the bare constructor, not
131
+ * `KeystoneSDK.create()`, which fetches remote config at call time.
129
132
  */
130
133
  declare class KeystoneUrEngine {
131
134
  private readonly sdk;
@@ -189,6 +192,7 @@ declare class KeystoneUrEngine {
189
192
  * here needs no such library.
190
193
  */
191
194
  deriveBtcAddressFromXpub(xpub: string, relativeDerivePath: string, scriptType: BtcScriptType): string;
195
+ deriveBtcAddressFromPublicKey(publicKeyHex: string, scriptType: BtcScriptType): string;
192
196
  buildBtcPsbtRequest(unsignedPsbtHex: string): KeystoneUr;
193
197
  /** Returns the hex-encoded (possibly still-unsigned-in-part) PSBT the device replied with. */
194
198
  parseBtcPsbt(ur: KeystoneUr): string;
@@ -203,15 +207,8 @@ declare class KeystoneUrEngine {
203
207
  buildSolSignRequest(input: KeystoneSolSignRequestInput): KeystoneUr;
204
208
  parseSolSignature(ur: KeystoneUr): KeystoneSolSignatureResult;
205
209
  /**
206
- * `@keystonehq/keystone-sdk`'s own bundled `sdk.tron` module is
207
- * deliberately NOT used here see `TronSignRequest.ts`'s doc comment for
208
- * why: it's a different (gzip/protobuf) protocol with response semantics
209
- * this package has no way to verify, whereas `TronSignRequest`/
210
- * `TronSignature` are a direct port of OneKey's own already-proven
211
- * production QR-wallet TRON implementation (a plain CBOR-native
212
- * sign-request/signature pair, same shape as eth/sol). The device decodes
213
- * `rawTxHex` itself — no client-side contract-type pre-parsing or
214
- * `tokenInfo` needed, unlike the public SDK's module.
210
+ * Keystone's native tron-sign-request/tron-signature pair (bare signature).
211
+ * `sdk.tron` from keystone-sdk is the older protobuf envelope; not used.
215
212
  */
216
213
  buildTronSignRequest(input: KeystoneTronSignRequestInput): KeystoneUr;
217
214
  parseTronSignature(ur: KeystoneUr): KeystoneTronSignatureResult;
@@ -225,54 +222,112 @@ declare class KeystoneUrEngine {
225
222
  * strip its "0x" and re-encode the same 20 bytes.
226
223
  */
227
224
  deriveTronAddressFromXpub(xpub: string, relativeDerivePath: string): string;
225
+ /**
226
+ * Split an account-level xpub back into the BIP-32 fields a host needs to
227
+ * treat it as a real extended key (`BtcPublicKey`). Everything here is
228
+ * carried inside the xpub's own serialization — depth, the PARENT key
229
+ * fingerprint (not the seed's master fingerprint), the chain code and the
230
+ * compressed public key — so this is a pure decode with no device round
231
+ * trip; the xpub itself was already device-verified when it was synced.
232
+ */
233
+ parseXpubMeta(xpub: string): {
234
+ publicKey: string;
235
+ chainCode: string;
236
+ depth: number;
237
+ parentFingerprint: number;
238
+ };
239
+ }
240
+
241
+ declare const KEYSTONE_WALLET_CONNECT_ID_PREFIX = "keystone-wallet:";
242
+ /** Fixed public source used to derive a collision-resistant wallet id. */
243
+ declare const KEYSTONE_WALLET_ID_PATH = "m/44'/60'/0'";
244
+ declare function walletConnectId(walletId: string): string;
245
+ interface KeystoneAccountEntry extends KeystoneParsedAccount {
246
+ hwkChain: ChainCapability;
228
247
  }
248
+ declare function accountKey(hwkChain: ChainCapability, path: string): string;
249
+ interface KeystoneDeviceRecord {
250
+ /** SHA-256 id derived from the fixed account-level identity xpub. */
251
+ walletId: string;
252
+ /** Lowercase 8-char BIP32 fingerprint used by BC-UR as xfp, never as identity. */
253
+ masterFingerprint: string;
254
+ connectId: string;
255
+ /** Optional physical-device id exposed by some Keystone QR export menus. */
256
+ hardwareDeviceId?: string;
257
+ /** Model string from the device (e.g. "Keystone 3 Pro"); not unique per unit. */
258
+ model?: string;
259
+ deviceVersion?: string;
260
+ importedAt: number;
261
+ /**
262
+ * Set to the connector's process-local `sessionId` once a live USB session exists for
263
+ * this wallet. Cleared by `releaseOperation`. Presence of this field is
264
+ * what `KeystoneAdapter._resolveUr` uses to route a call over USB instead
265
+ * of QR.
266
+ */
267
+ usbSessionId?: string;
268
+ /**
269
+ * Remains true after a live USB session is lost. It allows the adapter to
270
+ * wait through the device's short USB re-enumeration window without making
271
+ * wallets that have only ever used QR pay the same retry delay.
272
+ */
273
+ hadUsbSession?: boolean;
274
+ /**
275
+ * True once this wallet has completed at least one QR round trip.
276
+ * Distinguishes "USB session dropped but this wallet was also QR-synced —
277
+ * fall back to a QR-only entry" from "this was a USB-only wallet that
278
+ * never synced over QR — drop the entry entirely" on USB disconnect.
279
+ */
280
+ qrSynced?: boolean;
281
+ }
282
+ declare function deriveKeystoneWalletId(accounts: KeystoneParsedAccount[]): string;
283
+ declare function createDeviceRecord(walletId: string, masterFingerprint: string): KeystoneDeviceRecord;
284
+ declare function toDeviceInfo(record: KeystoneDeviceRecord): DeviceInfo;
285
+ /** A device row for a wallet the adapter hasn't synced yet — used while a cold-start round trip is in flight. */
286
+ declare function placeholderDeviceInfo(): DeviceInfo;
229
287
 
288
+ /** Key material for one operation, keyed by `accountKey()`; never retained. */
289
+ type AccountBook = Map<string, KeystoneAccountEntry>;
230
290
  interface ImportFromQrOptions {
231
291
  /**
232
- * 'request': host asks for specific paths via a `qr-hardware-call`
233
- * (KeyDerivation) UR precise, works regardless of what screen the device
234
- * is on. 'scan': just wait for whatever multi-account/HD-key export the
235
- * device is already showing. Defaults to 'request' with `paths`, or the
236
- * default EVM/BTC/SOL account set if `paths` is omitted.
292
+ * 'request': ask the device for the fixed identity xpub via a
293
+ * `qr-hardware-call` (KeyDerivation) UR. 'scan': just wait for whatever
294
+ * multi-account/HD-key export the device is already showing. Either way
295
+ * only the wallet identity is learned; key material is never retained.
237
296
  */
238
297
  mode?: 'request' | 'scan';
239
- paths?: Array<{
240
- hwkChain: ChainCapability;
241
- path: string;
242
- }>;
243
298
  }
244
299
  /**
245
- * Keystone hardware wallet adapter QR and USB channels merged behind one
246
- * `IHardwareWallet` surface, keyed by the wallet's master fingerprint (mfp):
247
- * a caller sees the same `evmSignTransaction(...)` call regardless of which
248
- * channel actually carries it. Internally, a chain method's UR round trip
249
- * either drives one or two `REQUEST_QR_DISPLAY`/`REQUEST_QR_SCAN` UI events
250
- * (QR) or a direct `IConnector.call(sessionId, 'resolveUr', ur)` (USB) — see
251
- * `_resolveUr`.
252
- *
253
- * QR needs no physical enumeration or explicit connect step: a caller can
254
- * call any chain method with `connectId`/`deviceId` both null and the
255
- * adapter drives its own implicit cold-start sync. USB is the opposite —
256
- * WebUSB device pickers require a user gesture, so a USB session only comes
257
- * into existence via an explicit `searchDevices()` + `connectDevice()` (see
258
- * `_connectUsb`). Once a USB session exists for a wallet's mfp, later calls
259
- * for that same wallet route over USB automatically (unless pinned via
260
- * `switchTransport`) — matching docs/design/keystone-integration/README.md §4.3.
300
+ * Keystone adapter: QR and USB behind one `IHardwareWallet`, keyed by a
301
+ * wallet id derived from the fixed identity xpub. `_resolveUr` picks the
302
+ * channel per request (USB when a session exists, else QR). Key material
303
+ * is fetched per operation and never retained on the wallet record.
261
304
  */
262
305
  declare class KeystoneAdapter implements IHardwareWallet {
263
306
  readonly vendor: "keystone";
264
307
  private readonly urEngine;
265
308
  private readonly emitter;
309
+ private readonly _operationRoutes;
310
+ private readonly _operations;
266
311
  private readonly _uiRegistry;
267
312
  private readonly _jobQueue;
268
313
  private readonly _devices;
314
+ private readonly _searchDeviceTargets;
315
+ private _activeSearchGeneration;
269
316
  private readonly _origin;
270
317
  /** How long to wait for the app to answer a `REQUEST_QR_DISPLAY`/`REQUEST_QR_SCAN` before failing. Defaults to the registry's own 10-minute default. */
271
318
  private readonly _qrTimeoutMs;
272
319
  /** Optional USB `IConnector` — supplied by the host app (DI, same pattern as Trezor/Ledger), e.g. via `createKeystoneWebUsbConnector()` from `@onekeyfe/hwk-keystone-connector-usb`. Undefined means QR-only. */
273
320
  private readonly _usbConnector;
321
+ /** Serializes USB open/identity handshakes that run outside the job queue. */
322
+ private _usbConnectTail;
323
+ private readonly _unsettledUsbOperations;
324
+ private readonly _usbIdleWaiters;
325
+ private _usbTeardownTail;
326
+ private _pendingUsbTeardowns;
274
327
  /** Explicit `switchTransport` pin. `undefined` means "auto": USB when a live session exists for the target wallet, else QR. */
275
328
  private _forcedTransport;
329
+ private readonly _handleUsbDisconnect;
330
+ private readonly _handleUsbUiEvent;
276
331
  constructor(options?: {
277
332
  origin?: string;
278
333
  qrTimeoutMs?: number;
@@ -285,16 +340,20 @@ declare class KeystoneAdapter implements IHardwareWallet {
285
340
  init(_config?: unknown): Promise<void>;
286
341
  dispose(): Promise<void>;
287
342
  /**
288
- * QR-synced wallets are always included (this instance's own state — no
289
- * enumeration exists for QR). When a USB connector is configured, its raw
290
- * scan results are appended as-is: a USB descriptor has no mfp until
291
- * `connectDevice()` actually opens+claims it (see
343
+ * Unscoped discovery includes QR-synced wallets already known to this
344
+ * adapter. Explicit QR discovery returns a virtual connection target because
345
+ * there is no physical descriptor to enumerate. When a USB connector is
346
+ * configured, its raw scan results are appended as-is: a USB descriptor has
347
+ * no mfp until `connectDevice()` actually opens+claims it (see
292
348
  * `KeystoneUsbConnectorBase.searchDevices`), so these entries carry an
293
349
  * empty `deviceId` and exist purely so a host can list "plugged in, click
294
350
  * to connect" candidates.
295
351
  */
296
- searchDevices(_options?: SearchDevicesOptions): Promise<DeviceInfo[]>;
297
- connectDevice(connectId: string): Promise<Response<string>>;
352
+ searchDevices(options?: SearchDevicesOptions): Promise<DeviceInfo[]>;
353
+ private _resetUsbSessions;
354
+ searchDeviceTargets(options?: SearchDevicesOptions): Promise<DeviceSearchTarget[]>;
355
+ listConnectionTargets(options?: SearchDevicesOptions): Promise<ConnectionTarget[]>;
356
+ connectDevice(searchTargetId: string): Promise<Response<string>>;
298
357
  /**
299
358
  * QR has no persistent connection to tear down — the account cache
300
359
  * survives so a later call resumes without re-syncing. For a USB session,
@@ -302,9 +361,9 @@ declare class KeystoneAdapter implements IHardwareWallet {
302
361
  * QR-only (if it was ever QR-synced) or removes it entirely (pure-USB
303
362
  * wallet that was never seen over QR) — see §4.2 of the design doc.
304
363
  */
305
- disconnectDevice(connectId: string): Promise<void>;
306
- getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>>;
307
- getSupportedChains(): ChainCapability[];
364
+ releaseOperation(operationId: string): Promise<void>;
365
+ private _releaseOperationConnection;
366
+ getDeviceInfo(connectIdOrOperationId: string, deviceId: string): Promise<Response<DeviceInfo>>;
308
367
  cancel(connectId?: string): void;
309
368
  getChainFingerprint(connectId: string, deviceId: string, chain: ChainForFingerprint): Promise<Response<string>>;
310
369
  uiResponse(response: UiResponseEvent): void;
@@ -314,32 +373,48 @@ declare class KeystoneAdapter implements IHardwareWallet {
314
373
  off(event: string, listener: DeviceEventListener): void;
315
374
  importFromQr(options?: ImportFromQrOptions): Promise<Response<DeviceInfo>>;
316
375
  allNetworkGetAddress: (connectId: string, deviceId: string, params: AllNetworkGetAddressParams) => Promise<Response<AllNetworkAddressResponse[]>>;
317
- evmGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<EvmGetAddressParams>>): Promise<Response<EvmAddress>>;
376
+ evmGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<EvmGetAddressParams>>, book?: AccountBook): Promise<Response<EvmAddress>>;
318
377
  evmSignTransaction(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<EvmSignTxParams>>): Promise<Response<EvmSignedTx>>;
319
378
  evmSignMessage(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<EvmSignMsgParams>>): Promise<Response<EvmSignature>>;
320
379
  evmSignTypedData(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<EvmSignTypedDataParams>>): Promise<Response<EvmSignature>>;
321
- btcGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<BtcGetAddressParams>>): Promise<Response<BtcAddress>>;
322
- btcGetPublicKey(_connectId?: NullableCallArg<string>, _deviceId?: NullableCallArg<string>, _params?: NullableCallArg<IHardwareCallParams<BtcGetPublicKeyParams>>): Promise<Response<BtcPublicKey>>;
380
+ btcGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<BtcGetAddressParams>>, book?: AccountBook): Promise<Response<BtcAddress>>;
381
+ /**
382
+ * Returns the account-level extended public key. `params.path` must be an
383
+ * ACCOUNT path (`m/84'/0'/0'`), not a leaf — that is the level Keystone
384
+ * actually syncs, and it is what a host needs to derive a whole account's
385
+ * addresses offline. Unlike `btcGetAddress` this has no script-type
386
+ * restriction: an xpub is script-type agnostic, so `86'` (taproot) works
387
+ * here even though deriving a taproot ADDRESS still needs an EC library
388
+ * this package doesn't wire in.
389
+ */
390
+ btcGetPublicKey(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<BtcGetPublicKeyParams>>, book?: AccountBook): Promise<Response<BtcPublicKey>>;
323
391
  btcSignTransaction(_connectId?: NullableCallArg<string>, _deviceId?: NullableCallArg<string>, _params?: NullableCallArg<IHardwareCallParams<BtcSignTxParams>>): Promise<Response<BtcSignedTx>>;
324
392
  btcSignPsbt(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<BtcSignPsbtParams>>): Promise<Response<BtcSignedPsbt>>;
325
393
  btcSignMessage(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<BtcSignMsgParams>>): Promise<Response<BtcSignature>>;
326
- btcGetMasterFingerprint(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>): Promise<Response<{
394
+ btcGetMasterFingerprint(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCommonCallParams>): Promise<Response<{
327
395
  masterFingerprint: string;
328
396
  }>>;
329
- solGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<SolGetAddressParams>>): Promise<Response<SolAddress>>;
397
+ solGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<SolGetAddressParams>>, book?: AccountBook): Promise<Response<SolAddress>>;
330
398
  solSignTransaction(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<SolSignTxParams>>): Promise<Response<SolSignedTx>>;
331
399
  solSignMessage(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<SolSignMsgParams>>): Promise<Response<SolSignature>>;
332
- tronGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<TronGetAddressParams>>): Promise<Response<TronAddress>>;
400
+ tronGetAddress(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<TronGetAddressParams>>, book?: AccountBook): Promise<Response<TronAddress>>;
333
401
  tronSignTransaction(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<TronSignTxParams>>): Promise<Response<TronSignedTx>>;
334
- tronSignMessage(_connectId?: NullableCallArg<string>, _deviceId?: NullableCallArg<string>, _params?: NullableCallArg<IHardwareCallParams<TronSignMsgParams>>): Promise<Response<TronSignature>>;
335
- private _mfpFromConnectId;
402
+ tronSignMessage(connectIdArg?: NullableCallArg<string>, deviceIdArg?: NullableCallArg<string>, paramsArg?: NullableCallArg<IHardwareCallParams<TronSignMsgParams>>): Promise<Response<TronSignature>>;
403
+ private _walletIdFromIdentifier;
404
+ private _allNetworkSyncSchema;
405
+ /**
406
+ * QR is an interactive batch transport: one account-creation action must
407
+ * produce one request QR and one response scan, regardless of how many
408
+ * chains or derivation paths the host bundled. USB keeps its proven
409
+ * one-path-at-a-time export flow because the device limits that channel.
410
+ */
411
+ private _prefetchAllNetworkAccounts;
336
412
  /**
337
- * Handles both connectId shapes a caller might hand back: the QR-style
338
- * `keystone-qr:<mfp>` prefix, and a bare mfp which is exactly what a
339
- * USB session's `sessionId`/`connectId` is (see `KeystoneUsbConnectorBase`
340
- * and `_connectUsb`).
413
+ * Resolve only the stable 64-hex wallet identity. The 8-hex BIP32 master
414
+ * fingerprint is protocol metadata and is never accepted as a lookup key.
341
415
  */
342
- private _findByConnectId;
416
+ private _resolveTarget;
417
+ private _assertParsedIdentity;
343
418
  /**
344
419
  * Folds a parsed account-response UR into the device table. `viaUsb`
345
420
  * (defaults false) says which channel actually carried this round trip —
@@ -347,99 +422,77 @@ declare class KeystoneAdapter implements IHardwareWallet {
347
422
  * already has a live session, so this must NOT unconditionally mark
348
423
  * `qrSynced`, or a USB-only wallet would wrongly survive a later USB
349
424
  * disconnect as a "QR-synced, demote to QR-only" entry instead of being
350
- * dropped outright (see `disconnectDevice`).
425
+ * dropped outright (see `releaseOperation`).
351
426
  */
352
427
  private _upsertDeviceRecord;
353
428
  /**
354
429
  * Opens+claims whatever Keystone the USB connector currently has
355
- * permission for, learns its mfp via `getAppConfig`, and merges it into
356
- * the device table by that mfp a QR-synced entry becomes
430
+ * permission for, learns its protocol mfp via `getAppConfig`, then requests
431
+ * one fixed account-level xpub and derives the stable wallet id. A
432
+ * QR-synced entry becomes
357
433
  * `{qr, usb}`-capable in place (one `device-changed`, not a second
358
434
  * `device-connect`); a wallet never seen before becomes a new USB-only
359
435
  * entry. See §4.2 of the design doc.
360
436
  */
361
437
  private _connectUsb;
438
+ private _connectUsbExclusive;
439
+ /**
440
+ * Probe already-authorized USB devices without opening a permission picker,
441
+ * then attach and verify the requested wallet when one is present. This is
442
+ * used both after an adapter restart and after a QR-only period, so plugging
443
+ * USB back in affects the next business call without changing an in-flight
444
+ * QR operation.
445
+ */
446
+ private _tryUsbAttach;
362
447
  /**
363
448
  * The one place that decides QR vs. USB for a UR round trip and carries it
364
449
  * out. `record` is the (possibly not-yet-existing, for a true cold start)
365
- * device row for the target wallet USB is only used when `record`
366
- * already has a live `usbSessionId` (a session comes from an explicit
367
- * `connectDevice()`, never conjured mid-call see the class doc). A
450
+ * device row for the target wallet. USB is the preferred channel: a known
451
+ * wallet record with no live session gets ONE best-effort re-attach here,
452
+ * and anything that goes wrong just leaves the call on QR. A
368
453
  * `switchTransport('qr')` pin forces QR even for a USB-attached wallet;
369
454
  * `switchTransport('usb')` on a wallet with no live USB session fails
370
455
  * closed rather than silently falling back to QR.
371
456
  */
372
457
  private _resolveUr;
458
+ private _resolveUrWithRoute;
373
459
  /**
374
- * Resolve (syncing over QR if needed) the account cached for `hwkChain` at
375
- * `syncPath`. Drives the "implicit account sync, then the real request" two
376
- * hop flow the first time a wallet/path pair is seen; a cache hit skips
377
- * straight to the caller's own round trip.
460
+ * Fetch one account's key material from the device for this operation only.
461
+ * `book` lets earlier fetches of the same operation be reused; nothing is
462
+ * retained on the record. A failed USB export ends this operation without
463
+ * replaying the request or switching transports.
378
464
  */
379
- private _ensureAccountSynced;
465
+ private _fetchAccount;
380
466
  /**
381
- * Like `_ensureAccountSynced`, but for operations (PSBT signing, master
467
+ * Like `_fetchAccount`, but for operations (PSBT signing, master
382
468
  * fingerprint) that only need to know WHICH wallet is attached, not a
383
469
  * specific cached path. Syncs the account-level path for `chain` as a
384
- * throwaway probe when the mfp isn't already known.
470
+ * throwaway probe when the wallet record isn't already known.
385
471
  *
386
472
  * `CHAIN_FINGERPRINT_PATHS[chain]` is a 5-segment LEAF path for `evm`
387
473
  * (`m/44'/60'/0'/0/0`) — sending that verbatim as a KeyDerivation request
388
474
  * asks Keystone for a non-standard path. Keystone's own docs
389
475
  * (dev.keyst.one's multichain KeyDerivation example) show the ETH
390
476
  * account-level path as `m/44'/60'/0'` (3 segments), same as what
391
- * `DEFAULT_IMPORT_SCHEMAS`/`_ensureAccountSynced` already request — so
477
+ * `_fetchAccount` already requests — so
392
478
  * truncate through `splitAccountPath` here too instead of using the raw
393
479
  * fingerprint leaf path. `btc`/`sol` are already 3-segment account paths
394
480
  * and pass through unchanged.
395
481
  */
396
- private _ensureMfpKnown;
482
+ private _ensureWalletKnown;
397
483
  private _requestQrDisplayAndAwaitResponse;
398
484
  private _requestQrScanAndAwaitResponse;
485
+ private _callUsbConnector;
486
+ private _runUsbTeardown;
487
+ private _waitForUsbOperationsToDrain;
488
+ private _retainUsbOperation;
489
+ private static _abortable;
399
490
  private static _throwIfAborted;
400
491
  private static _assertRequestIdMatches;
401
492
  private _unsupported;
402
493
  private _errorToFailure;
403
494
  }
404
495
 
405
- /** `keystone-qr:<mfp>` is the QR-only connectId; a merged USB session gets its own (phase 4). */
406
- declare const QR_CONNECT_ID_PREFIX = "keystone-qr:";
407
- declare function qrConnectId(masterFingerprint: string): string;
408
- interface KeystoneAccountEntry extends KeystoneParsedAccount {
409
- hwkChain: ChainCapability;
410
- }
411
- declare function accountKey(hwkChain: ChainCapability, path: string): string;
412
- interface KeystoneDeviceRecord {
413
- /** Lowercase hex BIP32 master fingerprint — the cross-channel wallet identity; doubles as `deviceId`. */
414
- masterFingerprint: string;
415
- connectId: string;
416
- /** Model string from the device (e.g. "Keystone 3 Pro"); not unique per unit. */
417
- model?: string;
418
- deviceVersion?: string;
419
- /** Keyed by `accountKey(hwkChain, path)`. Holds whatever was directly synced — usually account-level (3-segment) entries for EVM, exact leaf entries for SOL. */
420
- accounts: Map<string, KeystoneAccountEntry>;
421
- importedAt: number;
422
- /**
423
- * Set to the connector's `sessionId` (== this record's own mfp, per
424
- * `KeystoneUsbConnectorBase.connect`) once a live USB session exists for
425
- * this wallet. Cleared by `disconnectDevice`. Presence of this field is
426
- * what `KeystoneAdapter._resolveUr` uses to route a call over USB instead
427
- * of QR.
428
- */
429
- usbSessionId?: string;
430
- /**
431
- * True once this wallet has completed at least one QR round trip.
432
- * Distinguishes "USB session dropped but this wallet was also QR-synced —
433
- * fall back to a QR-only entry" from "this was a USB-only wallet that
434
- * never synced over QR — drop the entry entirely" on USB disconnect.
435
- */
436
- qrSynced?: boolean;
437
- }
438
- declare function createDeviceRecord(masterFingerprint: string): KeystoneDeviceRecord;
439
- declare function toDeviceInfo(record: KeystoneDeviceRecord): DeviceInfo;
440
- /** A device row for a wallet the adapter hasn't synced yet — used while a cold-start round trip is in flight. */
441
- declare function placeholderDeviceInfo(): DeviceInfo;
442
-
443
496
  /** Always returns an `m/`-prefixed path, regardless of the input's casing/prefix. */
444
497
  declare function normalizePath(path: string): string;
445
498
  /**
@@ -465,4 +518,4 @@ declare function splitAccountPath(path: string): {
465
518
  */
466
519
  declare function btcScriptTypeFromPath(path: string): BtcScriptType | undefined;
467
520
 
468
- export { type BtcScriptType, type ImportFromQrOptions, type KeystoneAccountEntry, KeystoneAdapter, type KeystoneBtcSignRequestAccount, type KeystoneBtcSignatureResult, type KeystoneDerivationCurve, type KeystoneDeviceRecord, type KeystoneEthSignRequestInput, type KeystoneEthSignatureResult, type KeystoneKeyDerivationRequestInput, type KeystoneKeySchema, type KeystoneParsedAccount, type KeystoneParsedMultiAccounts, type KeystoneSolSignRequestInput, type KeystoneSolSignatureResult, type KeystoneTronSignRequestInput, type KeystoneTronSignatureResult, type KeystoneUr, KeystoneUrEngine, QR_CONNECT_ID_PREFIX, accountKey, btcScriptTypeFromPath, createDeviceRecord, normalizePath, placeholderDeviceInfo, qrConnectId, splitAccountPath, toDeviceInfo };
521
+ export { type BtcScriptType, type ImportFromQrOptions, KEYSTONE_WALLET_CONNECT_ID_PREFIX, KEYSTONE_WALLET_ID_PATH, type KeystoneAccountEntry, KeystoneAdapter, type KeystoneBtcSignRequestAccount, type KeystoneBtcSignatureResult, type KeystoneDerivationCurve, type KeystoneDeviceRecord, type KeystoneEthSignRequestInput, type KeystoneEthSignatureResult, type KeystoneKeyDerivationRequestInput, type KeystoneKeySchema, type KeystoneParsedAccount, type KeystoneParsedMultiAccounts, type KeystoneSolSignRequestInput, type KeystoneSolSignatureResult, type KeystoneTronSignRequestInput, type KeystoneTronSignatureResult, type KeystoneUr, KeystoneUrEngine, accountKey, btcScriptTypeFromPath, createDeviceRecord, deriveKeystoneWalletId, normalizePath, placeholderDeviceInfo, splitAccountPath, toDeviceInfo, walletConnectId };