@onekeyfe/hd-core 1.2.8-alpha.1 → 1.2.8-alpha.11

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 (56) hide show
  1. package/README.md +27 -0
  2. package/__tests__/DeviceCommands.test.ts +66 -13
  3. package/__tests__/btc-derive-context-hash.test.ts +200 -0
  4. package/__tests__/core-error-output.test.ts +34 -3
  5. package/__tests__/device-lifecycle-events.test.ts +73 -24
  6. package/__tests__/device-pool-state.test.ts +50 -0
  7. package/__tests__/protocol-v2-bootloader-mode.test.ts +43 -2
  8. package/__tests__/protocol-v2.test.ts +0 -47
  9. package/__tests__/refresh-device-state.test.ts +19 -17
  10. package/__tests__/sol-sign-offchain-message.test.ts +0 -8
  11. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  12. package/dist/api/GetDeviceState.d.ts.map +1 -1
  13. package/dist/api/btc/BTCDeriveContextHash.d.ts +16 -0
  14. package/dist/api/btc/BTCDeriveContextHash.d.ts.map +1 -0
  15. package/dist/api/index.d.ts +1 -0
  16. package/dist/api/index.d.ts.map +1 -1
  17. package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
  18. package/dist/core/index.d.ts +0 -1
  19. package/dist/core/index.d.ts.map +1 -1
  20. package/dist/device/Device.d.ts +2 -0
  21. package/dist/device/Device.d.ts.map +1 -1
  22. package/dist/device/DeviceCommands.d.ts +4 -4
  23. package/dist/device/DeviceCommands.d.ts.map +1 -1
  24. package/dist/device/DevicePool.d.ts.map +1 -1
  25. package/dist/events/logBlockEvent.d.ts.map +1 -1
  26. package/dist/index.d.ts +18 -5
  27. package/dist/index.js +159 -28
  28. package/dist/inject.d.ts.map +1 -1
  29. package/dist/types/api/btcDeriveContextHash.d.ts +10 -0
  30. package/dist/types/api/btcDeriveContextHash.d.ts.map +1 -0
  31. package/dist/types/api/export.d.ts +1 -0
  32. package/dist/types/api/export.d.ts.map +1 -1
  33. package/dist/types/api/index.d.ts +2 -0
  34. package/dist/types/api/index.d.ts.map +1 -1
  35. package/dist/types/params.d.ts +1 -0
  36. package/dist/types/params.d.ts.map +1 -1
  37. package/dist/utils/patch.d.ts +1 -1
  38. package/dist/utils/patch.d.ts.map +1 -1
  39. package/package.json +4 -4
  40. package/src/api/FirmwareUpdateV4.ts +8 -25
  41. package/src/api/GetDeviceState.ts +2 -5
  42. package/src/api/btc/BTCDeriveContextHash.ts +90 -0
  43. package/src/api/index.ts +1 -0
  44. package/src/api/protocol-v2/DeviceReboot.ts +2 -0
  45. package/src/core/index.ts +3 -7
  46. package/src/data/messages/messages.json +51 -0
  47. package/src/device/Device.ts +11 -1
  48. package/src/device/DeviceCommands.ts +15 -1
  49. package/src/device/DevicePool.ts +12 -2
  50. package/src/events/core.ts +2 -2
  51. package/src/events/logBlockEvent.ts +1 -0
  52. package/src/inject.ts +2 -0
  53. package/src/types/api/btcDeriveContextHash.ts +15 -0
  54. package/src/types/api/export.ts +1 -0
  55. package/src/types/api/index.ts +2 -0
  56. package/src/types/params.ts +1 -1
package/src/core/index.ts CHANGED
@@ -23,7 +23,6 @@ import {
23
23
  createNeedUpgradeFirmwareHardwareError,
24
24
  createNewFirmwareForceUpdateHardwareError,
25
25
  createNewFirmwareUnReleaseHardwareError,
26
- isBleStaleBondHardwareError,
27
26
  } from '@onekeyfe/hd-shared';
28
27
 
29
28
  import { LoggerNames, enableLog, getLogger, setLoggerPostMessage, wait } from '../utils';
@@ -1035,10 +1034,6 @@ export function isMissingDetectedProtocolV2Error(method: BaseMethod, error: unkn
1035
1034
  );
1036
1035
  }
1037
1036
 
1038
- export function isTerminalBleStaleBondError(error: unknown) {
1039
- return isBleStaleBondHardwareError(error);
1040
- }
1041
-
1042
1037
  export function isDeviceIdentityMismatchError(error: unknown) {
1043
1038
  return (
1044
1039
  (error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.DeviceCheckDeviceIdError
@@ -1277,6 +1272,7 @@ const ensureConnected = async (
1277
1272
  HardwareErrorCode.BridgeNotInstalled,
1278
1273
  HardwareErrorCode.BridgeTimeoutError,
1279
1274
  HardwareErrorCode.BridgeNeedsPermission,
1275
+ HardwareErrorCode.WebUsbDeviceAccessError,
1280
1276
  ].includes(error.errorCode)
1281
1277
  ) {
1282
1278
  _deviceList = undefined;
@@ -1363,6 +1359,7 @@ const ensureConnected = async (
1363
1359
  HardwareErrorCode.DeviceDetectInBootloaderMode,
1364
1360
  HardwareErrorCode.BleCharacteristicNotifyChangeFailure,
1365
1361
  HardwareErrorCode.BridgeNeedsPermission,
1362
+ HardwareErrorCode.WebUsbDeviceAccessError,
1366
1363
  HardwareErrorCode.DeviceInterruptedFromUser,
1367
1364
  HardwareErrorCode.CallQueueActionCancelled,
1368
1365
  ].includes(error.errorCode) ||
@@ -1370,7 +1367,6 @@ const ensureConnected = async (
1370
1367
  [HardwareErrorCode.BleDeviceDisconnected, HardwareErrorCode.PollingTimeout].includes(
1371
1368
  error.errorCode
1372
1369
  )) ||
1373
- isTerminalBleStaleBondError(error) ||
1374
1370
  isDeviceIdentityMismatchError(error)
1375
1371
  ) {
1376
1372
  reject(error);
@@ -1593,7 +1589,7 @@ const onDeviceConnectHandler = (device: Device) => {
1593
1589
 
1594
1590
  const onDeviceDisconnectHandler = (device: Device) => {
1595
1591
  device.clearPreInitialized();
1596
- const deviceObject = device.toMessageObject();
1592
+ const deviceObject = device.toDisconnectMessageObject();
1597
1593
  if (!deviceObject) return;
1598
1594
  postMessage(createDeviceMessage(DEVICE.DISCONNECT, { device: deviceObject }));
1599
1595
  };
@@ -12485,6 +12485,8 @@
12485
12485
  "(has_bitcoin_only_values)": true
12486
12486
  },
12487
12487
  "values": {
12488
+ "MessageType_BabylonDeriveContextHash": 10054,
12489
+ "MessageType_BabylonDerivedContextHash": 10055,
12488
12490
  "MessageType_Initialize": 0,
12489
12491
  "MessageType_Ping": 1,
12490
12492
  "MessageType_Success": 2,
@@ -12949,6 +12951,55 @@
12949
12951
  "MessageType_UpgradeFileHeader": 10050
12950
12952
  }
12951
12953
  },
12954
+ "CanonicalBitcoinNetwork": {
12955
+ "values": {
12956
+ "BITCOIN_MAINNET": 0,
12957
+ "BITCOIN_TESTNET": 1,
12958
+ "BITCOIN_SIGNET": 2,
12959
+ "BITCOIN_REGTEST": 3
12960
+ }
12961
+ },
12962
+ "BabylonDeriveContextHash": {
12963
+ "fields": {
12964
+ "address_n": {
12965
+ "rule": "repeated",
12966
+ "type": "uint32",
12967
+ "id": 1,
12968
+ "options": {
12969
+ "packed": false
12970
+ }
12971
+ },
12972
+ "script_type": {
12973
+ "rule": "required",
12974
+ "type": "InputScriptType",
12975
+ "id": 2
12976
+ },
12977
+ "app_name": {
12978
+ "rule": "required",
12979
+ "type": "bytes",
12980
+ "id": 3
12981
+ },
12982
+ "context": {
12983
+ "rule": "required",
12984
+ "type": "bytes",
12985
+ "id": 4
12986
+ },
12987
+ "network": {
12988
+ "rule": "required",
12989
+ "type": "CanonicalBitcoinNetwork",
12990
+ "id": 5
12991
+ }
12992
+ }
12993
+ },
12994
+ "BabylonDerivedContextHash": {
12995
+ "fields": {
12996
+ "secret": {
12997
+ "rule": "required",
12998
+ "type": "bytes",
12999
+ "id": 1
13000
+ }
13001
+ }
13002
+ },
12952
13003
  "google": {
12953
13004
  "nested": {
12954
13005
  "protobuf": {
@@ -248,6 +248,9 @@ export class Device extends EventEmitter {
248
248
  /** Canonical device-state cache; legacy Features is a compatibility projection. */
249
249
  private stateStore = new DeviceStateStore();
250
250
 
251
+ /** Retain the old public identity only for disconnect notifications after wipe. */
252
+ private deviceBeforeWipe: DeviceTyped | null = null;
253
+
251
254
  /** Force the next initialization to reload DeviceInfo after reconnect or reboot. */
252
255
  private protocolV2StateNeedsReload = false;
253
256
 
@@ -351,6 +354,8 @@ export class Device extends EventEmitter {
351
354
  toMessageObject(): DeviceTyped | null {
352
355
  if (this.isUnacquired() || !this.features) return null;
353
356
 
357
+ this.deviceBeforeWipe = null;
358
+
354
359
  const env = DataManager.getSettings('env');
355
360
  const deviceType = this.getCurrentDeviceType();
356
361
 
@@ -395,6 +400,10 @@ export class Device extends EventEmitter {
395
400
  };
396
401
  }
397
402
 
403
+ toDisconnectMessageObject(): DeviceTyped | null {
404
+ return this.toMessageObject() ?? this.deviceBeforeWipe;
405
+ }
406
+
398
407
  /**
399
408
  * Device connect
400
409
  * @returns {Promise<boolean>}
@@ -1364,6 +1373,7 @@ export class Device extends EventEmitter {
1364
1373
  }
1365
1374
 
1366
1375
  invalidateAfterWipe() {
1376
+ this.deviceBeforeWipe = this.toMessageObject() ?? this.deviceBeforeWipe;
1367
1377
  const deviceId = this.getCurrentDeviceId();
1368
1378
  if (deviceId) {
1369
1379
  deviceWalletSessionStore.deleteDevice(deviceId);
@@ -1801,7 +1811,7 @@ export class Device extends EventEmitter {
1801
1811
  // both allow and require cases might generate single unexpected mode
1802
1812
  if (!this.isUnacquired()) {
1803
1813
  // allow cases
1804
- if (this.isBootloader() && !this.isProtocolV2() && !allow.includes(UI_REQUEST.BOOTLOADER)) {
1814
+ if ((this.isBootloader() || this.isRomloader()) && !allow.includes(UI_REQUEST.BOOTLOADER)) {
1805
1815
  return UI_REQUEST.BOOTLOADER;
1806
1816
  }
1807
1817
  if (!this.isInitialized() && !allow.includes(UI_REQUEST.NOT_INITIALIZE)) {
@@ -549,6 +549,16 @@ export class DeviceCommands {
549
549
  this.device.isProtocolV2() &&
550
550
  DEVICE_CONTROL_CALLS.has(callType) &&
551
551
  subcode === DeviceErrorCode.DeviceError_Busy;
552
+ const isProtocolV2PinCancelledBusyFailure =
553
+ this.device.isProtocolV2() &&
554
+ !DEVICE_SESSION_CALLS.has(callType) &&
555
+ subcode === DeviceSessionErrorCode.DeviceSessionError_UserCancelled &&
556
+ /^pin cancelled$/i.test(normalizedMessage);
557
+ const isProtocolV2FirmwareUpdateBusyFailure =
558
+ this.device.isProtocolV2() &&
559
+ /^requested command not allowed while a firmware update is in progress$/i.test(
560
+ normalizedMessage
561
+ );
552
562
  const isLegacyProtocolV2LockedFailure =
553
563
  this.device.isProtocolV2() && /^device (?:is )?locked$/i.test(normalizedMessage);
554
564
  if (
@@ -606,7 +616,11 @@ export class DeviceCommands {
606
616
  subcode,
607
617
  firmwareMessage: message,
608
618
  });
609
- } else if (isProtocolV2DeviceBusyFailure) {
619
+ } else if (
620
+ isProtocolV2DeviceBusyFailure ||
621
+ isProtocolV2PinCancelledBusyFailure ||
622
+ isProtocolV2FirmwareUpdateBusyFailure
623
+ ) {
610
624
  error = ERRORS.TypedError(HardwareErrorCode.DeviceBusy, message, {
611
625
  failureCode: code,
612
626
  subcode,
@@ -114,7 +114,11 @@ export class DevicePool extends EventEmitter {
114
114
  const exist = canPathIdentifyDevice(cachedPath)
115
115
  ? descriptorList.find(d => d.path === cachedPath)
116
116
  : undefined;
117
- if (exist && !initOptions?.forceProtocolDetection) {
117
+ if (
118
+ exist &&
119
+ !initOptions?.forceProtocolDetection &&
120
+ !(device.needReloadDevice && device.isUnacquired())
121
+ ) {
118
122
  // Log.debug('find existed Device: ', connectId);
119
123
  device.updateDescriptor(exist, true);
120
124
  await this._refreshRuntimeState(device, initOptions);
@@ -170,7 +174,13 @@ export class DevicePool extends EventEmitter {
170
174
  const forceProtocolDetection = initOptions?.forceProtocolDetection === true;
171
175
  const isNewDevice = !cachedDevice;
172
176
  const device = cachedDevice ?? Device.fromDescriptor(descriptor);
173
- if (isNewDevice || forceProtocolDetection) {
177
+ if (
178
+ isNewDevice ||
179
+ forceProtocolDetection ||
180
+ (device.needReloadDevice && device.isUnacquired())
181
+ ) {
182
+ // Wipe invalidates state while the same USB path can remain discoverable.
183
+ if (cachedDevice) device.updateDescriptor(descriptor, true);
174
184
  device.deviceConnector = this.connector;
175
185
  // Search/discovery acquires outside Device.run(). Start a new attempt so
176
186
  // a previous user cancel does not hide this device from later searches.
@@ -54,9 +54,9 @@ export const parseMessage = (messageData: any): CoreMessage => {
54
54
  };
55
55
 
56
56
  export const createErrorMessage = (error: Error & { code?: string | number }): Unsuccessful => {
57
- let payload = { error: error.message, code: error.code };
57
+ let payload: Unsuccessful['payload'] = { error: error.message, code: error.code };
58
58
  if (error instanceof HardwareError) {
59
- payload = { error: error.message, code: error.errorCode };
59
+ payload = { error: error.message, code: error.errorCode, params: error.params };
60
60
  }
61
61
  return {
62
62
  success: false,
@@ -11,6 +11,7 @@ export const LogBlockEvent: Set<string> = new Set([
11
11
  // These resource/file APIs did not exist in 1.1.32. Skip the payload so
12
12
  // the log layer does not copy huge Base64 or binary data.
13
13
  const LogPayloadBlockMethod: Set<string> = new Set([
14
+ 'btcDeriveContextHash',
14
15
  'deviceUploadNft',
15
16
  'deviceUploadWallpaper',
16
17
  'uploadPortfolio',
package/src/inject.ts CHANGED
@@ -309,6 +309,8 @@ export const createCoreApi = (
309
309
  call({ ...params, connectId, deviceId, method: 'btcGetAddress' }),
310
310
  btcGetPublicKey: (connectId, deviceId, params) =>
311
311
  call({ ...params, connectId, deviceId, method: 'btcGetPublicKey' }),
312
+ btcDeriveContextHash: (connectId, deviceId, params) =>
313
+ call({ ...params, connectId, deviceId, method: 'btcDeriveContextHash' }),
312
314
  btcSignMessage: (connectId, deviceId, params) =>
313
315
  call({ ...params, connectId, deviceId, method: 'btcSignMessage' }),
314
316
  btcSignPsbt: (connectId, deviceId, params) =>
@@ -0,0 +1,15 @@
1
+ import type { BabylonDerivedContextHash } from '@onekeyfe/hd-transport';
2
+ import type { CommonParams, Response } from '../params';
3
+
4
+ export type BTCDeriveContextHashParams = {
5
+ path: string | number[];
6
+ appName: string;
7
+ context: string;
8
+ network: 'bitcoin-mainnet' | 'bitcoin-testnet' | 'bitcoin-signet' | 'bitcoin-regtest';
9
+ };
10
+
11
+ export declare function btcDeriveContextHash(
12
+ connectId: string,
13
+ deviceId: string,
14
+ params: CommonParams & BTCDeriveContextHashParams
15
+ ): Response<BabylonDerivedContextHash>;
@@ -1,5 +1,6 @@
1
1
  export type { BTCAddress, BTCGetAddressParams } from './btcGetAddress';
2
2
  export type { BTCPublicKey, BTCGetPublicKeyParams } from './btcGetPublicKey';
3
+ export type { BTCDeriveContextHashParams } from './btcDeriveContextHash';
3
4
  export type { BTCSignMessageParams } from './btcSignMessage';
4
5
  export type { BTCVerifyMessageParams } from './btcVerifyMessage';
5
6
  export type {
@@ -73,6 +73,7 @@ import type { evmSignTypedData } from './evmSignTypedData';
73
73
  import type { evmVerifyMessage } from './evmVerifyMessage';
74
74
  import type { btcGetAddress } from './btcGetAddress';
75
75
  import type { btcGetPublicKey } from './btcGetPublicKey';
76
+ import type { btcDeriveContextHash } from './btcDeriveContextHash';
76
77
  import type { btcSignMessage } from './btcSignMessage';
77
78
  import type { btcSignPsbt } from './btcSignPsbt';
78
79
  import type { btcSignTransaction } from './btcSignTransaction';
@@ -286,6 +287,7 @@ export type CoreApi = {
286
287
  */
287
288
  btcGetAddress: typeof btcGetAddress;
288
289
  btcGetPublicKey: typeof btcGetPublicKey;
290
+ btcDeriveContextHash: typeof btcDeriveContextHash;
289
291
  btcSignMessage: typeof btcSignMessage;
290
292
  btcSignPsbt: typeof btcSignPsbt;
291
293
  btcSignTransaction: typeof btcSignTransaction;
@@ -83,7 +83,7 @@ export type Params<T> = CommonParams & T & { bundle?: undefined };
83
83
 
84
84
  export interface Unsuccessful {
85
85
  success: false;
86
- payload: { error: string; code?: string | number };
86
+ payload: { error: string; code?: string | number; params?: Record<string, unknown> };
87
87
  }
88
88
 
89
89
  export interface Success<T> {