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

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 (57) hide show
  1. package/__tests__/core-dispose.test.ts +114 -1
  2. package/__tests__/core-error-output.test.ts +21 -0
  3. package/__tests__/device-connector-protocol.test.ts +5 -2
  4. package/__tests__/device-lifecycle-events.test.ts +22 -3
  5. package/__tests__/logBlockEvent.test.ts +43 -0
  6. package/__tests__/sol-sign-offchain-message.test.ts +8 -0
  7. package/__tests__/usb-identity-probe.test.ts +358 -0
  8. package/__tests__/zcash-protobuf.test.ts +141 -0
  9. package/__tests__/zcash-sign-pczt.test.ts +387 -0
  10. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  11. package/dist/api/SearchDevices.d.ts +21 -1
  12. package/dist/api/SearchDevices.d.ts.map +1 -1
  13. package/dist/api/index.d.ts +2 -0
  14. package/dist/api/index.d.ts.map +1 -1
  15. package/dist/api/zcash/ZcashGetAddress.d.ts +12 -0
  16. package/dist/api/zcash/ZcashGetAddress.d.ts.map +1 -0
  17. package/dist/api/zcash/ZcashSignPczt.d.ts +16 -0
  18. package/dist/api/zcash/ZcashSignPczt.d.ts.map +1 -0
  19. package/dist/core/index.d.ts +3 -1
  20. package/dist/core/index.d.ts.map +1 -1
  21. package/dist/device/Device.d.ts.map +1 -1
  22. package/dist/device/DeviceCommands.d.ts +4 -4
  23. package/dist/events/logBlockEvent.d.ts.map +1 -1
  24. package/dist/index.d.ts +70 -6
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3350 -2865
  27. package/dist/inject.d.ts.map +1 -1
  28. package/dist/types/api/export.d.ts +2 -0
  29. package/dist/types/api/export.d.ts.map +1 -1
  30. package/dist/types/api/index.d.ts +4 -0
  31. package/dist/types/api/index.d.ts.map +1 -1
  32. package/dist/types/api/zcashGetAddress.d.ts +22 -0
  33. package/dist/types/api/zcashGetAddress.d.ts.map +1 -0
  34. package/dist/types/api/zcashSignPczt.d.ts +9 -0
  35. package/dist/types/api/zcashSignPczt.d.ts.map +1 -0
  36. package/dist/types/device.d.ts +9 -0
  37. package/dist/types/device.d.ts.map +1 -1
  38. package/dist/utils/patch.d.ts +1 -1
  39. package/dist/utils/patch.d.ts.map +1 -1
  40. package/package.json +4 -4
  41. package/src/api/FirmwareUpdateV4.ts +4 -7
  42. package/src/api/SearchDevices.ts +172 -7
  43. package/src/api/index.ts +2 -0
  44. package/src/api/zcash/ZcashGetAddress.ts +121 -0
  45. package/src/api/zcash/ZcashSignPczt.ts +155 -0
  46. package/src/core/index.ts +45 -14
  47. package/src/data/messages/messages-protocol-v2.json +138 -1
  48. package/src/device/Device.ts +3 -1
  49. package/src/device/DeviceConnector.ts +4 -4
  50. package/src/events/logBlockEvent.ts +4 -2
  51. package/src/index.ts +1 -0
  52. package/src/inject.ts +4 -0
  53. package/src/types/api/export.ts +2 -0
  54. package/src/types/api/index.ts +8 -0
  55. package/src/types/api/zcashGetAddress.ts +36 -0
  56. package/src/types/api/zcashSignPczt.ts +18 -0
  57. package/src/types/device.ts +12 -0
package/src/api/index.ts CHANGED
@@ -175,3 +175,5 @@ export { default as benfenSignTransaction } from './benfen/BenfenSignTransaction
175
175
 
176
176
  export { default as neoGetAddress } from './neo/NeoGetAddress';
177
177
  export { default as neoSignTransaction } from './neo/NeoSignTransaction';
178
+ export { default as zcashGetAddress } from './zcash/ZcashGetAddress';
179
+ export { default as zcashSignPczt } from './zcash/ZcashSignPczt';
@@ -0,0 +1,121 @@
1
+ import { ZcashAddressScope, ZcashAddressType } from '@onekeyfe/hd-transport';
2
+
3
+ import { BaseMethod } from '../BaseMethod';
4
+ import { serializedPath, toHardened, validatePath } from '../helpers/pathUtils';
5
+ import { invalidParameter, validateParams, validateResult } from '../helpers/paramsValidator';
6
+ import { UI_REQUEST } from '../../constants/ui-request';
7
+
8
+ import type { ZcashGetAddress as HardwareZcashGetAddress } from '@onekeyfe/hd-transport';
9
+ import type { ZcashGetAddressParams, ZcashAddress } from '../../types/api/zcashGetAddress';
10
+ import type { DeviceFirmwareRange } from '../../types';
11
+
12
+ export default class ZcashGetAddress extends BaseMethod<HardwareZcashGetAddress[]> {
13
+ hasBundle = false;
14
+
15
+ getSupportedProtocols() {
16
+ return ['V2'] as const;
17
+ }
18
+
19
+ init() {
20
+ this.checkDeviceId = true;
21
+ this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
22
+ this.strictCheckDeviceSupport = true;
23
+
24
+ this.hasBundle = !!this.payload?.bundle;
25
+ const payload = this.hasBundle ? this.payload : { bundle: [this.payload] };
26
+
27
+ validateParams(payload, [{ name: 'bundle', type: 'array' }]);
28
+
29
+ this.params = [];
30
+ payload.bundle.forEach((batch: ZcashGetAddressParams) => {
31
+ // ZIP-32 account path: m/32'/133'/account'
32
+ const addressN = validatePath(batch.path, 3);
33
+ if (
34
+ addressN.length !== 3 ||
35
+ addressN[0] !== toHardened(32) ||
36
+ addressN[1] !== toHardened(133) ||
37
+ addressN[2] < toHardened(0) ||
38
+ addressN[2] > 0xffffffff
39
+ ) {
40
+ throw invalidParameter("Zcash requires a ZIP-32 account path m/32'/133'/account'");
41
+ }
42
+ const addressType = batch.addressType ?? ZcashAddressType.UNIFIED_ORCHARD_P2PKH;
43
+ const scope = batch.scope ?? ZcashAddressScope.EXTERNAL;
44
+ const diversifierIndex = batch.diversifierIndex ?? 0;
45
+ if (
46
+ ![
47
+ ZcashAddressType.UNIFIED_ORCHARD_P2PKH,
48
+ ZcashAddressType.TRANSPARENT_P2PKH,
49
+ ZcashAddressType.UNIFIED_ORCHARD,
50
+ ].includes(addressType) ||
51
+ ![ZcashAddressScope.EXTERNAL, ZcashAddressScope.INTERNAL].includes(scope)
52
+ ) {
53
+ throw invalidParameter('Invalid Zcash address type or scope');
54
+ }
55
+ const maxIndex = addressType === ZcashAddressType.UNIFIED_ORCHARD ? 0xffffffff : 0x7fffffff;
56
+ if (
57
+ !Number.isSafeInteger(diversifierIndex) ||
58
+ diversifierIndex < 0 ||
59
+ diversifierIndex > maxIndex
60
+ ) {
61
+ throw invalidParameter('Invalid Zcash diversifier index');
62
+ }
63
+
64
+ validateParams(batch, [
65
+ { name: 'path', required: true },
66
+ { name: 'showOnOneKey', type: 'boolean' },
67
+ { name: 'includeUfvk', type: 'boolean' },
68
+ { name: 'includeSeedFingerprint', type: 'boolean' },
69
+ ]);
70
+
71
+ this.params.push({
72
+ address_n: addressN,
73
+ address_type: addressType,
74
+ scope,
75
+ diversifier_index: diversifierIndex,
76
+ show_display: batch.showOnOneKey ?? true,
77
+ include_ufvk: batch.includeUfvk ?? false,
78
+ include_seed_fingerprint: batch.includeSeedFingerprint ?? false,
79
+ });
80
+ });
81
+ }
82
+
83
+ getVersionRange(): DeviceFirmwareRange {
84
+ return {
85
+ model_pro2: {
86
+ min: '0.0.0',
87
+ },
88
+ };
89
+ }
90
+
91
+ async run() {
92
+ const responses: ZcashAddress[] = [];
93
+
94
+ for (let i = 0; i < this.params.length; i++) {
95
+ const param = this.params[i];
96
+
97
+ const res = await this.device.commands.typedCall('ZcashGetAddress', 'ZcashAddress', {
98
+ ...param,
99
+ });
100
+
101
+ const path = serializedPath(param.address_n);
102
+ responses.push({
103
+ path,
104
+ address: res.message.address,
105
+ ufvk: res.message.ufvk,
106
+ seedFingerprint: res.message.seed_fingerprint,
107
+ });
108
+
109
+ this.postPreviousAddressMessage({
110
+ address: res.message.address,
111
+ path,
112
+ });
113
+ }
114
+
115
+ validateResult(responses, ['address'], {
116
+ expectedLength: this.params.length,
117
+ });
118
+
119
+ return Promise.resolve(this.hasBundle ? responses : responses[0]);
120
+ }
121
+ }
@@ -0,0 +1,155 @@
1
+ import { bytesToHex } from '@noble/hashes/utils';
2
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
3
+
4
+ import { BaseMethod } from '../BaseMethod';
5
+ import { invalidParameter, validateParams } from '../helpers/paramsValidator';
6
+ import { stripHexPrefix } from '../helpers/hexUtils';
7
+ import { UI_REQUEST } from '../../constants/ui-request';
8
+
9
+ import type { ZcashSignPczt as HardwareZcashSignPczt } from '@onekeyfe/hd-transport';
10
+ import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
11
+ import type { ZcashSignedPczt } from '../../types/api/zcashSignPczt';
12
+ import type { DeviceFirmwareRange } from '../../types';
13
+
14
+ const CHUNK_BYTE_SIZE = 1024;
15
+ // Host memory sanity bound on the device-announced length, not a device limit.
16
+ const SIGNED_PCZT_SANITY_MAX_BYTES = 16 * 1024 * 1024;
17
+
18
+ export default class ZcashSignPczt extends BaseMethod<HardwareZcashSignPczt> {
19
+ pczt: Buffer = Buffer.alloc(0);
20
+
21
+ getSupportedProtocols() {
22
+ return ['V2'] as const;
23
+ }
24
+
25
+ init() {
26
+ this.checkDeviceId = true;
27
+ this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
28
+ this.strictCheckDeviceSupport = true;
29
+
30
+ validateParams(this.payload, [{ name: 'pczt', type: 'hexString', required: true }]);
31
+
32
+ // Reject odd-length hex instead of left-padding it, which would shift every nibble.
33
+ const pcztHex = stripHexPrefix(this.payload.pczt);
34
+ if (pcztHex.length % 2 !== 0) {
35
+ throw invalidParameter('pczt hex must have an even length');
36
+ }
37
+ this.pczt = Buffer.from(pcztHex, 'hex');
38
+ if (this.pczt.length === 0) {
39
+ throw invalidParameter('pczt is empty');
40
+ }
41
+
42
+ this.params = {
43
+ pczt_length: this.pczt.length,
44
+ pczt_initial_chunk: bytesToHex(this.pczt.subarray(0, CHUNK_BYTE_SIZE)),
45
+ };
46
+ }
47
+
48
+ getVersionRange(): DeviceFirmwareRange {
49
+ return {
50
+ model_pro2: {
51
+ min: '0.0.0',
52
+ },
53
+ };
54
+ }
55
+
56
+ // Upload: the device decides every chunk length via ZcashPcztChunkRequest and
57
+ // the host must answer with exactly that many bytes.
58
+ uploadPczt = async (
59
+ typedCall: TypedCall,
60
+ res: TypedResponseMessage<'ZcashSignedPczt'> | TypedResponseMessage<'ZcashPcztChunkRequest'>,
61
+ offset: number
62
+ ): Promise<TypedResponseMessage<'ZcashSignedPczt'>> => {
63
+ if (res.type === 'ZcashSignedPczt') {
64
+ if (offset !== this.pczt.length) {
65
+ throw ERRORS.TypedError(
66
+ HardwareErrorCode.ResponseUnexpectTypeError,
67
+ 'device completed signing before receiving the whole pczt'
68
+ );
69
+ }
70
+ return res;
71
+ }
72
+
73
+ const { chunk_length: chunkLength } = res.message;
74
+ if (
75
+ !Number.isSafeInteger(chunkLength) ||
76
+ chunkLength <= 0 ||
77
+ offset + chunkLength > this.pczt.length
78
+ ) {
79
+ throw ERRORS.TypedError(
80
+ HardwareErrorCode.ResponseUnexpectTypeError,
81
+ `device requested ${chunkLength} bytes at offset ${offset} of ${this.pczt.length}`
82
+ );
83
+ }
84
+
85
+ const chunk = this.pczt.subarray(offset, offset + chunkLength);
86
+ const next = await typedCall(
87
+ 'ZcashPcztChunkAck',
88
+ ['ZcashSignedPczt', 'ZcashPcztChunkRequest'],
89
+ {
90
+ data_chunk: bytesToHex(chunk),
91
+ }
92
+ );
93
+
94
+ return this.uploadPczt(typedCall, next, offset + chunkLength);
95
+ };
96
+
97
+ // Download: the host decides chunk lengths via ZcashSignedPcztChunkRequest
98
+ // until the announced pczt_length has been received.
99
+ downloadSignedPczt = async (
100
+ typedCall: TypedCall,
101
+ res: TypedResponseMessage<'ZcashSignedPczt'>
102
+ ): Promise<Buffer> => {
103
+ const { pczt_length: total, pczt_initial_chunk: initial } = res.message;
104
+ if (!Number.isSafeInteger(total) || total <= 0 || total > SIGNED_PCZT_SANITY_MAX_BYTES) {
105
+ throw ERRORS.TypedError(
106
+ HardwareErrorCode.ResponseUnexpectTypeError,
107
+ `device announced invalid signed pczt length ${total}`
108
+ );
109
+ }
110
+
111
+ const parts: Buffer[] = [Buffer.from(initial ?? '', 'hex')];
112
+ let received = parts[0].length;
113
+ if (received > total) {
114
+ throw ERRORS.TypedError(
115
+ HardwareErrorCode.ResponseUnexpectTypeError,
116
+ 'device returned more initial pczt bytes than announced'
117
+ );
118
+ }
119
+
120
+ while (received < total) {
121
+ const chunkLength = Math.min(CHUNK_BYTE_SIZE, total - received);
122
+ const ack = await typedCall('ZcashSignedPcztChunkRequest', 'ZcashPcztChunkAck', {
123
+ chunk_length: chunkLength,
124
+ });
125
+ const chunk = Buffer.from(ack.message.data_chunk ?? '', 'hex');
126
+ if (chunk.length !== chunkLength) {
127
+ throw ERRORS.TypedError(
128
+ HardwareErrorCode.ResponseUnexpectTypeError,
129
+ `device returned ${chunk.length} of ${chunkLength} requested bytes at offset ${received} of ${total}`
130
+ );
131
+ }
132
+ parts.push(chunk);
133
+ received += chunk.length;
134
+ }
135
+
136
+ return Buffer.concat(parts);
137
+ };
138
+
139
+ async run(): Promise<ZcashSignedPczt> {
140
+ const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
141
+
142
+ const first = await typedCall('ZcashSignPczt', ['ZcashSignedPczt', 'ZcashPcztChunkRequest'], {
143
+ ...this.params,
144
+ });
145
+
146
+ const signed = await this.uploadPczt(
147
+ typedCall,
148
+ first,
149
+ Math.min(CHUNK_BYTE_SIZE, this.pczt.length)
150
+ );
151
+ const pczt = await this.downloadSignedPczt(typedCall, signed);
152
+
153
+ return { pczt: bytesToHex(pczt) };
154
+ }
155
+ }
package/src/core/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import semver from 'semver';
2
+ import { getOwnedUsbDeviceIdentity } from '../api/SearchDevices';
2
3
  import EventEmitter from 'events';
3
4
  import {
4
5
  DeviceSessionPinType,
@@ -125,6 +126,8 @@ const parseInitOptions = (method?: BaseMethod): InitOptions => ({
125
126
  });
126
127
 
127
128
  let _core: Core | undefined;
129
+ let transportSwitchGeneration = 0;
130
+ let pendingTransportSwitch: Promise<void> = Promise.resolve();
128
131
  let _deviceList: DeviceList | undefined;
129
132
  let _connector: DeviceConnector | undefined;
130
133
  let _uiPromises: UiPromise<UiPromiseResponse['type']>[] = []; // Waiting for ui response
@@ -990,15 +993,11 @@ function canSkipInitialize(method: BaseMethod, device: Device): boolean {
990
993
  }
991
994
 
992
995
  export function isRetryableBleProtocolV2ProbeError(method: BaseMethod, error: unknown) {
993
- const typedError = error as { errorCode?: unknown; message?: unknown };
994
- const message =
995
- typeof typedError?.message === 'string' ? typedError.message : String(error ?? '');
996
+ const typedError = error as { errorCode?: unknown; params?: { expectedProtocol?: unknown } };
996
997
  return (
997
998
  method.payload.connectProtocol === 'V2' &&
998
- typedError?.errorCode === HardwareErrorCode.RuntimeError &&
999
- message.includes('Device protocol mismatch') &&
1000
- message.includes('expected V2') &&
1001
- message.includes('did not respond to expected protocol')
999
+ typedError?.errorCode === HardwareErrorCode.TransportProtocolProbeFailed &&
1000
+ typedError.params?.expectedProtocol === 'V2'
1002
1001
  );
1003
1002
  }
1004
1003
 
@@ -1008,7 +1007,7 @@ export function isRetryableBleConnectionError(method: BaseMethod, error: unknown
1008
1007
  }
1009
1008
  const typedError = error as {
1010
1009
  errorCode?: unknown;
1011
- params?: { acquireDeadlineExceeded?: unknown };
1010
+ params?: { acquireDeadlineExceeded?: unknown; expectedProtocol?: unknown };
1012
1011
  };
1013
1012
  if (
1014
1013
  typedError?.errorCode === HardwareErrorCode.BleTimeoutError &&
@@ -1019,6 +1018,8 @@ export function isRetryableBleConnectionError(method: BaseMethod, error: unknown
1019
1018
  return (
1020
1019
  typedError?.errorCode === HardwareErrorCode.BleTimeoutError ||
1021
1020
  typedError?.errorCode === HardwareErrorCode.BleConnectedError ||
1021
+ (typedError?.errorCode === HardwareErrorCode.TransportProtocolProbeFailed &&
1022
+ !typedError.params?.expectedProtocol) ||
1022
1023
  isRetryableBleProtocolV2ProbeError(method, error) ||
1023
1024
  isMissingDetectedProtocolV2Error(method, error)
1024
1025
  );
@@ -1273,6 +1274,8 @@ const ensureConnected = async (
1273
1274
  HardwareErrorCode.BridgeTimeoutError,
1274
1275
  HardwareErrorCode.BridgeNeedsPermission,
1275
1276
  HardwareErrorCode.WebUsbDeviceAccessError,
1277
+ HardwareErrorCode.TransportProtocolProbeFailed,
1278
+ HardwareErrorCode.TransportProtocolMismatch,
1276
1279
  ].includes(error.errorCode)
1277
1280
  ) {
1278
1281
  _deviceList = undefined;
@@ -1360,6 +1363,8 @@ const ensureConnected = async (
1360
1363
  HardwareErrorCode.BleCharacteristicNotifyChangeFailure,
1361
1364
  HardwareErrorCode.BridgeNeedsPermission,
1362
1365
  HardwareErrorCode.WebUsbDeviceAccessError,
1366
+ HardwareErrorCode.TransportProtocolProbeFailed,
1367
+ HardwareErrorCode.TransportProtocolMismatch,
1363
1368
  HardwareErrorCode.DeviceInterruptedFromUser,
1364
1369
  HardwareErrorCode.CallQueueActionCancelled,
1365
1370
  ].includes(error.errorCode) ||
@@ -1826,6 +1831,10 @@ export default class Core extends EventEmitter {
1826
1831
 
1827
1832
  private requestQueue = new RequestQueue();
1828
1833
 
1834
+ getOwnedUsbDeviceIdentity(descriptor: Parameters<typeof getOwnedUsbDeviceIdentity>[0]) {
1835
+ return getOwnedUsbDeviceIdentity(descriptor, this.requestQueue);
1836
+ }
1837
+
1829
1838
  private disposePromise?: Promise<void>;
1830
1839
 
1831
1840
  // background task
@@ -1959,6 +1968,8 @@ export default class Core extends EventEmitter {
1959
1968
 
1960
1969
  private async disposeResources(): Promise<void> {
1961
1970
  Log.debug(`[Core] Disposing SDK instance: ${this.sdkInstanceId}`);
1971
+ transportSwitchGeneration += 1;
1972
+ pendingTransportSwitch = Promise.resolve();
1962
1973
  pollingManager.stopAll();
1963
1974
  this.requestQueue.abortAllRequests();
1964
1975
  cleanup();
@@ -1993,6 +2004,8 @@ export default class Core extends EventEmitter {
1993
2004
  }
1994
2005
 
1995
2006
  export const initCore = () => {
2007
+ transportSwitchGeneration += 1;
2008
+ pendingTransportSwitch = Promise.resolve();
1996
2009
  const core = new Core();
1997
2010
  _core = core;
1998
2011
  return core;
@@ -2022,6 +2035,8 @@ export const init = async (
2022
2035
  plugin?: LowlevelTransportSharedPlugin
2023
2036
  ) => {
2024
2037
  try {
2038
+ transportSwitchGeneration += 1;
2039
+ pendingTransportSwitch = Promise.resolve();
2025
2040
  await DataManager.load(settings);
2026
2041
  initTransport(Transport, plugin);
2027
2042
  enableLog(DataManager.getSettings('debug'));
@@ -2047,10 +2062,26 @@ export const switchTransport = ({
2047
2062
  Transport: any;
2048
2063
  plugin?: LowlevelTransportSharedPlugin;
2049
2064
  }) => {
2050
- DataManager.updateEnv(env);
2051
- TransportManager.setTransport(Transport, plugin);
2052
- _deviceList = undefined;
2053
- DevicePool.resetState();
2054
- _connector = undefined;
2055
- initConnector();
2065
+ const generation = transportSwitchGeneration;
2066
+ // Preserve request order while native transport cleanup is pending.
2067
+ const switching = pendingTransportSwitch
2068
+ .catch(() => undefined)
2069
+ .then(async () => {
2070
+ if (generation !== transportSwitchGeneration) {
2071
+ throw ERRORS.TypedError(HardwareErrorCode.NotInitialized);
2072
+ }
2073
+ _connector?.stop();
2074
+ await TransportManager.getTransport()?.stop?.();
2075
+ if (generation !== transportSwitchGeneration) {
2076
+ throw ERRORS.TypedError(HardwareErrorCode.NotInitialized);
2077
+ }
2078
+ DataManager.updateEnv(env);
2079
+ TransportManager.setTransport(Transport, plugin);
2080
+ _deviceList = undefined;
2081
+ DevicePool.resetState();
2082
+ _connector = undefined;
2083
+ initConnector();
2084
+ });
2085
+ pendingTransportSwitch = switching;
2086
+ return switching;
2056
2087
  };
@@ -11034,6 +11034,61 @@
11034
11034
  }
11035
11035
  }
11036
11036
  },
11037
+ "ZcashSignPczt": {
11038
+ "fields": {
11039
+ "pczt_length": {
11040
+ "rule": "required",
11041
+ "type": "uint32",
11042
+ "id": 1
11043
+ },
11044
+ "pczt_initial_chunk": {
11045
+ "rule": "required",
11046
+ "type": "bytes",
11047
+ "id": 2
11048
+ }
11049
+ }
11050
+ },
11051
+ "ZcashPcztChunkRequest": {
11052
+ "fields": {
11053
+ "chunk_length": {
11054
+ "rule": "required",
11055
+ "type": "uint32",
11056
+ "id": 1
11057
+ }
11058
+ }
11059
+ },
11060
+ "ZcashPcztChunkAck": {
11061
+ "fields": {
11062
+ "data_chunk": {
11063
+ "rule": "required",
11064
+ "type": "bytes",
11065
+ "id": 1
11066
+ }
11067
+ }
11068
+ },
11069
+ "ZcashSignedPczt": {
11070
+ "fields": {
11071
+ "pczt_length": {
11072
+ "rule": "required",
11073
+ "type": "uint32",
11074
+ "id": 1
11075
+ },
11076
+ "pczt_initial_chunk": {
11077
+ "rule": "required",
11078
+ "type": "bytes",
11079
+ "id": 2
11080
+ }
11081
+ }
11082
+ },
11083
+ "ZcashSignedPcztChunkRequest": {
11084
+ "fields": {
11085
+ "chunk_length": {
11086
+ "rule": "required",
11087
+ "type": "uint32",
11088
+ "id": 1
11089
+ }
11090
+ }
11091
+ },
11037
11092
  "wire_in": {
11038
11093
  "type": "bool",
11039
11094
  "id": 50002,
@@ -11459,6 +11514,11 @@
11459
11514
  "MessageType_NeoAddress": 12302,
11460
11515
  "MessageType_NeoSignTx": 12303,
11461
11516
  "MessageType_NeoSignedTx": 12304,
11517
+ "MessageType_ZcashSignPczt": 12402,
11518
+ "MessageType_ZcashSignedPczt": 12403,
11519
+ "MessageType_ZcashPcztChunkRequest": 12404,
11520
+ "MessageType_ZcashPcztChunkAck": 12405,
11521
+ "MessageType_ZcashSignedPcztChunkRequest": 12406,
11462
11522
  "MessageType_DeviceFactoryInfoSet": 60000,
11463
11523
  "MessageType_DeviceFactoryInfoGet": 60001,
11464
11524
  "MessageType_DeviceFactoryInfo": 60002,
@@ -11511,7 +11571,9 @@
11511
11571
  "MessageType_PortfolioUpdate": 61400,
11512
11572
  "MessageType_NftUpdate": 61500,
11513
11573
  "MessageType_OnboardingStatusGet": 61600,
11514
- "MessageType_OnboardingStatus": 61601
11574
+ "MessageType_OnboardingStatus": 61601,
11575
+ "MessageType_ZcashGetAddress": 12400,
11576
+ "MessageType_ZcashAddress": 12401
11515
11577
  },
11516
11578
  "reserved": [
11517
11579
  [90, 92],
@@ -13730,6 +13792,81 @@
13730
13792
  }
13731
13793
  }
13732
13794
  }
13795
+ },
13796
+ "ZcashAddressType": {
13797
+ "values": {
13798
+ "UNIFIED_ORCHARD_P2PKH": 0,
13799
+ "TRANSPARENT_P2PKH": 1,
13800
+ "UNIFIED_ORCHARD": 2
13801
+ }
13802
+ },
13803
+ "ZcashAddressScope": {
13804
+ "values": {
13805
+ "EXTERNAL": 0,
13806
+ "INTERNAL": 1
13807
+ }
13808
+ },
13809
+ "ZcashGetAddress": {
13810
+ "fields": {
13811
+ "address_n": {
13812
+ "rule": "repeated",
13813
+ "type": "uint32",
13814
+ "id": 1,
13815
+ "options": {
13816
+ "packed": false
13817
+ }
13818
+ },
13819
+ "show_display": {
13820
+ "type": "bool",
13821
+ "id": 2
13822
+ },
13823
+ "include_seed_fingerprint": {
13824
+ "type": "bool",
13825
+ "id": 3
13826
+ },
13827
+ "include_ufvk": {
13828
+ "type": "bool",
13829
+ "id": 4
13830
+ },
13831
+ "diversifier_index": {
13832
+ "type": "uint32",
13833
+ "id": 5,
13834
+ "options": {
13835
+ "default": 0
13836
+ }
13837
+ },
13838
+ "address_type": {
13839
+ "type": "ZcashAddressType",
13840
+ "id": 6,
13841
+ "options": {
13842
+ "default": "UNIFIED_ORCHARD_P2PKH"
13843
+ }
13844
+ },
13845
+ "scope": {
13846
+ "type": "ZcashAddressScope",
13847
+ "id": 7,
13848
+ "options": {
13849
+ "default": "EXTERNAL"
13850
+ }
13851
+ }
13852
+ }
13853
+ },
13854
+ "ZcashAddress": {
13855
+ "fields": {
13856
+ "address": {
13857
+ "rule": "required",
13858
+ "type": "string",
13859
+ "id": 1
13860
+ },
13861
+ "ufvk": {
13862
+ "type": "string",
13863
+ "id": 2
13864
+ },
13865
+ "seed_fingerprint": {
13866
+ "type": "bytes",
13867
+ "id": 3
13868
+ }
13869
+ }
13733
13870
  }
13734
13871
  }
13735
13872
  }
@@ -587,10 +587,12 @@ export class Device extends EventEmitter {
587
587
  try {
588
588
  // BLE releases even when keepSession is set, so forward the intent.
589
589
  await this.deviceConnector?.release(this.mainId, false, this.keepSession);
590
- this.updateDescriptor({ session: null } as DeviceDescriptor);
591
590
  } catch (err) {
592
591
  Log.error('[Device] release error: ', err);
593
592
  } finally {
593
+ // Core no longer owns a logical transport session after release starts,
594
+ // even if native cleanup must be retried by the transport.
595
+ this.updateDescriptor({ session: null } as DeviceDescriptor);
594
596
  this.needReloadDevice = true;
595
597
  }
596
598
  }
@@ -133,10 +133,10 @@ export default class DeviceConnector {
133
133
  : undefined;
134
134
  const detectedProtocol = acquiredProtocol ?? transport.getProtocolType(path);
135
135
  if (detectedProtocol !== expectedProtocol) {
136
- throw ERRORS.TypedError(
137
- HardwareErrorCode.RuntimeError,
138
- `Device protocol mismatch: expected ${expectedProtocol}, detected ${detectedProtocol}`
139
- );
136
+ throw ERRORS.TypedError(HardwareErrorCode.TransportProtocolMismatch, undefined, {
137
+ expectedProtocol,
138
+ detectedProtocol,
139
+ });
140
140
  }
141
141
  }
142
142
  return res;
@@ -8,8 +8,8 @@ export const LogBlockEvent: Set<string> = new Set([
8
8
  UI_RESPONSE.RECEIVE_PASSPHRASE,
9
9
  ]);
10
10
 
11
- // These resource/file APIs did not exist in 1.1.32. Skip the payload so
12
- // the log layer does not copy huge Base64 or binary data.
11
+ // Drop sensitive wallet payloads and large resource data before logger caches
12
+ // or log events can retain them, regardless of whether debug output is enabled.
13
13
  const LogPayloadBlockMethod: Set<string> = new Set([
14
14
  'btcDeriveContextHash',
15
15
  'deviceUploadNft',
@@ -17,6 +17,8 @@ const LogPayloadBlockMethod: Set<string> = new Set([
17
17
  'uploadPortfolio',
18
18
  'fileWrite',
19
19
  'fileRead',
20
+ 'zcashGetAddress',
21
+ 'zcashSignPczt',
20
22
  ]);
21
23
 
22
24
  export function getLogBlockLabel(message: unknown): string | undefined {
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export { executeCallback, cleanupCallback };
21
21
  export { preloadSessionCache } from './device/Device';
22
22
  export { projectFeatures as projectDeviceStateFeatures } from './device/DeviceStateProjector';
23
23
  export { getMethodSupportedProtocols } from './api/utils';
24
+ export { probeUsbDeviceIdentitiesWithTransport } from './api/SearchDevices';
24
25
  export {
25
26
  getFirmwareUpdateHostBindingGeneration,
26
27
  registerFirmwareUpdateHostBinding,
package/src/inject.ts CHANGED
@@ -504,4 +504,8 @@ export const createCoreApi = (
504
504
  call({ ...params, connectId, deviceId, method: 'neoGetAddress' }),
505
505
  neoSignTransaction: (connectId, deviceId, params) =>
506
506
  call({ ...params, connectId, deviceId, method: 'neoSignTransaction' }),
507
+ zcashGetAddress: (connectId, deviceId, params) =>
508
+ call({ ...params, connectId, deviceId, method: 'zcashGetAddress' }),
509
+ zcashSignPczt: (connectId, deviceId, params) =>
510
+ call({ ...params, connectId, deviceId, method: 'zcashSignPczt' }),
507
511
  });
@@ -227,3 +227,5 @@ export type { BenfenAddress, BenfenGetAddressParams } from './benfenGetAddress';
227
227
  export type { BenfenPublicKey, BenfenGetPublicKeyParams } from './benfenGetPublicKey';
228
228
  export type { BenfenSignMessageParams } from './benfenSignMessage';
229
229
  export type { BenfenSignedTx, BenfenSignTransactionParams } from './benfenSignTransaction';
230
+ export type { ZcashAddress, ZcashGetAddressParams } from './zcashGetAddress';
231
+ export type { ZcashSignedPczt, ZcashSignPcztParams } from './zcashSignPczt';
@@ -154,6 +154,8 @@ import type { benfenSignTransaction } from './benfenSignTransaction';
154
154
  import type { benfenSignMessage } from './benfenSignMessage';
155
155
  import type { neoGetAddress } from './neoGetAddress';
156
156
  import type { neoSignTransaction } from './neoSignTransaction';
157
+ import type { zcashGetAddress } from './zcashGetAddress';
158
+ import type { zcashSignPczt } from './zcashSignPczt';
157
159
  import type { ConnectSettings } from '../settings';
158
160
  import type { HardwareConnectProtocol } from '@onekeyfe/hd-shared';
159
161
 
@@ -472,4 +474,10 @@ export type CoreApi = {
472
474
  */
473
475
  neoGetAddress: typeof neoGetAddress;
474
476
  neoSignTransaction: typeof neoSignTransaction;
477
+
478
+ /**
479
+ * Zcash
480
+ */
481
+ zcashGetAddress: typeof zcashGetAddress;
482
+ zcashSignPczt: typeof zcashSignPczt;
475
483
  };