@onekeyfe/hd-core 1.2.8-alpha.9 → 1.2.10-alpha.1
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/README.md +27 -0
- package/__tests__/allNetworkGetAddress-privacy-networks.test.ts +78 -0
- package/__tests__/btc-derive-context-hash.test.ts +200 -0
- package/__tests__/core-dispose.test.ts +114 -1
- package/__tests__/core-error-output.test.ts +21 -0
- package/__tests__/device-connector-protocol.test.ts +5 -2
- package/__tests__/device-lifecycle-events.test.ts +127 -10
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +11 -0
- package/__tests__/logBlockEvent.test.ts +331 -9
- package/__tests__/logger.test.ts +18 -0
- package/__tests__/monero-get-address.test.ts +147 -0
- package/__tests__/monero-key-image-sync.test.ts +272 -0
- package/__tests__/monero-sign-transaction.test.ts +436 -0
- package/__tests__/protocol-v2-resources.test.ts +14 -0
- package/__tests__/protocol-v2.test.ts +845 -3
- package/__tests__/protocolV2FileWrite.test.ts +454 -7
- package/__tests__/search-devices.test.ts +36 -0
- package/__tests__/sol-sign-offchain-message.test.ts +8 -0
- package/__tests__/usb-identity-probe.test.ts +358 -0
- package/__tests__/zcash-protobuf.test.ts +141 -0
- package/__tests__/zcash-sign-pczt.test.ts +446 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/FileWrite.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +5 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts +21 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/btc/BTCDeriveContextHash.d.ts +16 -0
- package/dist/api/btc/BTCDeriveContextHash.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
- package/dist/api/helpers/pathUtils.d.ts +1 -0
- package/dist/api/helpers/pathUtils.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +5 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/monero/MoneroGetAddress.d.ts +11 -0
- package/dist/api/monero/MoneroGetAddress.d.ts.map +1 -0
- package/dist/api/monero/MoneroGetWatchKey.d.ts +11 -0
- package/dist/api/monero/MoneroGetWatchKey.d.ts.map +1 -0
- package/dist/api/monero/MoneroKeyImageSync.d.ts +20 -0
- package/dist/api/monero/MoneroKeyImageSync.d.ts.map +1 -0
- package/dist/api/monero/MoneroSignTransaction.d.ts +17 -0
- package/dist/api/monero/MoneroSignTransaction.d.ts.map +1 -0
- package/dist/api/monero/helpers.d.ts +5 -0
- package/dist/api/monero/helpers.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/api/zcash/ZcashGetAddress.d.ts +12 -0
- package/dist/api/zcash/ZcashGetAddress.d.ts.map +1 -0
- package/dist/api/zcash/ZcashSignPczt.d.ts +16 -0
- package/dist/api/zcash/ZcashSignPczt.d.ts.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -0
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/events/logBlockEvent.d.ts +10 -0
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +2 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +192 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5751 -4191
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +1 -0
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/allNetworkGetAddress.d.ts +5 -1
- package/dist/types/api/allNetworkGetAddress.d.ts.map +1 -1
- package/dist/types/api/btcDeriveContextHash.d.ts +10 -0
- package/dist/types/api/btcDeriveContextHash.d.ts.map +1 -0
- package/dist/types/api/export.d.ts +7 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +14 -0
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/moneroGetAddress.d.ts +15 -0
- package/dist/types/api/moneroGetAddress.d.ts.map +1 -0
- package/dist/types/api/moneroGetWatchKey.d.ts +15 -0
- package/dist/types/api/moneroGetWatchKey.d.ts.map +1 -0
- package/dist/types/api/moneroKeyImageSync.d.ts +24 -0
- package/dist/types/api/moneroKeyImageSync.d.ts.map +1 -0
- package/dist/types/api/moneroSignTransaction.d.ts +32 -0
- package/dist/types/api/moneroSignTransaction.d.ts.map +1 -0
- package/dist/types/api/zcashGetAddress.d.ts +22 -0
- package/dist/types/api/zcashGetAddress.d.ts.map +1 -0
- package/dist/types/api/zcashSignPczt.d.ts +9 -0
- package/dist/types/api/zcashSignPczt.d.ts.map +1 -0
- package/dist/types/device.d.ts +10 -0
- package/dist/types/device.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +2 -0
- package/src/api/FileWrite.ts +7 -1
- package/src/api/FirmwareUpdateV4.ts +358 -74
- package/src/api/SearchDevices.ts +172 -7
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +38 -1
- package/src/api/btc/BTCDeriveContextHash.ts +90 -0
- package/src/api/firmware/FirmwareArtifactSource.ts +12 -3
- package/src/api/helpers/pathUtils.ts +23 -0
- package/src/api/helpers/protocolV2FileWrite.ts +382 -111
- package/src/api/index.ts +8 -0
- package/src/api/monero/MoneroGetAddress.ts +71 -0
- package/src/api/monero/MoneroGetWatchKey.ts +69 -0
- package/src/api/monero/MoneroKeyImageSync.ts +164 -0
- package/src/api/monero/MoneroSignTransaction.ts +319 -0
- package/src/api/monero/helpers.ts +28 -0
- package/src/api/protocol-v2/DeviceUploadNft.ts +6 -1
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +15 -1
- package/src/api/zcash/ZcashGetAddress.ts +119 -0
- package/src/api/zcash/ZcashSignPczt.ts +152 -0
- package/src/core/index.ts +49 -17
- package/src/data/messages/messages-protocol-v2.json +138 -1
- package/src/data/messages/messages.json +51 -0
- package/src/device/Device.ts +21 -3
- package/src/device/DeviceConnector.ts +4 -4
- package/src/events/logBlockEvent.ts +57 -3
- package/src/events/ui-request.ts +2 -0
- package/src/index.ts +1 -0
- package/src/inject.ts +15 -0
- package/src/protocols/protocol-v2/resources.ts +6 -1
- package/src/types/api/allNetworkGetAddress.ts +9 -1
- package/src/types/api/btcDeriveContextHash.ts +15 -0
- package/src/types/api/export.ts +16 -0
- package/src/types/api/index.ts +22 -0
- package/src/types/api/moneroGetAddress.ts +27 -0
- package/src/types/api/moneroGetWatchKey.ts +28 -0
- package/src/types/api/moneroKeyImageSync.ts +45 -0
- package/src/types/api/moneroSignTransaction.ts +54 -0
- package/src/types/api/zcashGetAddress.ts +35 -0
- package/src/types/api/zcashSignPczt.ts +18 -0
- package/src/types/device.ts +18 -0
- package/src/utils/logger.ts +4 -0
|
@@ -6,7 +6,11 @@ import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
|
|
|
6
6
|
import { BaseMethod } from '../BaseMethod';
|
|
7
7
|
import { decodeJpegBase64ToRgba } from '../helpers/base64Data';
|
|
8
8
|
import { invalidParameter } from '../helpers/filesystemValidation';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
createProtocolV2AssetFileWriteRecovery,
|
|
11
|
+
writeProtocolV2File,
|
|
12
|
+
} from '../helpers/protocolV2FileWrite';
|
|
13
|
+
import { ProtocolV2UiInteractionCoordinator } from '../../protocols/protocol-v2/uiInteraction';
|
|
10
14
|
import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
|
|
11
15
|
import { supportsProtocolV2Message } from '../../protocols/protocol-v2/features';
|
|
12
16
|
import { LoggerNames, getLogger } from '../../utils';
|
|
@@ -142,6 +146,7 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
|
|
|
142
146
|
chunkSize: this.params.chunkSize,
|
|
143
147
|
bleChunkSizeLimit,
|
|
144
148
|
maxChunkRetries: 3,
|
|
149
|
+
recoverConnection: createProtocolV2AssetFileWriteRecovery(this),
|
|
145
150
|
overwrite: true,
|
|
146
151
|
append: false,
|
|
147
152
|
throwIfAborted: () => this.throwIfAborted(),
|
|
@@ -171,6 +176,15 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
|
|
|
171
176
|
data,
|
|
172
177
|
useHostAssetPackage ? WALLPAPER_PACKAGE_BLE_CHUNK_SIZE : undefined
|
|
173
178
|
);
|
|
179
|
+
this.throwIfAborted();
|
|
180
|
+
new ProtocolV2UiInteractionCoordinator(this.device, this.postMessage).enterMethodInteraction({
|
|
181
|
+
request: 'button',
|
|
182
|
+
source: 'method-lifecycle',
|
|
183
|
+
reason: 'device-management',
|
|
184
|
+
completion: 'operation-completed',
|
|
185
|
+
deviceOnly: true,
|
|
186
|
+
operation: this.name,
|
|
187
|
+
});
|
|
174
188
|
const response = await this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
|
|
175
189
|
settings: { wallpaper_path: this.path },
|
|
176
190
|
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { ZcashAddressScope, ZcashAddressType } from '@onekeyfe/hd-transport';
|
|
2
|
+
|
|
3
|
+
import { BaseMethod } from '../BaseMethod';
|
|
4
|
+
import { serializedPath, toHardened, validateStrictPath } 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 { ZcashAddress, ZcashGetAddressParams } 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 = validateStrictPath(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
|
+
) {
|
|
39
|
+
throw invalidParameter("Zcash requires a ZIP-32 account path m/32'/133'/account'");
|
|
40
|
+
}
|
|
41
|
+
const addressType = batch.addressType ?? ZcashAddressType.UNIFIED_ORCHARD_P2PKH;
|
|
42
|
+
const scope = batch.scope ?? ZcashAddressScope.EXTERNAL;
|
|
43
|
+
const diversifierIndex = batch.diversifierIndex ?? 0;
|
|
44
|
+
if (
|
|
45
|
+
![
|
|
46
|
+
ZcashAddressType.UNIFIED_ORCHARD_P2PKH,
|
|
47
|
+
ZcashAddressType.TRANSPARENT_P2PKH,
|
|
48
|
+
ZcashAddressType.UNIFIED_ORCHARD,
|
|
49
|
+
].includes(addressType) ||
|
|
50
|
+
![ZcashAddressScope.EXTERNAL, ZcashAddressScope.INTERNAL].includes(scope)
|
|
51
|
+
) {
|
|
52
|
+
throw invalidParameter('Invalid Zcash address type or scope');
|
|
53
|
+
}
|
|
54
|
+
const maxIndex = addressType === ZcashAddressType.UNIFIED_ORCHARD ? 0xffffffff : 0x7fffffff;
|
|
55
|
+
if (
|
|
56
|
+
!Number.isSafeInteger(diversifierIndex) ||
|
|
57
|
+
diversifierIndex < 0 ||
|
|
58
|
+
diversifierIndex > maxIndex
|
|
59
|
+
) {
|
|
60
|
+
throw invalidParameter('Invalid Zcash diversifier index');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
validateParams(batch, [
|
|
64
|
+
{ name: 'path', required: true },
|
|
65
|
+
{ name: 'showOnOneKey', type: 'boolean' },
|
|
66
|
+
{ name: 'includeUfvk', type: 'boolean' },
|
|
67
|
+
{ name: 'includeSeedFingerprint', type: 'boolean' },
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
this.params.push({
|
|
71
|
+
address_n: addressN,
|
|
72
|
+
address_type: addressType,
|
|
73
|
+
scope,
|
|
74
|
+
diversifier_index: diversifierIndex,
|
|
75
|
+
show_display: batch.showOnOneKey ?? true,
|
|
76
|
+
include_ufvk: batch.includeUfvk ?? false,
|
|
77
|
+
include_seed_fingerprint: batch.includeSeedFingerprint ?? false,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getVersionRange(): DeviceFirmwareRange {
|
|
83
|
+
return {
|
|
84
|
+
model_pro2: {
|
|
85
|
+
min: '0.0.0',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async run() {
|
|
91
|
+
const responses: ZcashAddress[] = [];
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < this.params.length; i++) {
|
|
94
|
+
const param = this.params[i];
|
|
95
|
+
|
|
96
|
+
const res = await this.device.commands.typedCall('ZcashGetAddress', 'ZcashAddress', {
|
|
97
|
+
...param,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const path = serializedPath(param.address_n);
|
|
101
|
+
// The V2 decoder returns null for absent optional fields; omit them instead.
|
|
102
|
+
const { address, ufvk, seed_fingerprint: seedFingerprint } = res.message;
|
|
103
|
+
responses.push({
|
|
104
|
+
path,
|
|
105
|
+
address,
|
|
106
|
+
...(ufvk ? { ufvk } : {}),
|
|
107
|
+
...(seedFingerprint ? { seedFingerprint } : {}),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
this.postPreviousAddressMessage({ address, path });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
validateResult(responses, ['address'], {
|
|
114
|
+
expectedLength: this.params.length,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return Promise.resolve(this.hasBundle ? responses : responses[0]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
first: TypedResponseMessage<'ZcashSignedPczt'> | TypedResponseMessage<'ZcashPcztChunkRequest'>,
|
|
61
|
+
initialOffset: number
|
|
62
|
+
): Promise<TypedResponseMessage<'ZcashSignedPczt'>> => {
|
|
63
|
+
let res = first;
|
|
64
|
+
let offset = initialOffset;
|
|
65
|
+
while (res.type === 'ZcashPcztChunkRequest') {
|
|
66
|
+
const { chunk_length: chunkLength } = res.message;
|
|
67
|
+
if (
|
|
68
|
+
!Number.isSafeInteger(chunkLength) ||
|
|
69
|
+
chunkLength <= 0 ||
|
|
70
|
+
offset + chunkLength > this.pczt.length
|
|
71
|
+
) {
|
|
72
|
+
throw ERRORS.TypedError(
|
|
73
|
+
HardwareErrorCode.ResponseUnexpectTypeError,
|
|
74
|
+
`device requested ${chunkLength} bytes at offset ${offset} of ${this.pczt.length}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const chunk = this.pczt.subarray(offset, offset + chunkLength);
|
|
79
|
+
res = await typedCall('ZcashPcztChunkAck', ['ZcashSignedPczt', 'ZcashPcztChunkRequest'], {
|
|
80
|
+
data_chunk: bytesToHex(chunk),
|
|
81
|
+
});
|
|
82
|
+
offset += chunkLength;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (offset !== this.pczt.length) {
|
|
86
|
+
throw ERRORS.TypedError(
|
|
87
|
+
HardwareErrorCode.ResponseUnexpectTypeError,
|
|
88
|
+
'device completed signing before receiving the whole pczt'
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return res;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Download: the host decides chunk lengths via ZcashSignedPcztChunkRequest
|
|
95
|
+
// until the announced pczt_length has been received.
|
|
96
|
+
downloadSignedPczt = async (
|
|
97
|
+
typedCall: TypedCall,
|
|
98
|
+
res: TypedResponseMessage<'ZcashSignedPczt'>
|
|
99
|
+
): Promise<Buffer> => {
|
|
100
|
+
const { pczt_length: total, pczt_initial_chunk: initial } = res.message;
|
|
101
|
+
if (!Number.isSafeInteger(total) || total <= 0 || total > SIGNED_PCZT_SANITY_MAX_BYTES) {
|
|
102
|
+
throw ERRORS.TypedError(
|
|
103
|
+
HardwareErrorCode.ResponseUnexpectTypeError,
|
|
104
|
+
`device announced invalid signed pczt length ${total}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const parts: Buffer[] = [Buffer.from(initial ?? '', 'hex')];
|
|
109
|
+
let received = parts[0].length;
|
|
110
|
+
if (received > total) {
|
|
111
|
+
throw ERRORS.TypedError(
|
|
112
|
+
HardwareErrorCode.ResponseUnexpectTypeError,
|
|
113
|
+
'device returned more initial pczt bytes than announced'
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
while (received < total) {
|
|
118
|
+
const chunkLength = Math.min(CHUNK_BYTE_SIZE, total - received);
|
|
119
|
+
const ack = await typedCall('ZcashSignedPcztChunkRequest', 'ZcashPcztChunkAck', {
|
|
120
|
+
chunk_length: chunkLength,
|
|
121
|
+
});
|
|
122
|
+
const chunk = Buffer.from(ack.message.data_chunk ?? '', 'hex');
|
|
123
|
+
if (chunk.length !== chunkLength) {
|
|
124
|
+
throw ERRORS.TypedError(
|
|
125
|
+
HardwareErrorCode.ResponseUnexpectTypeError,
|
|
126
|
+
`device returned ${chunk.length} of ${chunkLength} requested bytes at offset ${received} of ${total}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
parts.push(chunk);
|
|
130
|
+
received += chunk.length;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return Buffer.concat(parts);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
async run(): Promise<ZcashSignedPczt> {
|
|
137
|
+
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
138
|
+
|
|
139
|
+
const first = await typedCall('ZcashSignPczt', ['ZcashSignedPczt', 'ZcashPcztChunkRequest'], {
|
|
140
|
+
...this.params,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const signed = await this.uploadPczt(
|
|
144
|
+
typedCall,
|
|
145
|
+
first,
|
|
146
|
+
Math.min(CHUNK_BYTE_SIZE, this.pczt.length)
|
|
147
|
+
);
|
|
148
|
+
const pczt = await this.downloadSignedPczt(typedCall, signed);
|
|
149
|
+
|
|
150
|
+
return { pczt: bytesToHex(pczt) };
|
|
151
|
+
}
|
|
152
|
+
}
|
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,
|
|
@@ -60,6 +61,7 @@ import {
|
|
|
60
61
|
formatLogMethodLabel,
|
|
61
62
|
getLogBlockLabel,
|
|
62
63
|
getSafeLogPayload,
|
|
64
|
+
getSafeLogTask,
|
|
63
65
|
} from '../events';
|
|
64
66
|
import TransportManager from '../data-manager/TransportManager';
|
|
65
67
|
import DeviceConnector from '../device/DeviceConnector';
|
|
@@ -125,6 +127,8 @@ const parseInitOptions = (method?: BaseMethod): InitOptions => ({
|
|
|
125
127
|
});
|
|
126
128
|
|
|
127
129
|
let _core: Core | undefined;
|
|
130
|
+
let transportSwitchGeneration = 0;
|
|
131
|
+
let pendingTransportSwitch: Promise<void> = Promise.resolve();
|
|
128
132
|
let _deviceList: DeviceList | undefined;
|
|
129
133
|
let _connector: DeviceConnector | undefined;
|
|
130
134
|
let _uiPromises: UiPromise<UiPromiseResponse['type']>[] = []; // Waiting for ui response
|
|
@@ -990,15 +994,11 @@ function canSkipInitialize(method: BaseMethod, device: Device): boolean {
|
|
|
990
994
|
}
|
|
991
995
|
|
|
992
996
|
export function isRetryableBleProtocolV2ProbeError(method: BaseMethod, error: unknown) {
|
|
993
|
-
const typedError = error as { errorCode?: unknown;
|
|
994
|
-
const message =
|
|
995
|
-
typeof typedError?.message === 'string' ? typedError.message : String(error ?? '');
|
|
997
|
+
const typedError = error as { errorCode?: unknown; params?: { expectedProtocol?: unknown } };
|
|
996
998
|
return (
|
|
997
999
|
method.payload.connectProtocol === 'V2' &&
|
|
998
|
-
typedError?.errorCode === HardwareErrorCode.
|
|
999
|
-
|
|
1000
|
-
message.includes('expected V2') &&
|
|
1001
|
-
message.includes('did not respond to expected protocol')
|
|
1000
|
+
typedError?.errorCode === HardwareErrorCode.TransportProtocolProbeFailed &&
|
|
1001
|
+
typedError.params?.expectedProtocol === 'V2'
|
|
1002
1002
|
);
|
|
1003
1003
|
}
|
|
1004
1004
|
|
|
@@ -1008,7 +1008,7 @@ export function isRetryableBleConnectionError(method: BaseMethod, error: unknown
|
|
|
1008
1008
|
}
|
|
1009
1009
|
const typedError = error as {
|
|
1010
1010
|
errorCode?: unknown;
|
|
1011
|
-
params?: { acquireDeadlineExceeded?: unknown };
|
|
1011
|
+
params?: { acquireDeadlineExceeded?: unknown; expectedProtocol?: unknown };
|
|
1012
1012
|
};
|
|
1013
1013
|
if (
|
|
1014
1014
|
typedError?.errorCode === HardwareErrorCode.BleTimeoutError &&
|
|
@@ -1019,6 +1019,8 @@ export function isRetryableBleConnectionError(method: BaseMethod, error: unknown
|
|
|
1019
1019
|
return (
|
|
1020
1020
|
typedError?.errorCode === HardwareErrorCode.BleTimeoutError ||
|
|
1021
1021
|
typedError?.errorCode === HardwareErrorCode.BleConnectedError ||
|
|
1022
|
+
(typedError?.errorCode === HardwareErrorCode.TransportProtocolProbeFailed &&
|
|
1023
|
+
!typedError.params?.expectedProtocol) ||
|
|
1022
1024
|
isRetryableBleProtocolV2ProbeError(method, error) ||
|
|
1023
1025
|
isMissingDetectedProtocolV2Error(method, error)
|
|
1024
1026
|
);
|
|
@@ -1273,6 +1275,8 @@ const ensureConnected = async (
|
|
|
1273
1275
|
HardwareErrorCode.BridgeTimeoutError,
|
|
1274
1276
|
HardwareErrorCode.BridgeNeedsPermission,
|
|
1275
1277
|
HardwareErrorCode.WebUsbDeviceAccessError,
|
|
1278
|
+
HardwareErrorCode.TransportProtocolProbeFailed,
|
|
1279
|
+
HardwareErrorCode.TransportProtocolMismatch,
|
|
1276
1280
|
].includes(error.errorCode)
|
|
1277
1281
|
) {
|
|
1278
1282
|
_deviceList = undefined;
|
|
@@ -1360,6 +1364,8 @@ const ensureConnected = async (
|
|
|
1360
1364
|
HardwareErrorCode.BleCharacteristicNotifyChangeFailure,
|
|
1361
1365
|
HardwareErrorCode.BridgeNeedsPermission,
|
|
1362
1366
|
HardwareErrorCode.WebUsbDeviceAccessError,
|
|
1367
|
+
HardwareErrorCode.TransportProtocolProbeFailed,
|
|
1368
|
+
HardwareErrorCode.TransportProtocolMismatch,
|
|
1363
1369
|
HardwareErrorCode.DeviceInterruptedFromUser,
|
|
1364
1370
|
HardwareErrorCode.CallQueueActionCancelled,
|
|
1365
1371
|
].includes(error.errorCode) ||
|
|
@@ -1446,7 +1452,7 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
1446
1452
|
};
|
|
1447
1453
|
for (const requestId of requestIds) {
|
|
1448
1454
|
const task = requestQueue.getTask(requestId);
|
|
1449
|
-
Log.debug('Cancel Api connect task: ', task);
|
|
1455
|
+
Log.debug('Cancel Api connect task: ', getSafeLogTask(task));
|
|
1450
1456
|
if (task) {
|
|
1451
1457
|
// During ensureConnected the method has a connectId but device is
|
|
1452
1458
|
// assigned only after the poll succeeds. Interrupt the cached BLE
|
|
@@ -1481,7 +1487,7 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
1481
1487
|
};
|
|
1482
1488
|
for (const requestId of requestQueue.getRequestTasksId()) {
|
|
1483
1489
|
const task = requestQueue.getTask(requestId);
|
|
1484
|
-
Log.debug('Cancel Api connect task: ', task);
|
|
1490
|
+
Log.debug('Cancel Api connect task: ', getSafeLogTask(task));
|
|
1485
1491
|
if (task) {
|
|
1486
1492
|
interruptDevice(task.method?.device);
|
|
1487
1493
|
if (task.method.connectId) {
|
|
@@ -1826,6 +1832,10 @@ export default class Core extends EventEmitter {
|
|
|
1826
1832
|
|
|
1827
1833
|
private requestQueue = new RequestQueue();
|
|
1828
1834
|
|
|
1835
|
+
getOwnedUsbDeviceIdentity(descriptor: Parameters<typeof getOwnedUsbDeviceIdentity>[0]) {
|
|
1836
|
+
return getOwnedUsbDeviceIdentity(descriptor, this.requestQueue);
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1829
1839
|
private disposePromise?: Promise<void>;
|
|
1830
1840
|
|
|
1831
1841
|
// background task
|
|
@@ -1940,7 +1950,7 @@ export default class Core extends EventEmitter {
|
|
|
1940
1950
|
break;
|
|
1941
1951
|
}
|
|
1942
1952
|
case IFRAME.CALLBACK: {
|
|
1943
|
-
Log.log('callback message: ', message);
|
|
1953
|
+
Log.log('callback message: ', getSafeLogPayload(message));
|
|
1944
1954
|
postMessage(message);
|
|
1945
1955
|
break;
|
|
1946
1956
|
}
|
|
@@ -1959,6 +1969,8 @@ export default class Core extends EventEmitter {
|
|
|
1959
1969
|
|
|
1960
1970
|
private async disposeResources(): Promise<void> {
|
|
1961
1971
|
Log.debug(`[Core] Disposing SDK instance: ${this.sdkInstanceId}`);
|
|
1972
|
+
transportSwitchGeneration += 1;
|
|
1973
|
+
pendingTransportSwitch = Promise.resolve();
|
|
1962
1974
|
pollingManager.stopAll();
|
|
1963
1975
|
this.requestQueue.abortAllRequests();
|
|
1964
1976
|
cleanup();
|
|
@@ -1993,6 +2005,8 @@ export default class Core extends EventEmitter {
|
|
|
1993
2005
|
}
|
|
1994
2006
|
|
|
1995
2007
|
export const initCore = () => {
|
|
2008
|
+
transportSwitchGeneration += 1;
|
|
2009
|
+
pendingTransportSwitch = Promise.resolve();
|
|
1996
2010
|
const core = new Core();
|
|
1997
2011
|
_core = core;
|
|
1998
2012
|
return core;
|
|
@@ -2022,6 +2036,8 @@ export const init = async (
|
|
|
2022
2036
|
plugin?: LowlevelTransportSharedPlugin
|
|
2023
2037
|
) => {
|
|
2024
2038
|
try {
|
|
2039
|
+
transportSwitchGeneration += 1;
|
|
2040
|
+
pendingTransportSwitch = Promise.resolve();
|
|
2025
2041
|
await DataManager.load(settings);
|
|
2026
2042
|
initTransport(Transport, plugin);
|
|
2027
2043
|
enableLog(DataManager.getSettings('debug'));
|
|
@@ -2047,10 +2063,26 @@ export const switchTransport = ({
|
|
|
2047
2063
|
Transport: any;
|
|
2048
2064
|
plugin?: LowlevelTransportSharedPlugin;
|
|
2049
2065
|
}) => {
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2066
|
+
const generation = transportSwitchGeneration;
|
|
2067
|
+
// Preserve request order while native transport cleanup is pending.
|
|
2068
|
+
const switching = pendingTransportSwitch
|
|
2069
|
+
.catch(() => undefined)
|
|
2070
|
+
.then(async () => {
|
|
2071
|
+
if (generation !== transportSwitchGeneration) {
|
|
2072
|
+
throw ERRORS.TypedError(HardwareErrorCode.NotInitialized);
|
|
2073
|
+
}
|
|
2074
|
+
_connector?.stop();
|
|
2075
|
+
await TransportManager.getTransport()?.stop?.();
|
|
2076
|
+
if (generation !== transportSwitchGeneration) {
|
|
2077
|
+
throw ERRORS.TypedError(HardwareErrorCode.NotInitialized);
|
|
2078
|
+
}
|
|
2079
|
+
DataManager.updateEnv(env);
|
|
2080
|
+
TransportManager.setTransport(Transport, plugin);
|
|
2081
|
+
_deviceList = undefined;
|
|
2082
|
+
DevicePool.resetState();
|
|
2083
|
+
_connector = undefined;
|
|
2084
|
+
initConnector();
|
|
2085
|
+
});
|
|
2086
|
+
pendingTransportSwitch = switching;
|
|
2087
|
+
return switching;
|
|
2056
2088
|
};
|
|
@@ -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
|
}
|