@onekeyfe/hwk-ledger-adapter 1.1.26-alpha.10

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.
@@ -0,0 +1,628 @@
1
+ import { IHardwareWallet, IConnector, TransportType, UiResponseEvent, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, ProgressCallback, 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, HardwareEventMap, DeviceEventListener, ChainForFingerprint, ConnectionType, DeviceDescriptor, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, DeviceChangeEvent, Failure, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
2
+ import { DeviceManagementKit, DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType } from '@ledgerhq/device-management-kit';
3
+ import { Address, Signature, SignerEth as SignerEth$1, TypedData } from '@ledgerhq/device-signer-kit-ethereum';
4
+ import { SignerBtc as SignerBtc$1 } from '@ledgerhq/device-signer-kit-bitcoin';
5
+ import { SignerSolana } from '@ledgerhq/device-signer-kit-solana';
6
+ import Transport from '@ledgerhq/hw-transport';
7
+
8
+ interface LedgerAdapterOptions {
9
+ /**
10
+ * `true` — emit `REQUEST_SELECT_DEVICE` on multi-device discovery and await
11
+ * `uiResponse({ type: RECEIVE_SELECT_DEVICE, payload: { sdkConnectId } })`.
12
+ * `false` (default) — silently pick the first device.
13
+ */
14
+ handleSelectDevice?: boolean;
15
+ }
16
+ /**
17
+ * Ledger hardware wallet adapter that delegates to an IConnector.
18
+ *
19
+ * This is a thin translation layer that:
20
+ * - Accepts a pre-configured IConnector (transport decisions are made at connector creation time)
21
+ * - Translates IHardwareWallet method calls to connector.call() invocations
22
+ * - Maps connector results/errors to our Response<T> format with enriched error messages
23
+ * - Translates connector events to HardwareEventMap events
24
+ * - Emits `REQUEST_DEVICE_PERMISSION` for OS-level permission checks
25
+ */
26
+ declare class LedgerAdapter implements IHardwareWallet {
27
+ readonly vendor: "ledger";
28
+ private readonly connector;
29
+ private readonly emitter;
30
+ private readonly _handleSelectDevice;
31
+ private _discoveredDevices;
32
+ private _sessions;
33
+ private readonly _uiRegistry;
34
+ private readonly _jobQueue;
35
+ constructor(connector: IConnector, options?: LedgerAdapterOptions);
36
+ /**
37
+ * Classify a method's interruptibility.
38
+ * - Signing / typed data / transaction → 'confirm' (user may decide via preemption UI)
39
+ * - Read-only queries (getAddress / getPublicKey / getMasterFingerprint) → 'safe'
40
+ * (auto-cancels any pending read for the same device)
41
+ */
42
+ private static _getInterruptibility;
43
+ get activeTransport(): TransportType | null;
44
+ getAvailableTransports(): TransportType[];
45
+ switchTransport(_type: TransportType): Promise<void>;
46
+ init(_config?: unknown): Promise<void>;
47
+ /**
48
+ * Clear cached device/session state without tearing down the adapter.
49
+ * Call before retrying after errors or when the device state may be stale.
50
+ * The next operation will re-discover and re-connect automatically.
51
+ */
52
+ resetState(): void;
53
+ dispose(): Promise<void>;
54
+ uiResponse(response: UiResponseEvent): void;
55
+ searchDevices(): Promise<DeviceInfo[]>;
56
+ connectDevice(connectId: string): Promise<Response<string>>;
57
+ disconnectDevice(connectId: string): Promise<void>;
58
+ getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>>;
59
+ getSupportedChains(): ChainCapability[];
60
+ private callChain;
61
+ /**
62
+ * Batch version of callChain — checks permission once,
63
+ * fingerprint is verified on the first call inside connectorCall.
64
+ */
65
+ private callChainBatch;
66
+ evmGetAddress(connectId: string, deviceId: string, params: EvmGetAddressParams): Promise<Response<EvmAddress>>;
67
+ evmGetAddresses(connectId: string, deviceId: string, params: EvmGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<EvmAddress[]>>;
68
+ evmSignTransaction(connectId: string, deviceId: string, params: EvmSignTxParams): Promise<Response<EvmSignedTx>>;
69
+ evmSignMessage(connectId: string, deviceId: string, params: EvmSignMsgParams): Promise<Response<EvmSignature>>;
70
+ evmSignTypedData(connectId: string, deviceId: string, params: EvmSignTypedDataParams): Promise<Response<EvmSignature>>;
71
+ btcGetAddress(connectId: string, deviceId: string, params: BtcGetAddressParams): Promise<Response<BtcAddress>>;
72
+ btcGetAddresses(connectId: string, deviceId: string, params: BtcGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<BtcAddress[]>>;
73
+ btcGetPublicKey(connectId: string, deviceId: string, params: BtcGetPublicKeyParams): Promise<Response<BtcPublicKey>>;
74
+ btcSignTransaction(connectId: string, deviceId: string, params: BtcSignTxParams): Promise<Response<BtcSignedTx>>;
75
+ btcSignPsbt(connectId: string, deviceId: string, params: BtcSignPsbtParams): Promise<Response<BtcSignedPsbt>>;
76
+ btcSignMessage(connectId: string, deviceId: string, params: BtcSignMsgParams): Promise<Response<BtcSignature>>;
77
+ btcGetMasterFingerprint(connectId: string, deviceId: string): Promise<Response<{
78
+ masterFingerprint: string;
79
+ }>>;
80
+ solGetAddress(connectId: string, deviceId: string, params: SolGetAddressParams): Promise<Response<SolAddress>>;
81
+ solGetAddresses(connectId: string, deviceId: string, params: SolGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<SolAddress[]>>;
82
+ solSignTransaction(connectId: string, deviceId: string, params: SolSignTxParams): Promise<Response<SolSignedTx>>;
83
+ solSignMessage(connectId: string, deviceId: string, params: SolSignMsgParams): Promise<Response<SolSignature>>;
84
+ tronGetAddress(connectId: string, deviceId: string, params: TronGetAddressParams): Promise<Response<TronAddress>>;
85
+ tronGetAddresses(connectId: string, deviceId: string, params: TronGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<TronAddress[]>>;
86
+ tronSignTransaction(connectId: string, deviceId: string, params: TronSignTxParams): Promise<Response<TronSignedTx>>;
87
+ tronSignMessage(connectId: string, deviceId: string, params: TronSignMsgParams): Promise<Response<TronSignature>>;
88
+ on<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;
89
+ on(event: string, listener: DeviceEventListener): void;
90
+ off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;
91
+ off(event: string, listener: DeviceEventListener): void;
92
+ cancel(connectId: string): void;
93
+ getChainFingerprint(connectId: string, deviceId: string, chain: ChainForFingerprint): Promise<Response<string>>;
94
+ /**
95
+ * Verify fingerprint using an existing sessionId directly.
96
+ * Safe to call inside connectorCall without causing queue deadlock.
97
+ */
98
+ private _verifyDeviceFingerprintWithSession;
99
+ /**
100
+ * Compute the chain fingerprint via a caller-supplied call strategy.
101
+ *
102
+ * Chains with a native device-side identity primitive (BTC → BIP32 master
103
+ * fingerprint) short-circuit at the top and return it verbatim, so the value
104
+ * stays reusable for higher-level use (BIP380 descriptors, PSBT signing).
105
+ *
106
+ * All other chains derive a fixed-path address and run it through
107
+ * `deriveDeviceFingerprint` to produce an opaque seed identifier.
108
+ *
109
+ * The two callers (`getChainFingerprint` / `_verifyDeviceFingerprintWithSession`)
110
+ * differ only in the underlying call mechanism, which is injected as `callMethod`
111
+ * to avoid queue deadlocks when running inside `connectorCall`.
112
+ */
113
+ private _computeChainFingerprint;
114
+ /**
115
+ * Ensure at least one device is connected and return a valid connectId.
116
+ *
117
+ * - If a session already exists for the given connectId, reuse it.
118
+ * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
119
+ * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
120
+ */
121
+ private static readonly MAX_DEVICE_RETRY;
122
+ private _connectingPromise;
123
+ private _waitForDeviceConnect;
124
+ private ensureConnected;
125
+ private _doConnect;
126
+ private _connectFirstOrSelect;
127
+ private _chooseDeviceFromList;
128
+ /**
129
+ * Call the connector with automatic session resolution and disconnect retry.
130
+ *
131
+ * 1. Resolves a valid connectId via ensureConnected()
132
+ * 2. Looks up sessionId from _sessions
133
+ * 3. Calls connector.call()
134
+ * 4. On disconnect error: clears stale session, re-connects, retries once
135
+ */
136
+ private connectorCall;
137
+ /**
138
+ * Race a promise against an abort signal. If the signal fires, rejects with the
139
+ * signal's reason (or a generic Error). The underlying connector.call() cannot
140
+ * actually be cancelled on Ledger DMK, but the caller gets the abort immediately.
141
+ */
142
+ private static _abortable;
143
+ /** Throw an AbortError if signal is already aborted. */
144
+ private static _throwIfAborted;
145
+ /** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
146
+ private _runConnectorCall;
147
+ /** Clear stale session, reconnect, and retry the call. */
148
+ private _retryWithFreshConnection;
149
+ /**
150
+ * Ensure OS-level device permission (Bluetooth / USB) before proceeding.
151
+ *
152
+ * Emits `REQUEST_DEVICE_PERMISSION` and awaits the consumer's
153
+ * `RECEIVE_DEVICE_PERMISSION` reply (60s budget covers "probe → system
154
+ * prompt → user tap" plus a generous margin). If the consumer never wires
155
+ * a handler or never replies, the wait times out and the operation fails
156
+ * fast so scanners/callers don't hang silently.
157
+ *
158
+ * - No connectId (searchDevices): environment-level permission
159
+ * - With connectId (business methods): device-level permission
160
+ */
161
+ private _ensureDevicePermission;
162
+ /**
163
+ * Convert a thrown error to a Response failure.
164
+ * Uses mapLedgerError to parse Ledger DMK error codes into HardwareErrorCode values.
165
+ */
166
+ private errorToFailure;
167
+ private deviceConnectHandler;
168
+ private deviceDisconnectHandler;
169
+ private uiEventForwarder;
170
+ private registerEventListeners;
171
+ private unregisterEventListeners;
172
+ private connectorDeviceToDeviceInfo;
173
+ }
174
+
175
+ /**
176
+ * A function that lazily loads and returns the transport factory
177
+ * for the Ledger DMK builder (e.g. webHidTransportFactory, rnBleTransportFactory).
178
+ */
179
+ type TransportFactory = () => Promise<unknown>;
180
+ interface LedgerConnectorBaseOptions {
181
+ /**
182
+ * Pre-built DMK instance. If not provided, a DMK will be created
183
+ * lazily on first use via the transport factory.
184
+ */
185
+ dmk?: DeviceManagementKit;
186
+ }
187
+ /**
188
+ * Shared base class for Ledger IConnector implementations.
189
+ *
190
+ * Encapsulates all shared logic: device discovery, connection management,
191
+ * method dispatch (EVM / BTC / SOL / TRON), signer lifecycle, event emission,
192
+ * and error handling.
193
+ *
194
+ * Chain-specific method implementations live in `./chains/` and receive
195
+ * a ConnectorContext that exposes shared helpers.
196
+ *
197
+ * Subclasses only need to:
198
+ * 1. Supply a transport factory via the constructor.
199
+ * 2. Optionally override `_resolveConnectId()` for transport-specific
200
+ * device identity resolution (e.g. BLE hex ID extraction).
201
+ */
202
+ declare class LedgerConnectorBase implements IConnector {
203
+ private _deviceManager;
204
+ private _signerManager;
205
+ private _dmk;
206
+ private readonly _eventHandlers;
207
+ private readonly _providedDmk;
208
+ private readonly _createTransport;
209
+ readonly connectionType: ConnectionType;
210
+ private _connectIdToPath;
211
+ private _pathToConnectId;
212
+ /** Register a connectId <-> path mapping from a device descriptor. */
213
+ private _registerDeviceId;
214
+ /** Get DMK path from external connectId. Falls back to connectId itself. */
215
+ private _getPathForConnectId;
216
+ /** Get external connectId from DMK path. Falls back to path itself. */
217
+ private _getConnectIdForPath;
218
+ private readonly _cancellers;
219
+ /**
220
+ * Resolves a Ledger signer kit module by package name.
221
+ * Override via constructor to use CJS paths for Metro (React Native).
222
+ * Default: dynamic import with bare specifier (webpack/rspack).
223
+ */
224
+ protected _importLedgerKit: (pkg: string) => Promise<any>;
225
+ /** Context object passed to per-chain handler functions. */
226
+ private readonly _ctx;
227
+ constructor(createTransport: TransportFactory, options?: {
228
+ connectionType?: ConnectionType;
229
+ dmk?: DeviceManagementKit;
230
+ /**
231
+ * Override how `@ledgerhq/device-signer-kit-*` packages are imported.
232
+ * Default: `(pkg) => import(pkg)` — works with webpack/rspack.
233
+ * For Metro (React Native): pass a resolver that uses CJS paths.
234
+ */
235
+ importLedgerKit?: (pkg: string) => Promise<any>;
236
+ });
237
+ /**
238
+ * Resolve the connectId for a discovered device descriptor.
239
+ * Default: use the DMK path (ephemeral UUID).
240
+ * Override in subclasses to extract stable identifiers (e.g. BLE hex ID).
241
+ */
242
+ protected _resolveConnectId(descriptor: DeviceDescriptor): string;
243
+ searchDevices(): Promise<ConnectorDevice[]>;
244
+ connect(deviceId?: string): Promise<ConnectorSession>;
245
+ disconnect(sessionId: string): Promise<void>;
246
+ call(sessionId: string, method: string, params: unknown): Promise<unknown>;
247
+ cancel(sessionId: string): Promise<void>;
248
+ uiResponse(_response: UiResponseEvent): void;
249
+ on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
250
+ off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
251
+ reset(): void;
252
+ /**
253
+ * Lazily create or return the DMK instance.
254
+ * If a DMK was provided via constructor, it is used directly.
255
+ * Otherwise, one is created via the transport factory.
256
+ */
257
+ protected _getOrCreateDmk(): Promise<DeviceManagementKit>;
258
+ private _initManagers;
259
+ private _getDeviceManager;
260
+ private _getSignerManager;
261
+ private _invalidateSession;
262
+ /**
263
+ * Replace an old session with a new one after app switch.
264
+ * Updates the connectId→path mapping so subsequent calls() use the new session,
265
+ * and emits device-connect so the adapter updates its _sessions Map.
266
+ */
267
+ private _replaceSession;
268
+ /**
269
+ * Light reset: clear signer/session state but keep DMK, BLE scan, and ID mapping alive.
270
+ * Used by connect() retry — we want to re-discover with the same transport.
271
+ */
272
+ private _resetSignersAndSessions;
273
+ private _resetAll;
274
+ protected _emit<K extends ConnectorEventType>(event: K, data: ConnectorEventMap[K]): void;
275
+ /**
276
+ * Return a per-call ctx with the chain's Ledger app name pre-bound to
277
+ * wrapError, so chain handlers don't need to repeat `{ defaultAppName: 'X' }`
278
+ * at every catch site. Falls through unchanged for unknown methods.
279
+ */
280
+ private _ctxForMethod;
281
+ private _wrapError;
282
+ }
283
+
284
+ /**
285
+ * Manages device discovery, connection, and session tracking.
286
+ * Wraps DMK's Observable APIs into simpler imperative calls.
287
+ */
288
+ declare class LedgerDeviceManager {
289
+ private readonly _dmk;
290
+ private readonly _discovered;
291
+ private readonly _sessions;
292
+ private readonly _sessionToDevice;
293
+ private _listenSub;
294
+ constructor(dmk: DeviceManagementKit);
295
+ /**
296
+ * One-shot enumeration: subscribe to listenToAvailableDevices,
297
+ * take the first emission, unsubscribe, return DeviceDescriptors.
298
+ */
299
+ enumerate(): Promise<DeviceDescriptor[]>;
300
+ /**
301
+ * Continuous listening: tracks device connect/disconnect via diffing.
302
+ */
303
+ listen(onChange: (event: DeviceChangeEvent) => void): void;
304
+ stopListening(): void;
305
+ /**
306
+ * Trigger browser device selection (WebHID requestDevice).
307
+ * Starts discovery for a short period, then stops.
308
+ */
309
+ /**
310
+ * Start BLE discovery if not already running.
311
+ * Does NOT stop — DMK keeps scanning in the background so that
312
+ * listenToAvailableDevices() always has fresh data.
313
+ */
314
+ private _discoverySub;
315
+ requestDevice(): Promise<void>;
316
+ /** Connect to a previously discovered device. Returns sessionId. */
317
+ connect(deviceId: string): Promise<string>;
318
+ /** Disconnect a session. */
319
+ disconnect(sessionId: string): Promise<void>;
320
+ getSessionId(deviceId: string): string | undefined;
321
+ getDeviceId(sessionId: string): string | undefined;
322
+ /** Get the underlying DMK instance (needed by SignerManager). */
323
+ getDmk(): DeviceManagementKit;
324
+ stopDiscovery(): void;
325
+ dispose(): void;
326
+ }
327
+
328
+ /**
329
+ * Re-export DMK types under local aliases for backward compatibility.
330
+ * These replace the previous duck-typed interfaces with the real SDK types.
331
+ */
332
+ type DmkDiscoveredDevice = DiscoveredDevice;
333
+ /**
334
+ * DMK DeviceAction — the Observable-based return type of all DMK signer methods.
335
+ *
336
+ * This is a permissive alias for `ExecuteDeviceActionReturnType` that accepts
337
+ * any Error and IntermediateValue generics. Signer wrapper code only cares about
338
+ * the Output type and the observable/cancel shape.
339
+ */
340
+ type DeviceAction<T> = ExecuteDeviceActionReturnType<T, any, any>;
341
+ /**
342
+ * DMK DeviceActionState — re-exported with permissive Error/IntermediateValue.
343
+ * The real type is a discriminated union on `status`.
344
+ */
345
+ type DeviceActionState<T> = DeviceActionState$1<T, any, any>;
346
+ /** ETH address result — re-exported from DMK for backward compatibility. */
347
+ type SignerEvmAddress = Address;
348
+ /** ETH signature result — re-exported from DMK for backward compatibility. */
349
+ type SignerEvmSignature = Signature;
350
+ /** BTC address result (WalletAddress not exported from DMK top-level). */
351
+ interface SignerBtcAddress {
352
+ address: string;
353
+ }
354
+
355
+ /**
356
+ * Wraps Ledger's SDK signer (Observable-based DeviceActions) into
357
+ * a simple async interface returning plain serializable data.
358
+ */
359
+ declare class SignerEth {
360
+ private readonly _sdk;
361
+ onInteraction?: (interaction: string) => void;
362
+ constructor(_sdk: SignerEth$1);
363
+ /**
364
+ * Optional callback registered per-call so the caller can obtain a canceller
365
+ * for the underlying DeviceAction. Caller can invoke it to release DMK's
366
+ * IntentQueue slot and unsubscribe from the action's observable.
367
+ */
368
+ onRegisterCanceller?: (cancel: () => void) => void;
369
+ getAddress(derivationPath: string, options?: {
370
+ checkOnDevice?: boolean;
371
+ }): Promise<SignerEvmAddress>;
372
+ signTransaction(derivationPath: string, serializedTxHex: string): Promise<SignerEvmSignature>;
373
+ signMessage(derivationPath: string, message: string): Promise<SignerEvmSignature>;
374
+ signTypedData(derivationPath: string, data: TypedData): Promise<SignerEvmSignature>;
375
+ }
376
+
377
+ type SignerEthBuilderFn = (args: {
378
+ dmk: DeviceManagementKit;
379
+ sessionId: string;
380
+ }) => {
381
+ build(): SignerEth$1;
382
+ } | Promise<{
383
+ build(): SignerEth$1;
384
+ }>;
385
+ /**
386
+ * Per-sessionId SignerEth factory. Builds fresh on every call — DMK signers
387
+ * hold DeviceAction state that isn't safe to reuse, so `invalidate` /
388
+ * `clearAll` are kept as no-op lifecycle hooks for callers.
389
+ */
390
+ declare class SignerManager {
391
+ private readonly _dmk;
392
+ private readonly _builderFn;
393
+ constructor(dmk: DeviceManagementKit, builderFn?: SignerEthBuilderFn);
394
+ getOrCreate(sessionId: string): Promise<SignerEth>;
395
+ invalidate(_sessionId: string): void;
396
+ clearAll(): void;
397
+ private static _defaultBuilder;
398
+ }
399
+
400
+ type BtcWallet = Parameters<SignerBtc$1['getWalletAddress']>[0];
401
+ type BtcPsbt = Parameters<SignerBtc$1['signPsbt']>[1];
402
+ type BtcPsbtOptions = Parameters<SignerBtc$1['signPsbt']>[2];
403
+ type BtcMessageOptions = Parameters<SignerBtc$1['signMessage']>[2];
404
+ /**
405
+ * Wraps Ledger's BTC SDK signer (Observable-based DeviceActions) into
406
+ * a simple async interface returning plain serializable data.
407
+ */
408
+ declare class SignerBtc {
409
+ private readonly _sdk;
410
+ onInteraction?: (interaction: string) => void;
411
+ onRegisterCanceller?: (cancel: () => void) => void;
412
+ constructor(_sdk: SignerBtc$1);
413
+ getWalletAddress(wallet: BtcWallet, addressIndex: number, options?: {
414
+ checkOnDevice?: boolean;
415
+ change?: boolean;
416
+ }): Promise<SignerBtcAddress>;
417
+ getExtendedPublicKey(derivationPath: string, options?: {
418
+ checkOnDevice?: boolean;
419
+ }): Promise<string>;
420
+ getMasterFingerprint(options?: {
421
+ skipOpenApp?: boolean;
422
+ }): Promise<Uint8Array>;
423
+ /**
424
+ * Sign a PSBT and return the array of partial signatures.
425
+ * The `wallet` param is a DefaultWallet or WalletPolicy instance.
426
+ * The `psbt` param can be a hex string, base64 string, or Uint8Array.
427
+ */
428
+ signPsbt(wallet: BtcWallet, psbt: BtcPsbt, options?: BtcPsbtOptions): Promise<unknown[]>;
429
+ /**
430
+ * Sign a PSBT and return the fully extracted raw transaction as a hex string.
431
+ * Like signPsbt, but also finalises the PSBT and extracts the transaction.
432
+ */
433
+ signTransaction(wallet: BtcWallet, psbt: BtcPsbt, options?: BtcPsbtOptions): Promise<string>;
434
+ /**
435
+ * Sign a message with the BTC app (BIP-137 / "Bitcoin Signed Message").
436
+ * Returns `{ r, s, v }` signature object.
437
+ */
438
+ signMessage(derivationPath: string, message: string, options?: BtcMessageOptions): Promise<{
439
+ r: string;
440
+ s: string;
441
+ v: number;
442
+ }>;
443
+ }
444
+
445
+ type SolTxOptions = Parameters<SignerSolana['signTransaction']>[2];
446
+ type SolMsgOptions = Parameters<SignerSolana['signMessage']>[2];
447
+ /**
448
+ * Wraps Ledger's Solana SDK signer (Observable-based DeviceActions) into
449
+ * a simple async interface returning plain serializable data.
450
+ *
451
+ * The Solana signer's `getAddress` returns a base58-encoded Ed25519 public key,
452
+ * which is also the Solana address.
453
+ */
454
+ declare class SignerSol {
455
+ private readonly _sdk;
456
+ onInteraction?: (interaction: string) => void;
457
+ onRegisterCanceller?: (cancel: () => void) => void;
458
+ constructor(_sdk: SignerSolana);
459
+ /**
460
+ * Get the Solana address (base58-encoded Ed25519 public key) at the given derivation path.
461
+ */
462
+ getAddress(derivationPath: string, options?: {
463
+ checkOnDevice?: boolean;
464
+ }): Promise<string>;
465
+ /**
466
+ * Sign a Solana transaction.
467
+ */
468
+ signTransaction(derivationPath: string, transaction: Uint8Array, options?: SolTxOptions): Promise<Uint8Array>;
469
+ /**
470
+ * Sign a message with the Solana app.
471
+ * DMK returns { signature: string } for signMessage (unlike signTransaction which returns Uint8Array).
472
+ */
473
+ signMessage(derivationPath: string, message: string | Uint8Array, options?: SolMsgOptions): Promise<{
474
+ signature: string;
475
+ }>;
476
+ }
477
+
478
+ /**
479
+ * Transport adapter that bridges Ledger's legacy hw-app-* SDKs to DMK's sendApdu.
480
+ *
481
+ * Legacy SDKs (hw-app-trx, hw-app-xrp, etc.) require a Transport instance.
482
+ * This adapter wraps DMK's session-based sendApdu so legacy SDKs can run
483
+ * over DMK's transport layer without a separate USB/HID connection.
484
+ *
485
+ * Usage:
486
+ * const transport = new DmkTransport(dmk, sessionId);
487
+ * const trx = new Trx(transport);
488
+ * const address = await trx.getAddress("44'/195'/0'/0/0");
489
+ */
490
+ declare class DmkTransport extends Transport {
491
+ private _dmk;
492
+ private _sessionId;
493
+ constructor(dmk: DeviceManagementKit, sessionId: string);
494
+ exchange(apdu: Buffer): Promise<Buffer>;
495
+ close(): Promise<void>;
496
+ }
497
+
498
+ /**
499
+ * Convert a DMK DeviceAction (Observable-based) into a Promise.
500
+ * Handles pending -> completed/error state transitions and interaction callbacks.
501
+ *
502
+ * Tracks the last DMK step observed (e.g. `signer.eth.steps.blindSignTransactionFallback`)
503
+ * and attaches it to the rejected error as a non-enumerable `_lastStep` property,
504
+ * so upstream error classifiers can distinguish failure contexts (e.g. Blind signing
505
+ * disabled vs. generic Invalid data).
506
+ *
507
+ * @param timeoutMs Timeout in ms. Resets each time the Observable emits (device is alive).
508
+ * Pass 0 to disable. Default: 30s.
509
+ * @param onRegisterCanceller Optional callback that receives a function which, when
510
+ * called, unsubscribes and cancels the underlying DeviceAction
511
+ * (releases DMK's IntentQueue slot). Caller is responsible
512
+ * for invoking the canceller on timeout/abort scenarios.
513
+ */
514
+ declare function deviceActionToPromise<T>(action: DeviceAction<T>, onInteraction?: (interaction: string) => void, timeoutMs?: number, onRegisterCanceller?: (cancel: () => void) => void): Promise<T>;
515
+
516
+ interface AppManagerOptions {
517
+ waitMs?: number;
518
+ maxRetries?: number;
519
+ }
520
+ /**
521
+ * Orchestrates opening / closing Ledger on-device apps so that the
522
+ * correct signer application is running before any signing call.
523
+ */
524
+ declare class AppManager {
525
+ private readonly _dmk;
526
+ private readonly _waitMs;
527
+ private readonly _maxRetries;
528
+ constructor(dmk: DeviceManagementKit, options?: AppManagerOptions);
529
+ /**
530
+ * Return the Ledger app name for a given chain ticker,
531
+ * or undefined if the chain is not supported.
532
+ */
533
+ static getAppName(chain: string): string | undefined;
534
+ /**
535
+ * Ensure the target app is open on the device identified by `sessionId`.
536
+ *
537
+ * Flow:
538
+ * 1. Check the currently running app.
539
+ * 2. If it is already the target, return immediately.
540
+ * 3. If a different app is running (not dashboard), close it first.
541
+ * 4. Open the target app.
542
+ * 5. Poll until the device confirms the target app is running.
543
+ */
544
+ /**
545
+ * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
546
+ * device is about to display "Open <app>" on screen and wait for the
547
+ * user's button press. UI consumers should show their "open app" prompt
548
+ * in response. NOT called when the target app is already open (no user
549
+ * interaction needed in that case).
550
+ *
551
+ * Important: OpenAppCommand is blocking. It does not resolve until the user
552
+ * has physically confirmed on the device, so anything that runs AFTER
553
+ * `await this._openApp(...)` lands AFTER the prompt is already gone.
554
+ * Hence the callback must fire BEFORE that await.
555
+ */
556
+ ensureAppOpen(sessionId: string, targetAppName: string, onConfirmOnDevice?: () => void): Promise<void>;
557
+ private _getCurrentApp;
558
+ private _openApp;
559
+ private _closeCurrentApp;
560
+ /**
561
+ * Poll the device until the expected app is reported as running,
562
+ * or throw after `_maxRetries` attempts.
563
+ */
564
+ private _waitForApp;
565
+ private _isDashboard;
566
+ private _wait;
567
+ }
568
+
569
+ /**
570
+ * Ledger-specific Failure: adds `appName` for "the currently-open app" — a
571
+ * Ledger hardware concept not shared with other vendors, so it lives here
572
+ * rather than in core's generic Failure.
573
+ */
574
+ type LedgerFailure = Omit<Failure, 'payload'> & {
575
+ payload: Failure['payload'] & {
576
+ appName?: string;
577
+ };
578
+ };
579
+ interface WrapErrorOptions {
580
+ /**
581
+ * Fallback app name when the raw error doesn't carry `appName` itself
582
+ * (DMK signer errors don't). Used by mapLedgerError so downstream
583
+ * AppNotOpen / WrongApp / AppTooOld toasts can interpolate `{appName}`.
584
+ */
585
+ defaultAppName?: string;
586
+ }
587
+ /**
588
+ * Structurally compatible with `Failure`; writes `appName` only when provided,
589
+ * so `'appName' in payload` is a reliable "has info" signal for consumers.
590
+ */
591
+ declare function ledgerFailure(code: HardwareErrorCode, error: string, appName?: string): LedgerFailure;
592
+ /** Check if an error (or any error in its chain) represents a locked Ledger device. */
593
+ declare function isDeviceLockedError(err: unknown): boolean;
594
+ /**
595
+ * Map a Ledger DMK error to a HardwareErrorCode and human-readable message.
596
+ * `opts.defaultAppName` fills `appName` when the raw error doesn't carry it
597
+ * (DMK signer errors don't).
598
+ */
599
+ declare function mapLedgerError(err: unknown, opts?: WrapErrorOptions): {
600
+ code: HardwareErrorCode;
601
+ message: string;
602
+ appName?: string;
603
+ };
604
+
605
+ /**
606
+ * SDK-global event bus. Per-runtime singleton — each process subscribes
607
+ * independently; cross-process hosts forward events over their own IPC.
608
+ */
609
+ type SdkLogEvent = {
610
+ type: 'log';
611
+ level: 'debug' | 'error';
612
+ /** Pre-stringified payload. */
613
+ message: string;
614
+ };
615
+ /** Add new variants here; hosts dispatch on `event.type`. */
616
+ type SdkEvent = SdkLogEvent;
617
+ type SdkEventListener = (event: SdkEvent) => void;
618
+ declare function onSdkEvent(listener: SdkEventListener): () => void;
619
+ declare function offSdkEvent(listener: SdkEventListener): void;
620
+
621
+ /**
622
+ * Extract the stable 4-digit HEX identifier from a Ledger BLE device name.
623
+ * e.g., "Nano X 123A" -> "123A", "Ledger Nano X AB12" -> "AB12"
624
+ * Returns undefined if no valid HEX suffix found.
625
+ */
626
+ declare function extractBleHexId(name?: string): string | undefined;
627
+
628
+ export { AppManager, type DeviceActionState, type DmkDiscoveredDevice, DmkTransport, LedgerAdapter, LedgerConnectorBase, type LedgerConnectorBaseOptions, LedgerDeviceManager, type LedgerFailure, type SdkEvent, type SdkEventListener, type SdkLogEvent, SignerBtc, type SignerBtcAddress, SignerEth, type SignerEvmAddress, type SignerEvmSignature, SignerManager, SignerSol, type TransportFactory, deviceActionToPromise, extractBleHexId, isDeviceLockedError, ledgerFailure, mapLedgerError, offSdkEvent, onSdkEvent };