@onekeyfe/hd-core 1.1.4-alpha.2 → 1.1.4-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/api/BaseMethod.d.ts +2 -0
  2. package/dist/api/BaseMethod.d.ts.map +1 -1
  3. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts +4 -28
  4. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
  5. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +47 -0
  6. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -0
  7. package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts +8 -0
  8. package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts.map +1 -0
  9. package/dist/api/btc/BTCGetPublicKey.d.ts.map +1 -1
  10. package/dist/api/cosmos/CosmosGetPublicKey.d.ts +1 -1
  11. package/dist/api/cosmos/CosmosGetPublicKey.d.ts.map +1 -1
  12. package/dist/api/device/DeviceUnlock.d.ts +0 -2
  13. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  14. package/dist/api/evm/EVMGetPublicKey.d.ts +1 -0
  15. package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
  16. package/dist/api/index.d.ts +1 -0
  17. package/dist/api/index.d.ts.map +1 -1
  18. package/dist/core/RequestQueue.d.ts +4 -0
  19. package/dist/core/RequestQueue.d.ts.map +1 -1
  20. package/dist/core/index.d.ts +3 -2
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/device/Device.d.ts +4 -1
  23. package/dist/device/Device.d.ts.map +1 -1
  24. package/dist/events/call.d.ts +9 -0
  25. package/dist/events/call.d.ts.map +1 -1
  26. package/dist/events/core.d.ts +2 -2
  27. package/dist/events/core.d.ts.map +1 -1
  28. package/dist/events/iframe.d.ts +11 -1
  29. package/dist/events/iframe.d.ts.map +1 -1
  30. package/dist/index.d.ts +41 -11
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +408 -195
  33. package/dist/inject.d.ts +3 -0
  34. package/dist/inject.d.ts.map +1 -1
  35. package/dist/types/api/allNetworkGetAddress.d.ts +12 -3
  36. package/dist/types/api/allNetworkGetAddress.d.ts.map +1 -1
  37. package/dist/types/api/evmGetPublicKey.d.ts +1 -0
  38. package/dist/types/api/evmGetPublicKey.d.ts.map +1 -1
  39. package/dist/types/api/index.d.ts +2 -1
  40. package/dist/types/api/index.d.ts.map +1 -1
  41. package/dist/utils/findDefectiveBatchDevice.d.ts +0 -5
  42. package/dist/utils/findDefectiveBatchDevice.d.ts.map +1 -1
  43. package/package.json +4 -4
  44. package/src/api/BaseMethod.ts +3 -0
  45. package/src/api/allnetwork/AllNetworkGetAddress.ts +19 -408
  46. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +480 -0
  47. package/src/api/allnetwork/AllNetworkGetAddressByLoop.ts +161 -0
  48. package/src/api/btc/BTCGetPublicKey.ts +13 -0
  49. package/src/api/cosmos/CosmosGetPublicKey.ts +1 -1
  50. package/src/api/device/DeviceUnlock.ts +1 -48
  51. package/src/api/evm/EVMGetPublicKey.ts +9 -3
  52. package/src/api/index.ts +1 -0
  53. package/src/core/RequestQueue.ts +26 -0
  54. package/src/core/index.ts +42 -82
  55. package/src/device/Device.ts +66 -0
  56. package/src/events/call.ts +10 -0
  57. package/src/events/core.ts +7 -1
  58. package/src/events/iframe.ts +12 -1
  59. package/src/index.ts +2 -1
  60. package/src/inject.ts +47 -0
  61. package/src/types/api/allNetworkGetAddress.ts +17 -3
  62. package/src/types/api/evmGetPublicKey.ts +1 -0
  63. package/src/types/api/index.ts +2 -1
  64. package/src/utils/findDefectiveBatchDevice.ts +0 -29
@@ -1,59 +1,12 @@
1
1
  import { LockDevice } from '@onekeyfe/hd-transport';
2
- import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
3
- import semver from 'semver';
4
2
  import { BaseMethod } from '../BaseMethod';
5
- import { toHardened } from '../helpers/pathUtils';
6
- import { DeviceFirmwareRange } from '../../types';
7
- import { getDeviceFirmwareVersion, getMethodVersionRange } from '../../utils';
8
3
 
9
4
  export default class DeviceUnlock extends BaseMethod<LockDevice> {
10
5
  init() {
11
6
  this.useDevicePassphraseState = false;
12
7
  }
13
8
 
14
- supportUnlockVersionRange(): DeviceFirmwareRange {
15
- return {
16
- pro: {
17
- min: '4.15.0',
18
- },
19
- };
20
- }
21
-
22
9
  async run() {
23
- const firmwareVersion = getDeviceFirmwareVersion(this.device.features)?.join('.');
24
- const versionRange = getMethodVersionRange(
25
- this.device.features,
26
- type => this.supportUnlockVersionRange()[type]
27
- );
28
-
29
- if (versionRange && semver.gte(firmwareVersion, versionRange.min)) {
30
- const res = await this.device.commands.typedCall('UnLockDevice', 'UnLockDeviceResponse');
31
- if (this.device.features) {
32
- this.device.features.unlocked = res.message.unlocked == null ? null : res.message.unlocked;
33
- this.device.features.unlocked_attach_pin =
34
- res.message.unlocked_attach_pin == null ? undefined : res.message.unlocked_attach_pin;
35
- this.device.features.passphrase_protection =
36
- res.message.passphrase_protection == null ? null : res.message.passphrase_protection;
37
-
38
- return Promise.resolve(this.device.features);
39
- }
40
-
41
- const featuresRes = await this.device.commands.typedCall('GetFeatures', 'Features');
42
- return Promise.resolve(featuresRes.message);
43
- }
44
-
45
- const { type } = await this.device.commands.typedCall('GetAddress', 'Address', {
46
- address_n: [toHardened(44), toHardened(1), toHardened(0), 0, 0],
47
- coin_name: 'Testnet',
48
- script_type: 'SPENDADDRESS',
49
- show_display: false,
50
- });
51
-
52
- // @ts-expect-error
53
- if (type === 'CallMethodError') {
54
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Get the passphrase state error');
55
- }
56
- const res = await this.device.commands.typedCall('GetFeatures', 'Features');
57
- return Promise.resolve(res.message);
10
+ return this.device.unlockDevice();
58
11
  }
59
12
  }
@@ -13,6 +13,8 @@ import { batchGetPublickeys } from '../helpers/batchGetPublickeys';
13
13
  export default class EVMGetPublicKey extends BaseMethod<EthereumGetPublicKeyOneKey[]> {
14
14
  hasBundle = false;
15
15
 
16
+ confirmShowOnOneKey = false;
17
+
16
18
  useBatch = false;
17
19
 
18
20
  init() {
@@ -20,9 +22,13 @@ export default class EVMGetPublicKey extends BaseMethod<EthereumGetPublicKeyOneK
20
22
  this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
21
23
 
22
24
  this.hasBundle = !!this.payload?.bundle;
23
- this.useBatch = this.payload?.bundle?.every(
24
- (item: EVMGetPublicKeyParams) => item.showOnOneKey !== true
25
+
26
+ this.confirmShowOnOneKey = this.payload?.bundle?.some(
27
+ (item: EVMGetPublicKeyParams) => !!item.showOnOneKey
25
28
  );
29
+
30
+ this.useBatch = !this.confirmShowOnOneKey && this.hasBundle && this.payload.useBatch;
31
+
26
32
  const payload = this.hasBundle ? this.payload : { bundle: [this.payload] };
27
33
 
28
34
  // check payload
@@ -66,7 +72,7 @@ export default class EVMGetPublicKey extends BaseMethod<EthereumGetPublicKeyOneK
66
72
  async run() {
67
73
  const responses: EVMPublicKey[] = [];
68
74
 
69
- if (this.useBatch && this.hasBundle && supportBatchPublicKey(this.device?.features)) {
75
+ if (this.useBatch && supportBatchPublicKey(this.device?.features)) {
70
76
  try {
71
77
  const res = await batchGetPublickeys(this.device, this.params, 'secp256k1', 60, {
72
78
  includeNode: false,
package/src/api/index.ts CHANGED
@@ -41,6 +41,7 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
41
41
  export { default as cipherKeyValue } from './CipherKeyValue';
42
42
 
43
43
  export { default as allNetworkGetAddress } from './allnetwork/AllNetworkGetAddress';
44
+ export { default as allNetworkGetAddressByLoop } from './allnetwork/AllNetworkGetAddressByLoop';
44
45
 
45
46
  export { default as btcGetAddress } from './btc/BTCGetAddress';
46
47
  export { default as btcGetPublicKey } from './btc/BTCGetPublicKey';
@@ -13,6 +13,8 @@ export type RequestTask = {
13
13
  export default class RequestQueue {
14
14
  private requestQueue = new Map<number, RequestTask>();
15
15
 
16
+ private pendingCallbackTasks = new Map<string, Deferred<void>>();
17
+
16
18
  // 生成唯一请求ID
17
19
  public generateRequestId = (method?: BaseMethod) => {
18
20
  if (method && method.responseID != null) {
@@ -104,4 +106,28 @@ export default class RequestQueue {
104
106
  public releaseTask(requestId: number) {
105
107
  this.requestQueue.delete(requestId);
106
108
  }
109
+
110
+ public registerPendingCallbackTask(connectId: string, callbackPromise: Deferred<void>) {
111
+ this.pendingCallbackTasks.set(connectId, callbackPromise);
112
+
113
+ callbackPromise.promise.finally(() => {
114
+ Log.debug(`Callback task completed for connectId: ${connectId}`);
115
+ this.pendingCallbackTasks.delete(connectId);
116
+ });
117
+ }
118
+
119
+ public async waitForPendingCallbackTasks(connectId: string): Promise<void> {
120
+ const pendingTask = this.pendingCallbackTasks.get(connectId);
121
+ if (pendingTask) {
122
+ Log.debug(`Waiting for pending callback task to complete for connectId: ${connectId}`);
123
+ await pendingTask.promise;
124
+ }
125
+ }
126
+
127
+ public cancelCallbackTasks(connectId: string) {
128
+ const pendingTask = this.pendingCallbackTasks.get(connectId);
129
+ if (pendingTask) {
130
+ pendingTask.resolve();
131
+ }
132
+ }
107
133
  }
package/src/core/index.ts CHANGED
@@ -3,19 +3,17 @@ import EventEmitter from 'events';
3
3
  import { Features, LowlevelTransportSharedPlugin, OneKeyDeviceInfo } from '@onekeyfe/hd-transport';
4
4
  import {
5
5
  createDeferred,
6
- Deferred,
7
- ERRORS,
8
- HardwareError,
9
- HardwareErrorCode,
10
6
  createDeprecatedHardwareError,
11
7
  createNeedUpgradeFirmwareHardwareError,
12
8
  createNewFirmwareForceUpdateHardwareError,
13
9
  createNewFirmwareUnReleaseHardwareError,
14
- createDefectiveFirmwareError,
10
+ Deferred,
11
+ ERRORS,
12
+ HardwareError,
13
+ HardwareErrorCode,
15
14
  } from '@onekeyfe/hd-shared';
16
15
  import {
17
16
  getDeviceFirmwareVersion,
18
- getDeviceBLEFirmwareVersion,
19
17
  enableLog,
20
18
  getLogger,
21
19
  LoggerNames,
@@ -23,10 +21,6 @@ import {
23
21
  wait,
24
22
  getMethodVersionRange,
25
23
  } from '../utils';
26
- import {
27
- findDefectiveBatchDevice,
28
- getDefectiveDeviceInfo,
29
- } from '../utils/findDefectiveBatchDevice';
30
24
  import { supportNewPassphrase } from '../utils/deviceFeaturesUtils';
31
25
  import { Device, DeviceEvents, InitOptions, RunOptions } from '../device/Device';
32
26
  import { DeviceList } from '../device/DeviceList';
@@ -58,7 +52,7 @@ import { getSynchronize } from '../utils/getSynchronize';
58
52
 
59
53
  const Log = getLogger(LoggerNames.Core);
60
54
 
61
- type CoreContext = ReturnType<Core['getCoreContext']>;
55
+ export type CoreContext = ReturnType<Core['getCoreContext']>;
62
56
 
63
57
  function hasDeriveCardano(method: BaseMethod): boolean {
64
58
  if (
@@ -201,6 +195,11 @@ const onCallDevice = async (
201
195
  DevicePool.clearDeviceCache(method.payload.connectId);
202
196
  }
203
197
 
198
+ // wait for previous callback tasks to complete (ensure device does not call concurrently)
199
+ if (method.connectId) {
200
+ await context.waitForCallbackTasks(method.connectId);
201
+ }
202
+
204
203
  await waitForPendingPromise(getPrePendingCallPromise, setPrePendingCallPromise);
205
204
 
206
205
  const task = requestQueue.createTask(method);
@@ -231,6 +230,7 @@ const onCallDevice = async (
231
230
 
232
231
  Log.debug('Call API - setDevice: ', device.mainId);
233
232
  method.setDevice?.(device);
233
+ method.context = context;
234
234
 
235
235
  device.on(DEVICE.PIN, onDevicePinHandler);
236
236
  device.on(DEVICE.BUTTON, onDeviceButtonHandler);
@@ -246,6 +246,10 @@ const onCallDevice = async (
246
246
  );
247
247
 
248
248
  try {
249
+ if (method.connectId) {
250
+ await context.waitForCallbackTasks(method.connectId);
251
+ }
252
+
249
253
  await waitForPendingPromise(getPrePendingCallPromise, setPrePendingCallPromise);
250
254
 
251
255
  const inner = async (): Promise<void> => {
@@ -257,96 +261,35 @@ const onCallDevice = async (
257
261
 
258
262
  if (device.features) {
259
263
  await DataManager.checkAndReloadData();
260
-
261
- // 检测故障固件设备
262
- if (findDefectiveBatchDevice(device.features)) {
263
- const defectiveInfo = getDefectiveDeviceInfo(device.features);
264
- if (defectiveInfo) {
265
- throw createDefectiveFirmwareError(
266
- defectiveInfo.serialNo,
267
- defectiveInfo.seVersion || 'Unknown',
268
- defectiveInfo.deviceType,
269
- method.connectId,
270
- method.deviceId
271
- );
272
- }
273
- }
274
-
275
264
  const newVersionStatus = DataManager.getFirmwareStatus(device.features);
276
265
  const bleVersionStatus = DataManager.getBLEFirmwareStatus(device.features);
277
-
278
- const currentFirmwareVersion = getDeviceFirmwareVersion(device.features).join('.');
279
- const currentBleVersion = getDeviceBLEFirmwareVersion(device.features).join('.');
280
266
  if (
281
267
  (newVersionStatus === 'required' || bleVersionStatus === 'required') &&
282
268
  method.skipForceUpdateCheck === false
283
269
  ) {
284
- // Get current version information for error reporting
285
- const currentVersions = {
286
- firmware: currentFirmwareVersion,
287
- ble: currentBleVersion,
288
- };
289
-
290
- // Provide more specific error message based on which version check failed
291
- if (newVersionStatus === 'required' && bleVersionStatus === 'required') {
292
- throw createNewFirmwareForceUpdateHardwareError(
293
- method.connectId,
294
- method.deviceId,
295
- 'both',
296
- currentVersions
297
- );
298
- } else if (newVersionStatus === 'required') {
299
- throw createNewFirmwareForceUpdateHardwareError(
300
- method.connectId,
301
- method.deviceId,
302
- 'firmware',
303
- currentVersions
304
- );
305
- } else {
306
- throw createNewFirmwareForceUpdateHardwareError(
307
- method.connectId,
308
- method.deviceId,
309
- 'ble',
310
- currentVersions
311
- );
312
- }
270
+ throw createNewFirmwareForceUpdateHardwareError(method.connectId, method.deviceId);
313
271
  }
314
272
 
315
273
  if (versionRange) {
316
- if (
317
- semver.valid(versionRange.min) &&
318
- semver.lt(currentFirmwareVersion, versionRange.min)
319
- ) {
274
+ const currentVersion = getDeviceFirmwareVersion(device.features).join('.');
275
+ if (semver.valid(versionRange.min) && semver.lt(currentVersion, versionRange.min)) {
320
276
  if (newVersionStatus === 'none' || newVersionStatus === 'valid') {
321
- throw createNewFirmwareUnReleaseHardwareError(
322
- currentFirmwareVersion,
323
- versionRange.min,
324
- method.name
325
- );
277
+ throw createNewFirmwareUnReleaseHardwareError(currentVersion, versionRange.min);
326
278
  }
327
279
 
328
280
  return Promise.reject(
329
- createNeedUpgradeFirmwareHardwareError(
330
- currentFirmwareVersion,
331
- versionRange.min,
332
- method.name
333
- )
281
+ createNeedUpgradeFirmwareHardwareError(currentVersion, versionRange.min)
334
282
  );
335
283
  }
336
284
  if (
337
285
  versionRange.max &&
338
286
  semver.valid(versionRange.max) &&
339
- semver.gte(currentFirmwareVersion, versionRange.max)
287
+ semver.gte(currentVersion, versionRange.max)
340
288
  ) {
341
- return Promise.reject(
342
- createDeprecatedHardwareError(currentFirmwareVersion, versionRange.max, method.name)
343
- );
289
+ return Promise.reject(createDeprecatedHardwareError(currentVersion, versionRange.max));
344
290
  }
345
291
  } else if (method.strictCheckDeviceSupport) {
346
- throw ERRORS.TypedError(
347
- HardwareErrorCode.DeviceNotSupportMethod,
348
- `Method '${method.name}' is not supported by this device`
349
- );
292
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceNotSupportMethod);
350
293
  }
351
294
  }
352
295
 
@@ -735,6 +678,7 @@ const ensureConnected = async (
735
678
  HardwareErrorCode.BleWriteCharacteristicError,
736
679
  HardwareErrorCode.BleAlreadyConnected,
737
680
  HardwareErrorCode.FirmwareUpdateLimitOneDevice,
681
+ HardwareErrorCode.SelectDevice,
738
682
  HardwareErrorCode.DeviceDetectInBootloaderMode,
739
683
  HardwareErrorCode.BleCharacteristicNotifyChangeFailure,
740
684
  HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission,
@@ -777,6 +721,10 @@ export const cancel = (context: CoreContext, connectId?: string) => {
777
721
  // }
778
722
  // setPrePendingCallPromise(device?.interruptionFromUser());
779
723
  // requestQueue.abortRequestsByConnectId(connectId);
724
+
725
+ // cancel callback tasks
726
+ requestQueue.cancelCallbackTasks(connectId);
727
+
780
728
  const requestIds = requestQueue.getRequestTasksId();
781
729
  Log.debug(
782
730
  `Cancel Api connect requestQueues: length:${requestIds.length} requestIds:${requestIds.join(
@@ -910,7 +858,7 @@ const onDevicePinHandler = async (...[device, type, callback]: DeviceEvents['pin
910
858
  callback(null, uiResp.payload);
911
859
  };
912
860
 
913
- const onDeviceButtonHandler = (...[device, request]: [...DeviceEvents['button']]) => {
861
+ export const onDeviceButtonHandler = (...[device, request]: [...DeviceEvents['button']]) => {
914
862
  postMessage(createDeviceMessage(DEVICE.BUTTON, { ...request, device: device.toMessageObject() }));
915
863
 
916
864
  if (request.code === 'ButtonRequest_PinEntry' || request.code === 'ButtonRequest_AttachPin') {
@@ -1014,7 +962,7 @@ const removeUiPromise = (promise: Deferred<any>) => {
1014
962
  export default class Core extends EventEmitter {
1015
963
  private requestQueue = new RequestQueue();
1016
964
 
1017
- // 上一个请求的 promise 完成,后续需要清理的工作,需要在下一次请求前完成
965
+ // background task
1018
966
  private prePendingCallPromise: Promise<void> | undefined;
1019
967
 
1020
968
  private methodSynchronize = getSynchronize();
@@ -1027,6 +975,13 @@ export default class Core extends EventEmitter {
1027
975
  setPrePendingCallPromise: (promise: Promise<void> | undefined) => {
1028
976
  this.prePendingCallPromise = promise;
1029
977
  },
978
+ // callback 任务管理
979
+ registerCallbackTask: (connectId: string, callbackPromise: Deferred<any>) => {
980
+ this.requestQueue.registerPendingCallbackTask(connectId, callbackPromise);
981
+ },
982
+ waitForCallbackTasks: (connectId: string) =>
983
+ this.requestQueue.waitForPendingCallbackTasks(connectId),
984
+ cancelCallbackTasks: (connectId: string) => this.requestQueue.cancelCallbackTasks(connectId),
1030
985
  };
1031
986
  }
1032
987
 
@@ -1077,6 +1032,11 @@ export default class Core extends EventEmitter {
1077
1032
  cancel(this.getCoreContext(), message.payload.connectId);
1078
1033
  break;
1079
1034
  }
1035
+ case IFRAME.CALLBACK: {
1036
+ Log.log('callback message: ', message);
1037
+ postMessage(message);
1038
+ break;
1039
+ }
1080
1040
  default:
1081
1041
  break;
1082
1042
  }
@@ -1,4 +1,5 @@
1
1
  import EventEmitter from 'events';
2
+ import semver from 'semver';
2
3
  import { OneKeyDeviceInfo as DeviceDescriptor } from '@onekeyfe/hd-transport';
3
4
  import {
4
5
  createDeferred,
@@ -16,6 +17,7 @@ import {
16
17
  getDeviceType,
17
18
  getDeviceUUID,
18
19
  getLogger,
20
+ getMethodVersionRange,
19
21
  LoggerNames,
20
22
  } from '../utils';
21
23
  import {
@@ -28,6 +30,7 @@ import type DeviceConnector from './DeviceConnector';
28
30
  import { DeviceCommands, PassphrasePromptResponse } from './DeviceCommands';
29
31
 
30
32
  import {
33
+ type DeviceFirmwareRange,
31
34
  EOneKeyDeviceMode,
32
35
  type Device as DeviceTyped,
33
36
  type Features,
@@ -43,6 +46,7 @@ import {
43
46
  import { PROTO } from '../constants';
44
47
  import { DataManager } from '../data-manager';
45
48
  import TransportManager from '../data-manager/TransportManager';
49
+ import { toHardened } from '../api/helpers/pathUtils';
46
50
 
47
51
  export type InitOptions = {
48
52
  initSession?: boolean;
@@ -151,6 +155,8 @@ export class Device extends EventEmitter {
151
155
 
152
156
  passphraseState: string | undefined = undefined;
153
157
 
158
+ pendingCallbackPromise?: Deferred<void>;
159
+
154
160
  constructor(descriptor: DeviceDescriptor) {
155
161
  super();
156
162
  this.originalDescriptor = descriptor;
@@ -264,6 +270,18 @@ export class Device extends EventEmitter {
264
270
  (this.isUsedHere() && !this.keepSession && this.mainId) ||
265
271
  (this.mainId && DataManager.isBleConnect(env))
266
272
  ) {
273
+ // wait for callback tasks to complete before releasing device
274
+ if (this.pendingCallbackPromise) {
275
+ try {
276
+ Log.debug(
277
+ 'Waiting for callback tasks to complete before releasing device (in release method)'
278
+ );
279
+ await this.pendingCallbackPromise.promise;
280
+ } catch (error) {
281
+ Log.error('Error waiting for callback tasks in release method:', error);
282
+ }
283
+ }
284
+
267
285
  if (this.commands) {
268
286
  this.commands.dispose(false);
269
287
  if (this.commands.callPromise) {
@@ -732,6 +750,54 @@ export class Device extends EventEmitter {
732
750
  return res.message;
733
751
  }
734
752
 
753
+ supportUnlockVersionRange(): DeviceFirmwareRange {
754
+ return {
755
+ pro: {
756
+ min: '4.15.0',
757
+ },
758
+ };
759
+ }
760
+
761
+ async unlockDevice() {
762
+ const firmwareVersion = getDeviceFirmwareVersion(this.features)?.join('.');
763
+ const versionRange = getMethodVersionRange(
764
+ this.features,
765
+ type => this.supportUnlockVersionRange()[type]
766
+ );
767
+
768
+ if (versionRange && semver.gte(firmwareVersion, versionRange.min)) {
769
+ const res = await this.commands.typedCall('UnLockDevice', 'UnLockDeviceResponse');
770
+ if (this.features) {
771
+ this.features.unlocked = res.message.unlocked == null ? null : res.message.unlocked;
772
+ this.features.unlocked_attach_pin =
773
+ res.message.unlocked_attach_pin == null ? undefined : res.message.unlocked_attach_pin;
774
+ this.features.passphrase_protection =
775
+ res.message.passphrase_protection == null ? null : res.message.passphrase_protection;
776
+
777
+ return Promise.resolve(this.features);
778
+ }
779
+
780
+ const featuresRes = await this.commands.typedCall('GetFeatures', 'Features');
781
+ this._updateFeatures(featuresRes.message);
782
+ return Promise.resolve(featuresRes.message);
783
+ }
784
+
785
+ const { type } = await this.commands.typedCall('GetAddress', 'Address', {
786
+ address_n: [toHardened(44), toHardened(1), toHardened(0), 0, 0],
787
+ coin_name: 'Testnet',
788
+ script_type: 'SPENDADDRESS',
789
+ show_display: false,
790
+ });
791
+
792
+ // @ts-expect-error
793
+ if (type === 'CallMethodError') {
794
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'unlock device error');
795
+ }
796
+ const res = await this.commands.typedCall('GetFeatures', 'Features');
797
+ this._updateFeatures(res.message);
798
+ return Promise.resolve(res.message);
799
+ }
800
+
735
801
  async checkPassphraseStateSafety(
736
802
  passphraseState?: string,
737
803
  useEmptyPassphrase?: boolean,
@@ -58,6 +58,16 @@ export interface IFrameSwitchTransportMessage {
58
58
  payload: { env: ConnectSettings['env'] };
59
59
  }
60
60
 
61
+ export interface IFrameCallbackMessage {
62
+ event: typeof IFRAME.CALLBACK;
63
+ type: typeof IFRAME.CALLBACK;
64
+ payload: {
65
+ callbackId: string;
66
+ data?: any;
67
+ error?: any;
68
+ };
69
+ }
70
+
61
71
  export const RESPONSE_EVENT = 'RESPONSE_EVENT';
62
72
 
63
73
  export interface MethodResponseMessage {
@@ -1,6 +1,11 @@
1
1
  import { HardwareError } from '@onekeyfe/hd-shared';
2
2
  import { Unsuccessful } from '../types/params';
3
- import { IFrameCallMessage, IFrameCancelMessage, IFrameSwitchTransportMessage } from './call';
3
+ import {
4
+ IFrameCallMessage,
5
+ IFrameCancelMessage,
6
+ IFrameSwitchTransportMessage,
7
+ IFrameCallbackMessage,
8
+ } from './call';
4
9
  import { DeviceEventMessage } from './device';
5
10
  import { IFrameEventMessage } from './iframe';
6
11
  import { UiEventMessage } from './ui-request';
@@ -18,6 +23,7 @@ export type CoreMessage = {
18
23
  | IFrameCallMessage
19
24
  | IFrameCancelMessage
20
25
  | IFrameSwitchTransportMessage
26
+ | IFrameCallbackMessage
21
27
  | UiResponseMessage
22
28
  | UiEventMessage
23
29
  | DeviceEventMessage
@@ -8,6 +8,7 @@ export const IFRAME = {
8
8
  CALL: 'iframe-call',
9
9
  CANCEL: 'iframe-cancel',
10
10
  SWITCH_TRANSPORT: 'iframe-switch-transport',
11
+ CALLBACK: 'iframe-callback',
11
12
  } as const;
12
13
 
13
14
  export interface IFrameInit {
@@ -29,7 +30,17 @@ export interface IFrameSwitchTransport {
29
30
  };
30
31
  }
31
32
 
32
- export type IFrameEvent = IFrameInit | IFrameBridge | IFrameSwitchTransport;
33
+ export interface IFrameCallback {
34
+ type: typeof IFRAME.CALLBACK;
35
+ payload: {
36
+ callbackId: string;
37
+ data?: any;
38
+ error?: any;
39
+ finished?: boolean;
40
+ };
41
+ }
42
+
43
+ export type IFrameEvent = IFrameInit | IFrameBridge | IFrameSwitchTransport | IFrameCallback;
33
44
  export type IFrameEventMessage = IFrameEvent & { event: typeof UI_EVENT };
34
45
 
35
46
  export const createIFrameMessage: MessageFactoryFn<typeof UI_EVENT, IFrameEvent> = (
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { inject, InjectApi } from './inject';
1
+ import { inject, InjectApi, executeCallback, cleanupCallback } from './inject';
2
2
  import { lowLevelInject, LowLevelInjectApi, LowLevelCoreApi } from './lowLevelInject';
3
3
  import { topLevelInject } from './topLevelInject';
4
4
  import { CoreApi } from './types/api';
@@ -14,6 +14,7 @@ export * from './data-manager';
14
14
  export * from './events';
15
15
  export * from './types';
16
16
  export { whitelist, whitelistExtension } from './data/config';
17
+ export { executeCallback, cleanupCallback };
17
18
 
18
19
  const HardwareSdk = ({
19
20
  init,
package/src/inject.ts CHANGED
@@ -1,6 +1,31 @@
1
1
  import { EventEmitter } from 'events';
2
2
  import { CallMethod } from './events';
3
3
  import { CoreApi } from './types/api';
4
+ import type { AllNetworkAddress } from './types/api/allNetworkGetAddress';
5
+
6
+ type CallbackFunction = (data?: any, error?: { message: string; code?: number }) => void;
7
+
8
+ const callbackManager = new Map<string, CallbackFunction>();
9
+
10
+ const generateCallbackId = () =>
11
+ `callback_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
12
+
13
+ const registerCallback = (id: string, callback: CallbackFunction) => {
14
+ callbackManager.set(id, callback);
15
+ };
16
+
17
+ const executeCallback = (id: string, ...args: any[]) => {
18
+ const callback = callbackManager.get(id);
19
+ if (callback) {
20
+ callback(...args);
21
+ }
22
+ };
23
+
24
+ const cleanupCallback = (id: string) => {
25
+ callbackManager.delete(id);
26
+ };
27
+
28
+ export { executeCallback, cleanupCallback };
4
29
 
5
30
  export interface InjectApi {
6
31
  call: CallMethod;
@@ -147,6 +172,28 @@ export const createCoreApi = (
147
172
 
148
173
  allNetworkGetAddress: (connectId, deviceId, params) =>
149
174
  call({ ...params, connectId, deviceId, method: 'allNetworkGetAddress' }),
175
+ allNetworkGetAddressByLoop: (connectId, deviceId, params) => {
176
+ const { onLoopItemResponse, onAllItemsResponse, ...restParams } = params;
177
+
178
+ const callbackId = generateCallbackId();
179
+ registerCallback(callbackId, onLoopItemResponse);
180
+
181
+ const callbackIdFinish = generateCallbackId();
182
+ registerCallback(callbackIdFinish, (data?: AllNetworkAddress[]) => {
183
+ onAllItemsResponse?.(data);
184
+ cleanupCallback(callbackIdFinish);
185
+ cleanupCallback(callbackId);
186
+ });
187
+
188
+ return call({
189
+ ...restParams,
190
+ connectId,
191
+ deviceId,
192
+ method: 'allNetworkGetAddressByLoop',
193
+ callbackId,
194
+ callbackIdFinish,
195
+ });
196
+ },
150
197
 
151
198
  evmGetAddress: (connectId, deviceId, params) =>
152
199
  call({ ...params, connectId, deviceId, method: 'evmGetAddress' }),
@@ -1,4 +1,4 @@
1
- import type { CommonParams, Response } from '../params';
1
+ import type { CommonParams, Response, Unsuccessful } from '../params';
2
2
  import type { CardanoAddressParameters } from './cardano';
3
3
 
4
4
  export type INetwork =
@@ -91,10 +91,10 @@ type AllNetworkAddressPayload =
91
91
  xpubSegwit: string;
92
92
  };
93
93
 
94
- export type AllNetworkAddress = CommonResponseParams & {
94
+ export type AllNetworkAddress = AllNetworkAddressParams & {
95
95
  success: boolean;
96
96
  payload?:
97
- | AllNetworkAddressPayload
97
+ | (AllNetworkAddressPayload & { rootFingerprint: number })
98
98
  | {
99
99
  error: string;
100
100
  code: number;
@@ -108,8 +108,22 @@ export type AllNetworkGetAddressParams = {
108
108
  bundle: AllNetworkAddressParams[];
109
109
  };
110
110
 
111
+ export type AllNetworkGetAddressParamsByLoop = AllNetworkGetAddressParams & {
112
+ callbackId?: string;
113
+ callbackIdFinish?: string;
114
+ onLoopItemResponse: (data?: AllNetworkAddress) => void;
115
+ onAllItemsResponse: (data?: AllNetworkAddress[], error?: Unsuccessful) => void;
116
+ };
117
+
111
118
  export declare function allNetworkGetAddress(
112
119
  connectId: string,
113
120
  deviceId: string,
114
121
  params: CommonParams & AllNetworkGetAddressParams
115
122
  ): Response<AllNetworkAddress[]>;
123
+
124
+ export declare function allNetworkGetAddressByLoop(
125
+ connectId: string,
126
+ deviceId: string,
127
+ params: CommonParams & AllNetworkGetAddressParamsByLoop
128
+ // only return empty array
129
+ ): Response<AllNetworkAddress[]>;
@@ -14,6 +14,7 @@ export type EVMGetPublicKeyParams = {
14
14
  path: string | number[];
15
15
  showOnOneKey?: boolean;
16
16
  chainId?: number;
17
+ useBatch?: boolean;
17
18
  };
18
19
 
19
20
  export declare function evmGetPublicKey(