@onekeyfe/hwk-adapter-core 1.1.28 → 1.1.29-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/chunk-6JWUE3GT.mjs +151 -0
- package/dist/chunk-6JWUE3GT.mjs.map +1 -0
- package/dist/chunk-D5OZT7RZ.mjs +138 -0
- package/dist/chunk-D5OZT7RZ.mjs.map +1 -0
- package/dist/chunk-LYVS67EX.js +151 -0
- package/dist/chunk-LYVS67EX.js.map +1 -0
- package/dist/chunk-QD4EQWQA.js +138 -0
- package/dist/chunk-QD4EQWQA.js.map +1 -0
- package/dist/errors.d.mts +164 -0
- package/dist/errors.d.ts +164 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.mjs +13 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.d.mts +610 -292
- package/dist/index.d.ts +610 -292
- package/dist/index.js +452 -368
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +400 -258
- package/dist/index.mjs.map +1 -1
- package/dist/ui-events-BzkI1wZk.d.mts +132 -0
- package/dist/ui-events-BzkI1wZk.d.ts +132 -0
- package/dist/ui-events.d.mts +1 -0
- package/dist/ui-events.d.ts +1 -0
- package/dist/ui-events.js +21 -0
- package/dist/ui-events.js.map +1 -0
- package/dist/ui-events.mjs +21 -0
- package/dist/ui-events.mjs.map +1 -0
- package/package.json +22 -2
package/dist/index.mjs
CHANGED
|
@@ -1,68 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
HardwareErrorCode2[HardwareErrorCode2["ChainNotSupported"] = 10108] = "ChainNotSupported";
|
|
18
|
-
HardwareErrorCode2[HardwareErrorCode2["DeviceOneDeviceOnly"] = 10109] = "DeviceOneDeviceOnly";
|
|
19
|
-
HardwareErrorCode2[HardwareErrorCode2["FirmwareTooOld"] = 10200] = "FirmwareTooOld";
|
|
20
|
-
HardwareErrorCode2[HardwareErrorCode2["FirmwareUpdateRequired"] = 10201] = "FirmwareUpdateRequired";
|
|
21
|
-
HardwareErrorCode2[HardwareErrorCode2["TransportError"] = 10300] = "TransportError";
|
|
22
|
-
HardwareErrorCode2[HardwareErrorCode2["BridgeNotFound"] = 10301] = "BridgeNotFound";
|
|
23
|
-
HardwareErrorCode2[HardwareErrorCode2["TransportNotAvailable"] = 10302] = "TransportNotAvailable";
|
|
24
|
-
HardwareErrorCode2[HardwareErrorCode2["DevicePermissionDenied"] = 10303] = "DevicePermissionDenied";
|
|
25
|
-
HardwareErrorCode2[HardwareErrorCode2["BlePairingTimeout"] = 10304] = "BlePairingTimeout";
|
|
26
|
-
HardwareErrorCode2[HardwareErrorCode2["NetworkError"] = 10305] = "NetworkError";
|
|
27
|
-
HardwareErrorCode2[HardwareErrorCode2["PinInvalid"] = 10400] = "PinInvalid";
|
|
28
|
-
HardwareErrorCode2[HardwareErrorCode2["PinCancelled"] = 10401] = "PinCancelled";
|
|
29
|
-
HardwareErrorCode2[HardwareErrorCode2["PassphraseRejected"] = 10402] = "PassphraseRejected";
|
|
30
|
-
HardwareErrorCode2[HardwareErrorCode2["AppNotInstalled"] = 10500] = "AppNotInstalled";
|
|
31
|
-
HardwareErrorCode2[HardwareErrorCode2["WrongApp"] = 10501] = "WrongApp";
|
|
32
|
-
HardwareErrorCode2[HardwareErrorCode2["AppTooOld"] = 10502] = "AppTooOld";
|
|
33
|
-
HardwareErrorCode2[HardwareErrorCode2["DeviceOutOfMemory"] = 10503] = "DeviceOutOfMemory";
|
|
34
|
-
HardwareErrorCode2[HardwareErrorCode2["EvmBlindSigningRequired"] = 11e3] = "EvmBlindSigningRequired";
|
|
35
|
-
HardwareErrorCode2[HardwareErrorCode2["EvmClearSignPluginMissing"] = 11001] = "EvmClearSignPluginMissing";
|
|
36
|
-
HardwareErrorCode2[HardwareErrorCode2["EvmDataTooLarge"] = 11002] = "EvmDataTooLarge";
|
|
37
|
-
HardwareErrorCode2[HardwareErrorCode2["EvmTxTypeNotSupported"] = 11003] = "EvmTxTypeNotSupported";
|
|
38
|
-
HardwareErrorCode2[HardwareErrorCode2["SolanaBlindSigningRequired"] = 11100] = "SolanaBlindSigningRequired";
|
|
39
|
-
HardwareErrorCode2[HardwareErrorCode2["TronCustomContractRequired"] = 11200] = "TronCustomContractRequired";
|
|
40
|
-
HardwareErrorCode2[HardwareErrorCode2["TronDataSigningRequired"] = 11201] = "TronDataSigningRequired";
|
|
41
|
-
HardwareErrorCode2[HardwareErrorCode2["TronSignByHashRequired"] = 11202] = "TronSignByHashRequired";
|
|
42
|
-
HardwareErrorCode2[HardwareErrorCode2["BtcWalletPolicyHmacMismatch"] = 11300] = "BtcWalletPolicyHmacMismatch";
|
|
43
|
-
HardwareErrorCode2[HardwareErrorCode2["BtcUnexpectedState"] = 11301] = "BtcUnexpectedState";
|
|
44
|
-
return HardwareErrorCode2;
|
|
45
|
-
})(HardwareErrorCode || {});
|
|
46
|
-
var ORPHAN_ELIGIBLE_ERROR_CODES = [
|
|
47
|
-
10005 /* UserAborted */,
|
|
48
|
-
10001 /* UserRejected */,
|
|
49
|
-
10100 /* DeviceNotFound */,
|
|
50
|
-
10101 /* DeviceDisconnected */,
|
|
51
|
-
10106 /* DeviceMismatch */,
|
|
52
|
-
10107 /* DeviceAppStuck */,
|
|
53
|
-
10109 /* DeviceOneDeviceOnly */,
|
|
54
|
-
10300 /* TransportError */,
|
|
55
|
-
10303 /* DevicePermissionDenied */,
|
|
56
|
-
10304 /* BlePairingTimeout */
|
|
57
|
-
];
|
|
58
|
-
function createHwkError(payload) {
|
|
59
|
-
return Object.assign(new Error(payload.message), {
|
|
60
|
-
code: payload.code,
|
|
61
|
-
...payload._tag !== void 0 && { _tag: payload._tag },
|
|
62
|
-
...payload.appName !== void 0 && { appName: payload.appName },
|
|
63
|
-
...payload.params !== void 0 && { params: payload.params }
|
|
64
|
-
});
|
|
65
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
HardwareErrorCode,
|
|
3
|
+
ORPHAN_ELIGIBLE_ERROR_CODES,
|
|
4
|
+
createHwkError,
|
|
5
|
+
enrichErrorMessage
|
|
6
|
+
} from "./chunk-D5OZT7RZ.mjs";
|
|
7
|
+
import {
|
|
8
|
+
UI_EVENT,
|
|
9
|
+
UI_REQUEST,
|
|
10
|
+
UI_REQUEST_CANCELLED_TAG,
|
|
11
|
+
UI_REQUEST_DEFAULT_TIMEOUT_MS,
|
|
12
|
+
UI_REQUEST_PREEMPTED_TAG,
|
|
13
|
+
UI_REQUEST_TIMEOUT_TAG,
|
|
14
|
+
UI_RESPONSE,
|
|
15
|
+
UiRequestRegistry
|
|
16
|
+
} from "./chunk-6JWUE3GT.mjs";
|
|
66
17
|
|
|
67
18
|
// src/types/response.ts
|
|
68
19
|
function success(payload) {
|
|
@@ -95,43 +46,19 @@ var DEVICE_EVENT = "DEVICE_EVENT";
|
|
|
95
46
|
var DEVICE = {
|
|
96
47
|
CONNECT: "device-connect",
|
|
97
48
|
DISCONNECT: "device-disconnect",
|
|
98
|
-
CHANGED: "device-changed"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
REQUEST_SELECT_DEVICE: "ui-request-select-device",
|
|
112
|
-
REQUEST_DEVICE_CONNECT: "ui-request-device-connect",
|
|
113
|
-
// Ledger BTC App: account index >= 100 requires display=true. Adapter asks
|
|
114
|
-
// the user once per session before promoting the call.
|
|
115
|
-
REQUEST_BTC_HIGH_INDEX_CONFIRM: "ui-request-btc-high-index-confirm",
|
|
116
|
-
// Required app is not installed; with autoInstallApp on, ask the user
|
|
117
|
-
// whether to install it before retrying the operation.
|
|
118
|
-
REQUEST_INSTALL_APP: "ui-request-install-app",
|
|
119
|
-
CLOSE_UI_WINDOW: "ui-close",
|
|
120
|
-
DEVICE_PROGRESS: "ui-device_progress",
|
|
121
|
-
FIRMWARE_PROGRESS: "ui-firmware-progress",
|
|
122
|
-
FIRMWARE_TIP: "ui-firmware-tip"
|
|
123
|
-
};
|
|
124
|
-
var UI_RESPONSE = {
|
|
125
|
-
RECEIVE_PIN: "receive-pin",
|
|
126
|
-
RECEIVE_PASSPHRASE: "receive-passphrase",
|
|
127
|
-
RECEIVE_PASSPHRASE_ON_DEVICE: "receive-passphrase-on-device",
|
|
128
|
-
RECEIVE_QR_RESPONSE: "receive-qr-response",
|
|
129
|
-
RECEIVE_SELECT_DEVICE: "receive-select-device",
|
|
130
|
-
RECEIVE_DEVICE_CONNECT: "receive-device-connect",
|
|
131
|
-
RECEIVE_DEVICE_PERMISSION: "receive-device-permission",
|
|
132
|
-
RECEIVE_BTC_HIGH_INDEX_CONFIRM: "receive-btc-high-index-confirm",
|
|
133
|
-
RECEIVE_INSTALL_APP: "receive-install-app",
|
|
134
|
-
CANCEL: "cancel"
|
|
49
|
+
CHANGED: "device-changed",
|
|
50
|
+
FEATURES: "features",
|
|
51
|
+
/**
|
|
52
|
+
* Trezor-only. Emitted after a successful THP handshake that minted or
|
|
53
|
+
* refreshed pairing credentials. The host should persist `credentials`
|
|
54
|
+
* keyed by `deviceId` and feed them back into the connector on the next
|
|
55
|
+
* connect to skip the CodeEntry/QrCode/NFC pairing UX.
|
|
56
|
+
*
|
|
57
|
+
* The `TREZOR_` prefix mirrors `UI_REQUEST.REQUEST_TREZOR_THP_PAIRING` —
|
|
58
|
+
* vendor-specific events live in the shared event taxonomy but are named
|
|
59
|
+
* so hosts can ignore them when they don't drive Trezor hardware.
|
|
60
|
+
*/
|
|
61
|
+
TREZOR_THP_CREDENTIALS_CHANGED: "device-trezor-thp-credentials-changed"
|
|
135
62
|
};
|
|
136
63
|
|
|
137
64
|
// src/events/sdk.ts
|
|
@@ -262,7 +189,7 @@ function createBridgedConnector(vendor, connectionType, bridge) {
|
|
|
262
189
|
const handlerMap = /* @__PURE__ */ new Map();
|
|
263
190
|
return {
|
|
264
191
|
connectionType,
|
|
265
|
-
searchDevices: () => bridge.searchDevices({ vendor }),
|
|
192
|
+
searchDevices: (options) => bridge.searchDevices({ vendor, options }),
|
|
266
193
|
connect: (deviceId) => bridge.connect({ vendor, deviceId }),
|
|
267
194
|
disconnect: (sessionId) => bridge.disconnect({ vendor, sessionId }),
|
|
268
195
|
call: (sessionId, method, callParams) => bridge.call({ vendor, sessionId, method, callParams }),
|
|
@@ -290,7 +217,8 @@ function createBridgedConnector(vendor, connectionType, bridge) {
|
|
|
290
217
|
inner.delete(handler);
|
|
291
218
|
if (inner.size === 0) handlerMap.delete(event);
|
|
292
219
|
},
|
|
293
|
-
reset: () => bridge.reset({ vendor })
|
|
220
|
+
reset: () => bridge.reset({ vendor }),
|
|
221
|
+
setKnownCredentials: bridge.setKnownCredentials ? (credentials) => bridge.setKnownCredentials({ vendor, credentials }) : void 0
|
|
294
222
|
};
|
|
295
223
|
}
|
|
296
224
|
var SERIALIZED_ERROR_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -350,6 +278,222 @@ function rehydrateConnectorError(error) {
|
|
|
350
278
|
...params ?? {}
|
|
351
279
|
});
|
|
352
280
|
}
|
|
281
|
+
function isDeviceUnavailableError(error) {
|
|
282
|
+
const typed = error;
|
|
283
|
+
if (typed.code === 10100 /* DeviceNotFound */ || typed.code === 10101 /* DeviceDisconnected */) {
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function combinedDeviceNotFoundError(message) {
|
|
289
|
+
return createHwkError({
|
|
290
|
+
code: 10100 /* DeviceNotFound */,
|
|
291
|
+
message
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
function combinedSessionNotFoundError(message) {
|
|
295
|
+
return createHwkError({
|
|
296
|
+
code: 10101 /* DeviceDisconnected */,
|
|
297
|
+
message
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
function createCombinedConnector(connectors) {
|
|
301
|
+
if (connectors.length === 0) {
|
|
302
|
+
throw new Error("createCombinedConnector: at least one connector is required");
|
|
303
|
+
}
|
|
304
|
+
const SEARCH_SETTLE_AFTER_FIRST_DEVICE_MS = 250;
|
|
305
|
+
const deviceOwner = /* @__PURE__ */ new Map();
|
|
306
|
+
const sessionOwner = /* @__PURE__ */ new Map();
|
|
307
|
+
const forwarders = /* @__PURE__ */ new Map();
|
|
308
|
+
const rank = (device) => device.connectionType === "ble" ? 1 : 0;
|
|
309
|
+
const sharedCredentials = [];
|
|
310
|
+
const credentialKey = (c) => c.credential ?? JSON.stringify(c);
|
|
311
|
+
const mergeShared = (incoming) => {
|
|
312
|
+
let changed = false;
|
|
313
|
+
for (const cred of incoming) {
|
|
314
|
+
const key = credentialKey(cred);
|
|
315
|
+
if (!sharedCredentials.some((e) => credentialKey(e) === key)) {
|
|
316
|
+
sharedCredentials.push(cred);
|
|
317
|
+
changed = true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return changed;
|
|
321
|
+
};
|
|
322
|
+
const broadcastCredentials = async () => {
|
|
323
|
+
await Promise.all(
|
|
324
|
+
connectors.map((child) => Promise.resolve(child.setKnownCredentials?.(sharedCredentials)))
|
|
325
|
+
);
|
|
326
|
+
};
|
|
327
|
+
for (const child of connectors) {
|
|
328
|
+
child.on("device-trezor-thp-credentials-changed", (data) => {
|
|
329
|
+
if (mergeShared(data.credentials)) void broadcastCredentials();
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
const searchDevices = async (options = {}) => {
|
|
333
|
+
const perConnector = [];
|
|
334
|
+
await new Promise((resolve) => {
|
|
335
|
+
let finished = false;
|
|
336
|
+
let remaining = connectors.length;
|
|
337
|
+
let settleTimer;
|
|
338
|
+
const finish = () => {
|
|
339
|
+
if (finished) return;
|
|
340
|
+
finished = true;
|
|
341
|
+
if (settleTimer) clearTimeout(settleTimer);
|
|
342
|
+
resolve();
|
|
343
|
+
};
|
|
344
|
+
connectors.forEach((child, index) => {
|
|
345
|
+
void child.searchDevices().then(
|
|
346
|
+
(devices) => devices.map((device) => ({
|
|
347
|
+
...device,
|
|
348
|
+
connectionType: device.connectionType ?? child.connectionType
|
|
349
|
+
}))
|
|
350
|
+
).catch(
|
|
351
|
+
() => (
|
|
352
|
+
// A transport that can't scan (powered off, unauthorized, absent)
|
|
353
|
+
// must not fail the whole fused search.
|
|
354
|
+
[]
|
|
355
|
+
)
|
|
356
|
+
).then((devices) => {
|
|
357
|
+
remaining -= 1;
|
|
358
|
+
if (!finished) {
|
|
359
|
+
perConnector.push({ index, devices });
|
|
360
|
+
}
|
|
361
|
+
if (remaining === 0) {
|
|
362
|
+
finish();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const hasUsbDevice = devices.some((device) => device.connectionType === "usb");
|
|
366
|
+
if (hasUsbDevice && !settleTimer && !options.waitForAll) {
|
|
367
|
+
settleTimer = setTimeout(finish, SEARCH_SETTLE_AFTER_FIRST_DEVICE_MS);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
perConnector.sort((a, b) => a.index - b.index);
|
|
373
|
+
deviceOwner.clear();
|
|
374
|
+
const merged = [];
|
|
375
|
+
perConnector.forEach(({ index, devices }) => {
|
|
376
|
+
for (const device of devices) {
|
|
377
|
+
deviceOwner.set(device.connectId, connectors[index]);
|
|
378
|
+
merged.push(device);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
return merged.sort((a, b) => rank(a) - rank(b));
|
|
382
|
+
};
|
|
383
|
+
const resolveOwner = async (deviceId) => {
|
|
384
|
+
if (deviceId && deviceOwner.has(deviceId)) {
|
|
385
|
+
return { owner: deviceOwner.get(deviceId), deviceId };
|
|
386
|
+
}
|
|
387
|
+
const devices = await searchDevices({ waitForAll: Boolean(deviceId) });
|
|
388
|
+
if (deviceId) {
|
|
389
|
+
const owner = deviceOwner.get(deviceId);
|
|
390
|
+
if (!owner)
|
|
391
|
+
throw combinedDeviceNotFoundError(`Combined connector: device not found: ${deviceId}`);
|
|
392
|
+
return { owner, deviceId };
|
|
393
|
+
}
|
|
394
|
+
const first = devices[0];
|
|
395
|
+
if (!first) throw combinedDeviceNotFoundError("Combined connector: no devices found");
|
|
396
|
+
return { owner: deviceOwner.get(first.connectId), deviceId: first.connectId };
|
|
397
|
+
};
|
|
398
|
+
const connectByExplicitId = async (deviceId) => {
|
|
399
|
+
const cachedOwner = deviceOwner.get(deviceId);
|
|
400
|
+
if (cachedOwner) {
|
|
401
|
+
return { session: await cachedOwner.connect(deviceId), owner: cachedOwner };
|
|
402
|
+
}
|
|
403
|
+
let lastError;
|
|
404
|
+
for (const child of connectors) {
|
|
405
|
+
try {
|
|
406
|
+
const session = await child.connect(deviceId);
|
|
407
|
+
deviceOwner.set(deviceId, child);
|
|
408
|
+
return { session, owner: child };
|
|
409
|
+
} catch (error) {
|
|
410
|
+
if (!isDeviceUnavailableError(error)) {
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
lastError = error;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const message = lastError instanceof Error ? lastError.message : `Combined connector: device not found: ${deviceId}`;
|
|
417
|
+
throw createHwkError({
|
|
418
|
+
code: 10100 /* DeviceNotFound */,
|
|
419
|
+
message
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
return {
|
|
423
|
+
// Nominal value only — the per-device `connectionType` is authoritative
|
|
424
|
+
// for a fused connector.
|
|
425
|
+
connectionType: connectors[0].connectionType,
|
|
426
|
+
searchDevices: (options) => searchDevices({ waitForAll: options?.waitForAll }),
|
|
427
|
+
connect: async (deviceId) => {
|
|
428
|
+
let owner;
|
|
429
|
+
let session;
|
|
430
|
+
if (deviceId) {
|
|
431
|
+
({ session, owner } = await connectByExplicitId(deviceId));
|
|
432
|
+
} else {
|
|
433
|
+
const resolved = await resolveOwner();
|
|
434
|
+
owner = resolved.owner;
|
|
435
|
+
session = await owner.connect(resolved.deviceId);
|
|
436
|
+
}
|
|
437
|
+
sessionOwner.set(session.sessionId, owner);
|
|
438
|
+
return session;
|
|
439
|
+
},
|
|
440
|
+
disconnect: async (sessionId) => {
|
|
441
|
+
const owner = sessionOwner.get(sessionId);
|
|
442
|
+
if (!owner) return;
|
|
443
|
+
await owner.disconnect(sessionId);
|
|
444
|
+
sessionOwner.delete(sessionId);
|
|
445
|
+
},
|
|
446
|
+
call: async (sessionId, method, params) => {
|
|
447
|
+
const owner = sessionOwner.get(sessionId);
|
|
448
|
+
if (!owner) {
|
|
449
|
+
throw combinedSessionNotFoundError(`Combined connector: session not found: ${sessionId}`);
|
|
450
|
+
}
|
|
451
|
+
return owner.call(sessionId, method, params);
|
|
452
|
+
},
|
|
453
|
+
cancel: async (sessionId) => {
|
|
454
|
+
const owner = sessionOwner.get(sessionId);
|
|
455
|
+
if (!owner) return;
|
|
456
|
+
await owner.cancel(sessionId);
|
|
457
|
+
},
|
|
458
|
+
uiResponse: (response) => {
|
|
459
|
+
for (const child of connectors) child.uiResponse(response);
|
|
460
|
+
},
|
|
461
|
+
on: (event, handler) => {
|
|
462
|
+
const attached = connectors.map((child) => {
|
|
463
|
+
const forward = (data) => handler(data);
|
|
464
|
+
child.on(event, forward);
|
|
465
|
+
return { child, handler: forward };
|
|
466
|
+
});
|
|
467
|
+
let inner = forwarders.get(event);
|
|
468
|
+
if (!inner) {
|
|
469
|
+
inner = /* @__PURE__ */ new Map();
|
|
470
|
+
forwarders.set(event, inner);
|
|
471
|
+
}
|
|
472
|
+
inner.set(handler, attached);
|
|
473
|
+
},
|
|
474
|
+
off: (event, handler) => {
|
|
475
|
+
const inner = forwarders.get(event);
|
|
476
|
+
const attached = inner?.get(handler);
|
|
477
|
+
if (!attached || !inner) return;
|
|
478
|
+
for (const { child, handler: forward } of attached) {
|
|
479
|
+
child.off(event, forward);
|
|
480
|
+
}
|
|
481
|
+
inner.delete(handler);
|
|
482
|
+
if (inner.size === 0) forwarders.delete(event);
|
|
483
|
+
},
|
|
484
|
+
reset: () => {
|
|
485
|
+
for (const child of connectors) child.reset();
|
|
486
|
+
deviceOwner.clear();
|
|
487
|
+
sessionOwner.clear();
|
|
488
|
+
forwarders.clear();
|
|
489
|
+
},
|
|
490
|
+
setKnownCredentials: connectors.some((c) => c.setKnownCredentials) ? async (credentials) => {
|
|
491
|
+
sharedCredentials.length = 0;
|
|
492
|
+
mergeShared(credentials ?? []);
|
|
493
|
+
await broadcastCredentials();
|
|
494
|
+
} : void 0
|
|
495
|
+
};
|
|
496
|
+
}
|
|
353
497
|
|
|
354
498
|
// src/utils/TypedEventEmitter.ts
|
|
355
499
|
var TypedEventEmitter = class {
|
|
@@ -381,103 +525,9 @@ var TypedEventEmitter = class {
|
|
|
381
525
|
removeAllListeners() {
|
|
382
526
|
this._listeners.clear();
|
|
383
527
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
var UI_REQUEST_DEFAULT_TIMEOUT_MS = 6e5;
|
|
388
|
-
var RESPONSE_TO_REQUEST = {
|
|
389
|
-
[UI_RESPONSE.RECEIVE_PIN]: UI_REQUEST.REQUEST_PIN,
|
|
390
|
-
[UI_RESPONSE.RECEIVE_PASSPHRASE]: UI_REQUEST.REQUEST_PASSPHRASE,
|
|
391
|
-
[UI_RESPONSE.RECEIVE_PASSPHRASE_ON_DEVICE]: UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,
|
|
392
|
-
[UI_RESPONSE.RECEIVE_SELECT_DEVICE]: UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
393
|
-
[UI_RESPONSE.RECEIVE_DEVICE_CONNECT]: UI_REQUEST.REQUEST_DEVICE_CONNECT,
|
|
394
|
-
[UI_RESPONSE.RECEIVE_DEVICE_PERMISSION]: UI_REQUEST.REQUEST_DEVICE_PERMISSION,
|
|
395
|
-
[UI_RESPONSE.RECEIVE_BTC_HIGH_INDEX_CONFIRM]: UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,
|
|
396
|
-
[UI_RESPONSE.RECEIVE_INSTALL_APP]: UI_REQUEST.REQUEST_INSTALL_APP
|
|
397
|
-
// RECEIVE_QR_RESPONSE maps to QR_DISPLAY or QR_SCAN — resolved dynamically below.
|
|
398
|
-
};
|
|
399
|
-
var UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
|
|
400
|
-
var UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
|
|
401
|
-
var UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
|
|
402
|
-
var UiRequestRegistry = class {
|
|
403
|
-
constructor() {
|
|
404
|
-
this.pending = /* @__PURE__ */ new Map();
|
|
405
|
-
}
|
|
406
|
-
wait(requestType, options) {
|
|
407
|
-
const existing = this.pending.get(requestType);
|
|
408
|
-
if (existing) {
|
|
409
|
-
clearTimeout(existing.timer);
|
|
410
|
-
this.pending.delete(requestType);
|
|
411
|
-
existing.reject(
|
|
412
|
-
Object.assign(new Error(`UI request '${requestType}' was superseded by a new request`), {
|
|
413
|
-
_tag: UI_REQUEST_PREEMPTED_TAG
|
|
414
|
-
})
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
const timeoutMs = options?.timeoutMs ?? UI_REQUEST_DEFAULT_TIMEOUT_MS;
|
|
418
|
-
return new Promise((resolve, reject) => {
|
|
419
|
-
const timer = setTimeout(() => {
|
|
420
|
-
if (this.pending.get(requestType)?.timer === timer) {
|
|
421
|
-
this.pending.delete(requestType);
|
|
422
|
-
reject(
|
|
423
|
-
Object.assign(new Error(`UI request '${requestType}' timed out after ${timeoutMs}ms`), {
|
|
424
|
-
_tag: UI_REQUEST_TIMEOUT_TAG
|
|
425
|
-
})
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
}, timeoutMs);
|
|
429
|
-
this.pending.set(requestType, {
|
|
430
|
-
resolve,
|
|
431
|
-
reject,
|
|
432
|
-
timer
|
|
433
|
-
});
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
resolve(responseType, payload) {
|
|
437
|
-
let requestType = RESPONSE_TO_REQUEST[responseType];
|
|
438
|
-
if (responseType === UI_RESPONSE.RECEIVE_QR_RESPONSE) {
|
|
439
|
-
if (this.pending.has(UI_REQUEST.REQUEST_QR_DISPLAY)) {
|
|
440
|
-
requestType = UI_REQUEST.REQUEST_QR_DISPLAY;
|
|
441
|
-
} else if (this.pending.has(UI_REQUEST.REQUEST_QR_SCAN)) {
|
|
442
|
-
requestType = UI_REQUEST.REQUEST_QR_SCAN;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
if (!requestType) return;
|
|
446
|
-
const entry = this.pending.get(requestType);
|
|
447
|
-
if (!entry) return;
|
|
448
|
-
clearTimeout(entry.timer);
|
|
449
|
-
this.pending.delete(requestType);
|
|
450
|
-
entry.resolve(payload);
|
|
451
|
-
}
|
|
452
|
-
cancel(requestType) {
|
|
453
|
-
if (requestType) {
|
|
454
|
-
const entry = this.pending.get(requestType);
|
|
455
|
-
if (!entry) return;
|
|
456
|
-
clearTimeout(entry.timer);
|
|
457
|
-
this.pending.delete(requestType);
|
|
458
|
-
entry.reject(
|
|
459
|
-
Object.assign(new Error(`UI request '${requestType}' was cancelled`), {
|
|
460
|
-
_tag: UI_REQUEST_CANCELLED_TAG
|
|
461
|
-
})
|
|
462
|
-
);
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
for (const [type, entry] of this.pending) {
|
|
466
|
-
clearTimeout(entry.timer);
|
|
467
|
-
entry.reject(
|
|
468
|
-
Object.assign(new Error(`UI request '${type}' was cancelled`), {
|
|
469
|
-
_tag: UI_REQUEST_CANCELLED_TAG
|
|
470
|
-
})
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
this.pending.clear();
|
|
474
|
-
}
|
|
475
|
-
reset() {
|
|
476
|
-
this.cancel();
|
|
477
|
-
}
|
|
478
|
-
hasPending(requestType) {
|
|
479
|
-
if (requestType) return this.pending.has(requestType);
|
|
480
|
-
return this.pending.size > 0;
|
|
528
|
+
/** Number of listeners registered for `event`. 0 if none. */
|
|
529
|
+
listenerCount(event) {
|
|
530
|
+
return this._listeners.get(event)?.size ?? 0;
|
|
481
531
|
}
|
|
482
532
|
};
|
|
483
533
|
|
|
@@ -512,64 +562,37 @@ function bytesToHex2(bytes) {
|
|
|
512
562
|
return nobleBytesToHex(bytes);
|
|
513
563
|
}
|
|
514
564
|
|
|
515
|
-
// src/utils/
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
case 10305 /* NetworkError */:
|
|
541
|
-
return `${originalMessage}. Network error \u2014 check your internet connection and try again.`;
|
|
542
|
-
case 10200 /* FirmwareTooOld */:
|
|
543
|
-
return `${originalMessage}. Please update your device firmware.`;
|
|
544
|
-
case 10104 /* DeviceNotInitialized */:
|
|
545
|
-
return `${originalMessage}. The device may need to be set up first.`;
|
|
546
|
-
case 10003 /* OperationTimeout */:
|
|
547
|
-
return `${originalMessage}. The operation timed out. Please try again.`;
|
|
548
|
-
case 11e3 /* EvmBlindSigningRequired */:
|
|
549
|
-
return "Ledger: Blind signing not enabled in Ethereum app.";
|
|
550
|
-
case 11001 /* EvmClearSignPluginMissing */:
|
|
551
|
-
return "Ledger: Required plugin not installed (install via Ledger Live).";
|
|
552
|
-
case 11002 /* EvmDataTooLarge */:
|
|
553
|
-
return "Ledger: Transaction data too large for device memory.";
|
|
554
|
-
case 11003 /* EvmTxTypeNotSupported */:
|
|
555
|
-
return "Ledger: Transaction type not supported by current Ethereum app.";
|
|
556
|
-
case 10502 /* AppTooOld */:
|
|
557
|
-
return "Ledger: App out of date (update via Ledger Live).";
|
|
558
|
-
case 11100 /* SolanaBlindSigningRequired */:
|
|
559
|
-
return "Blind signing disabled in the Solana app.";
|
|
560
|
-
case 11200 /* TronCustomContractRequired */:
|
|
561
|
-
return "Custom Contracts setting disabled in the Tron app.";
|
|
562
|
-
case 11201 /* TronDataSigningRequired */:
|
|
563
|
-
return "Transactions Data setting disabled in the Tron app.";
|
|
564
|
-
case 11202 /* TronSignByHashRequired */:
|
|
565
|
-
return "Sign by Hash setting disabled in the Tron app.";
|
|
566
|
-
case 11300 /* BtcWalletPolicyHmacMismatch */:
|
|
567
|
-
return "Wallet policy not registered or HMAC mismatch.";
|
|
568
|
-
case 11301 /* BtcUnexpectedState */:
|
|
569
|
-
return "Signing aborted due to unexpected device state.";
|
|
570
|
-
default:
|
|
571
|
-
return originalMessage;
|
|
565
|
+
// src/utils/deviceIdentity.ts
|
|
566
|
+
var ONEKEY_BLE_SERVICE_UUID = "00000001-0000-1000-8000-00805f9b34fb";
|
|
567
|
+
var TREZOR_BLE_SERVICE_UUID = "8c000001-a59b-4d58-a9ad-073df69fa1b1";
|
|
568
|
+
var LEDGER_USB_VENDOR_ID = 11415;
|
|
569
|
+
var lower = (value) => value?.trim().toLowerCase() ?? "";
|
|
570
|
+
var hasServiceUuid = (input, uuid) => {
|
|
571
|
+
const expected = uuid.toLowerCase();
|
|
572
|
+
const values = [
|
|
573
|
+
...input.serviceUUIDs ?? [],
|
|
574
|
+
...input.advertisedServiceUuids ?? [],
|
|
575
|
+
...input.serviceUuids ?? []
|
|
576
|
+
];
|
|
577
|
+
return values.some((value) => value.toLowerCase() === expected);
|
|
578
|
+
};
|
|
579
|
+
function detectHardwareVendorFromDescriptor(input) {
|
|
580
|
+
const manufacturerName = lower(input.manufacturerName);
|
|
581
|
+
const fwVendor = lower(input.fw_vendor);
|
|
582
|
+
if (hasServiceUuid(input, ONEKEY_BLE_SERVICE_UUID) || manufacturerName.includes("onekey") || fwVendor === "onekey" || input.onekey_version || input.onekey_device_type || input.onekey_serial) {
|
|
583
|
+
return "onekey";
|
|
584
|
+
}
|
|
585
|
+
if (hasServiceUuid(input, TREZOR_BLE_SERVICE_UUID) || manufacturerName.includes("trezor") || fwVendor === "trezor") {
|
|
586
|
+
return "trezor";
|
|
587
|
+
}
|
|
588
|
+
if (typeof input.vendor === "number" && input.vendor === LEDGER_USB_VENDOR_ID || input.vendorId === LEDGER_USB_VENDOR_ID || manufacturerName.includes("ledger")) {
|
|
589
|
+
return "ledger";
|
|
572
590
|
}
|
|
591
|
+
return void 0;
|
|
592
|
+
}
|
|
593
|
+
function isKnownNonTargetHardwareVendor(input, targetVendor) {
|
|
594
|
+
const detectedVendor = detectHardwareVendorFromDescriptor(input);
|
|
595
|
+
return detectedVendor !== void 0 && detectedVendor !== targetVendor;
|
|
573
596
|
}
|
|
574
597
|
|
|
575
598
|
// src/utils/batchCall.ts
|
|
@@ -585,12 +608,123 @@ async function batchCall(params, callFn, onProgress) {
|
|
|
585
608
|
}
|
|
586
609
|
return { success: true, payload: results };
|
|
587
610
|
}
|
|
611
|
+
|
|
612
|
+
// src/utils/methodCatalog.ts
|
|
613
|
+
var HARDWARE_METHOD_CATALOG = {
|
|
614
|
+
evmGetAddress: { chain: "evm", allNetwork: true },
|
|
615
|
+
evmSignTransaction: { chain: "evm", allNetwork: false },
|
|
616
|
+
evmSignMessage: { chain: "evm", allNetwork: false },
|
|
617
|
+
evmSignTypedData: { chain: "evm", allNetwork: false },
|
|
618
|
+
btcGetAddress: { chain: "btc", allNetwork: true },
|
|
619
|
+
btcGetPublicKey: { chain: "btc", allNetwork: true },
|
|
620
|
+
btcSignTransaction: { chain: "btc", allNetwork: false },
|
|
621
|
+
btcSignPsbt: { chain: "btc", allNetwork: false },
|
|
622
|
+
btcSignMessage: { chain: "btc", allNetwork: false },
|
|
623
|
+
btcGetMasterFingerprint: { chain: "btc", allNetwork: false },
|
|
624
|
+
solGetAddress: { chain: "sol", allNetwork: true },
|
|
625
|
+
solSignTransaction: { chain: "sol", allNetwork: false },
|
|
626
|
+
solSignMessage: { chain: "sol", allNetwork: false },
|
|
627
|
+
tronGetAddress: { chain: "tron", allNetwork: true },
|
|
628
|
+
tronSignTransaction: { chain: "tron", allNetwork: false },
|
|
629
|
+
tronSignMessage: { chain: "tron", allNetwork: false }
|
|
630
|
+
};
|
|
631
|
+
var ALL_NETWORK_METHOD_NAMES = Object.entries(HARDWARE_METHOD_CATALOG).filter(([, metadata]) => metadata.allNetwork).map(([method]) => method);
|
|
632
|
+
var ALL_NETWORK_METHOD_SET = new Set(ALL_NETWORK_METHOD_NAMES);
|
|
633
|
+
function getHardwareMethodMetadata(method) {
|
|
634
|
+
return HARDWARE_METHOD_CATALOG[method];
|
|
635
|
+
}
|
|
636
|
+
function isAllNetworkMethodName(method) {
|
|
637
|
+
return ALL_NETWORK_METHOD_SET.has(method);
|
|
638
|
+
}
|
|
639
|
+
function getAllNetworkMethodChain(method) {
|
|
640
|
+
return HARDWARE_METHOD_CATALOG[method].chain;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// src/utils/allNetwork.ts
|
|
644
|
+
async function runAllNetworkGetAddress({
|
|
645
|
+
connectId,
|
|
646
|
+
deviceId,
|
|
647
|
+
params,
|
|
648
|
+
getMethodChain = (method) => getAllNetworkMethodChain(method),
|
|
649
|
+
normalizeItem = (_method, item) => item,
|
|
650
|
+
buildUnsupportedNetworkResponse,
|
|
651
|
+
callItem,
|
|
652
|
+
attachIdentity,
|
|
653
|
+
shouldAbortBundle = () => false,
|
|
654
|
+
buildTopLevelFailure = defaultBuildTopLevelFailure
|
|
655
|
+
}) {
|
|
656
|
+
const responses = [];
|
|
657
|
+
for (const [index, item] of params.bundle.entries()) {
|
|
658
|
+
if (!isAllNetworkMethodName(String(item.methodName))) {
|
|
659
|
+
responses.push(buildUnsupportedMethodResponse(item));
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
const method = item.methodName;
|
|
663
|
+
const unsupportedNetwork = buildUnsupportedNetworkResponse?.(item, method);
|
|
664
|
+
if (unsupportedNetwork) {
|
|
665
|
+
responses.push(unsupportedNetwork);
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
const chain = getMethodChain(method, item);
|
|
669
|
+
const normalizedItem = normalizeItem(method, item);
|
|
670
|
+
const context = {
|
|
671
|
+
connectId,
|
|
672
|
+
deviceId,
|
|
673
|
+
method,
|
|
674
|
+
chain,
|
|
675
|
+
item: normalizedItem,
|
|
676
|
+
index
|
|
677
|
+
};
|
|
678
|
+
const response = await callItem(context);
|
|
679
|
+
const itemResponse = response.success ? await attachIdentity({
|
|
680
|
+
...context,
|
|
681
|
+
payload: response.payload
|
|
682
|
+
}) : {
|
|
683
|
+
...normalizedItem,
|
|
684
|
+
success: false,
|
|
685
|
+
payload: response.payload
|
|
686
|
+
};
|
|
687
|
+
const responseContext = { ...context, response: itemResponse };
|
|
688
|
+
if (!itemResponse.success && shouldAbortBundle(itemResponse, responseContext)) {
|
|
689
|
+
return buildTopLevelFailure(itemResponse, responseContext);
|
|
690
|
+
}
|
|
691
|
+
responses.push(itemResponse);
|
|
692
|
+
}
|
|
693
|
+
return success(responses);
|
|
694
|
+
}
|
|
695
|
+
function buildUnsupportedMethodResponse(item) {
|
|
696
|
+
return {
|
|
697
|
+
...item,
|
|
698
|
+
success: false,
|
|
699
|
+
payload: {
|
|
700
|
+
code: 10002 /* InvalidParams */,
|
|
701
|
+
error: `Unsupported allNetwork method: ${String(item.methodName)}`
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
function defaultBuildTopLevelFailure(response) {
|
|
706
|
+
const payload = response.payload ?? {};
|
|
707
|
+
return failure(
|
|
708
|
+
payload.code ?? 10106 /* DeviceMismatch */,
|
|
709
|
+
payload.error ?? "All-network get-address aborted",
|
|
710
|
+
normalizeFailureParams(payload.params)
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
function normalizeFailureParams(params) {
|
|
714
|
+
return params && typeof params === "object" ? params : void 0;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// src/constants.ts
|
|
718
|
+
var DEVICE_CONNECT_RETRY_DELAY_MS = 1e3;
|
|
588
719
|
export {
|
|
720
|
+
ALL_NETWORK_METHOD_NAMES,
|
|
589
721
|
CHAIN_FINGERPRINT_PATHS,
|
|
590
722
|
DEVICE,
|
|
723
|
+
DEVICE_CONNECT_RETRY_DELAY_MS,
|
|
591
724
|
DEVICE_EVENT,
|
|
592
725
|
DeviceJobQueue,
|
|
593
726
|
EConnectorInteraction,
|
|
727
|
+
HARDWARE_METHOD_CATALOG,
|
|
594
728
|
HardwareErrorCode,
|
|
595
729
|
ORPHAN_ELIGIBLE_ERROR_CODES,
|
|
596
730
|
SDK,
|
|
@@ -604,17 +738,25 @@ export {
|
|
|
604
738
|
UI_RESPONSE,
|
|
605
739
|
UiRequestRegistry,
|
|
606
740
|
batchCall,
|
|
741
|
+
buildUnsupportedMethodResponse,
|
|
607
742
|
bytesToHex2 as bytesToHex,
|
|
608
743
|
compareSemver,
|
|
609
744
|
createBridgedConnector,
|
|
745
|
+
createCombinedConnector,
|
|
610
746
|
createHwkError,
|
|
611
747
|
deriveDeviceFingerprint,
|
|
748
|
+
detectHardwareVendorFromDescriptor,
|
|
612
749
|
enrichErrorMessage,
|
|
613
750
|
ensure0x,
|
|
614
751
|
failure,
|
|
752
|
+
getAllNetworkMethodChain,
|
|
753
|
+
getHardwareMethodMetadata,
|
|
615
754
|
hexToBytes,
|
|
755
|
+
isAllNetworkMethodName,
|
|
756
|
+
isKnownNonTargetHardwareVendor,
|
|
616
757
|
padHex64,
|
|
617
758
|
rehydrateConnectorError,
|
|
759
|
+
runAllNetworkGetAddress,
|
|
618
760
|
serializeConnectorError,
|
|
619
761
|
stripHex,
|
|
620
762
|
success
|