@onekeyfe/hd-core 1.2.0-alpha.35 → 1.2.0-alpha.36

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 (50) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +74 -0
  2. package/__tests__/DeviceEventRegistration.test.ts +6 -0
  3. package/__tests__/get-device-state.test.ts +104 -12
  4. package/__tests__/open-wallet-session.test.ts +131 -7
  5. package/__tests__/protocol-v2-ui-lifecycle.test.ts +56 -0
  6. package/__tests__/protocol-v2.test.ts +290 -39
  7. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  8. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  9. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  10. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  11. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  12. package/dist/core/deviceEventRegistration.d.ts +2 -0
  13. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  14. package/dist/core/index.d.ts.map +1 -1
  15. package/dist/device/Device.d.ts +22 -4
  16. package/dist/device/Device.d.ts.map +1 -1
  17. package/dist/events/device.d.ts +4 -0
  18. package/dist/events/device.d.ts.map +1 -1
  19. package/dist/events/ui-request.d.ts +27 -2
  20. package/dist/events/ui-request.d.ts.map +1 -1
  21. package/dist/index.d.ts +56 -7
  22. package/dist/index.js +692 -397
  23. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  24. package/dist/protocols/protocol-v2/uiInteraction.d.ts +3 -3
  25. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  26. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  27. package/dist/protocols/protocol-v2/walletSession.d.ts +4 -1
  28. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  29. package/dist/utils/deviceFeaturesUtils.d.ts +2 -0
  30. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  31. package/dist/utils/patch.d.ts +1 -1
  32. package/package.json +4 -4
  33. package/src/api/BaseMethod.ts +1 -1
  34. package/src/api/FirmwareUpdateV4.ts +13 -6
  35. package/src/api/GetPassphraseState.ts +7 -1
  36. package/src/api/OpenWalletSession.ts +18 -3
  37. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +24 -2
  38. package/src/api/device/DeviceUnlock.ts +1 -1
  39. package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
  40. package/src/core/deviceEventRegistration.ts +4 -0
  41. package/src/core/index.ts +46 -4
  42. package/src/data/messages/messages-protocol-v2.json +15 -0
  43. package/src/device/Device.ts +221 -24
  44. package/src/events/device.ts +4 -0
  45. package/src/events/ui-request.ts +32 -2
  46. package/src/protocols/protocol-v2/features.ts +9 -2
  47. package/src/protocols/protocol-v2/uiInteraction.ts +31 -5
  48. package/src/protocols/protocol-v2/unlockRetry.ts +33 -11
  49. package/src/protocols/protocol-v2/walletSession.ts +140 -32
  50. package/src/utils/deviceFeaturesUtils.ts +4 -0
package/dist/index.js CHANGED
@@ -38049,11 +38049,26 @@ var nested = {
38049
38049
  DeviceSessionError_Busy: 5
38050
38050
  }
38051
38051
  },
38052
+ DeviceSessionSeedDomain: {
38053
+ values: {
38054
+ SeedDomain_Standard: 1,
38055
+ SeedDomain_Cardano: 2
38056
+ }
38057
+ },
38052
38058
  DeviceSessionGet: {
38053
38059
  fields: {
38054
38060
  session_id: {
38055
38061
  type: "bytes",
38056
38062
  id: 1
38063
+ },
38064
+ btc_test_address: {
38065
+ type: "string",
38066
+ id: 2
38067
+ },
38068
+ seed_domains: {
38069
+ rule: "repeated",
38070
+ type: "DeviceSessionSeedDomain",
38071
+ id: 3
38057
38072
  }
38058
38073
  }
38059
38074
  },
@@ -39930,6 +39945,8 @@ const DEVICE = {
39930
39945
  LOADING: 'device-loading',
39931
39946
  BUTTON: 'button',
39932
39947
  PIN: 'pin',
39948
+ PIN_ON_DEVICE: 'pin_on_device',
39949
+ PIN_ON_DEVICE_COMPLETE: 'pin_on_device_complete',
39933
39950
  PASSPHRASE: 'passphrase',
39934
39951
  PASSPHRASE_ON_DEVICE: 'passphrase_on_device',
39935
39952
  ATTACH_PIN_ON_DEVICE: 'attach_pin_on_device',
@@ -40086,21 +40103,46 @@ function refreshProtocolV2DeviceStatus(device) {
40086
40103
  return device.updateProtocolV2Status(status);
40087
40104
  });
40088
40105
  }
40089
- const negotiateEventlessWalletSession = (device) => __awaiter(void 0, void 0, void 0, function* () {
40090
- yield device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {
40091
- eventless_wallet_session: true,
40106
+ function ensureProtocolV2WalletSessionUnlocked(device) {
40107
+ var _a, _b, _c;
40108
+ return __awaiter(this, void 0, void 0, function* () {
40109
+ if (!device.isProtocolV2() || ((_a = device.isBootloader) === null || _a === void 0 ? void 0 : _a.call(device)) || ((_b = device.isRomloader) === null || _b === void 0 ? void 0 : _b.call(device))) {
40110
+ return false;
40111
+ }
40112
+ yield refreshProtocolV2DeviceStatus(device);
40113
+ if (((_c = device.state) === null || _c === void 0 ? void 0 : _c.status.unlocked) !== false) {
40114
+ return false;
40115
+ }
40116
+ yield device.unlockDevice(hdTransport.DeviceSessionPinType.Main, {
40117
+ source: 'unlock-coordinator',
40118
+ reason: 'device-locked',
40119
+ deviceOnly: true,
40120
+ });
40121
+ return true;
40092
40122
  });
40123
+ }
40124
+ const negotiateEventlessWalletSession = (device) => __awaiter(void 0, void 0, void 0, function* () {
40125
+ yield device.ensureProtocolV2RuntimeContext();
40126
+ });
40127
+ const getDeviceSession = (device, request, deriveCardano) => __awaiter(void 0, void 0, void 0, function* () {
40128
+ const payload = deriveCardano === undefined
40129
+ ? request
40130
+ : Object.assign(Object.assign({}, request), { seed_domains: [
40131
+ hdTransport.DeviceSessionSeedDomain.SeedDomain_Standard,
40132
+ ...(deriveCardano ? [hdTransport.DeviceSessionSeedDomain.SeedDomain_Cardano] : []),
40133
+ ] });
40134
+ return device.commands.typedCall('DeviceSessionGet', 'DeviceSession', payload);
40093
40135
  });
40094
- const getDeviceSession = (device, request) => __awaiter(void 0, void 0, void 0, function* () { return device.commands.typedCall('DeviceSessionGet', 'DeviceSession', request); });
40095
40136
  const askDevicePassphrase = (device, requestPayload) => __awaiter(void 0, void 0, void 0, function* () {
40096
40137
  yield device.commands.typedCall('DeviceSessionAskPassphrase', 'Success', requestPayload);
40097
40138
  yield refreshProtocolV2DeviceStatus(device);
40098
40139
  });
40099
- const selectDeviceSession = (device, expectedPassphraseState) => __awaiter(void 0, void 0, void 0, function* () {
40100
- var _a;
40140
+ const selectDeviceSession = (device, expectedPassphraseState, deriveCardano) => __awaiter(void 0, void 0, void 0, function* () {
40141
+ var _a, _b, _c;
40101
40142
  const existsAttachPinUser = ((_a = device.features) === null || _a === void 0 ? void 0 : _a.attachToPinEnabled) === true;
40102
40143
  const metadata = Object.assign({ source: 'wallet-session-coordinator', reason: expectedPassphraseState ? 'session-recovery' : 'open-wallet' }, (expectedPassphraseState ? { expectedPassphraseState } : {}));
40103
- const response = yield device.commands.promptPassphrase(Object.assign({ existsAttachPinUser, deviceOnly: false }, metadata), { cancelDeviceOnReject: false });
40144
+ const passphraseInteraction = (_b = device.createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(device, 'passphrase', 'start');
40145
+ const response = yield device.commands.promptPassphrase(Object.assign(Object.assign({ existsAttachPinUser, deviceOnly: false }, metadata), (passphraseInteraction ? { interaction: passphraseInteraction } : {})), { cancelDeviceOnReject: false });
40104
40146
  const hostPassphrase = typeof response.passphrase === 'string' ? response.passphrase.normalize('NFKD') : undefined;
40105
40147
  const hasHostPassphrase = typeof hostPassphrase === 'string' && hostPassphrase.length > 0;
40106
40148
  const hostPassphraseByteLength = hasHostPassphrase ? utf8ByteLength(hostPassphrase) : undefined;
@@ -40122,23 +40164,27 @@ const selectDeviceSession = (device, expectedPassphraseState) => __awaiter(void
40122
40164
  if (!existsAttachPinUser) {
40123
40165
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Attach PIN wallet selection is unavailable on this device.');
40124
40166
  }
40125
- device.emit(DEVICE.ATTACH_PIN_ON_DEVICE, device, metadata);
40126
- yield device.unlockDevice(hdTransport.DeviceSessionPinType.AttachToPin);
40127
- return getDeviceSession(device, {});
40167
+ const attachPinInteraction = (_c = device.createProtocolV2UiPhaseMetadata) === null || _c === void 0 ? void 0 : _c.call(device, 'pin', 'start');
40168
+ device.emit(DEVICE.ATTACH_PIN_ON_DEVICE, device, Object.assign(Object.assign({}, metadata), (attachPinInteraction ? { interaction: attachPinInteraction } : {})));
40169
+ yield device.unlockDevice(hdTransport.DeviceSessionPinType.AttachToPin, {
40170
+ emitUiEvent: false,
40171
+ interaction: attachPinInteraction,
40172
+ });
40173
+ return getDeviceSession(device, {}, deriveCardano);
40128
40174
  }
40129
40175
  if (hasHostPassphrase) {
40130
40176
  yield askDevicePassphrase(device, {
40131
40177
  passphrase: hostPassphrase,
40132
40178
  on_device: false,
40133
40179
  });
40134
- return getDeviceSession(device, {});
40180
+ return getDeviceSession(device, {}, deriveCardano);
40135
40181
  }
40136
- device.emit(DEVICE.PASSPHRASE_ON_DEVICE, device, metadata);
40182
+ device.emit(DEVICE.PASSPHRASE_ON_DEVICE, device, Object.assign(Object.assign({}, metadata), (passphraseInteraction ? { interaction: passphraseInteraction } : {})));
40137
40183
  yield askDevicePassphrase(device, { on_device: true });
40138
- return getDeviceSession(device, {});
40184
+ return getDeviceSession(device, {}, deriveCardano);
40139
40185
  });
40140
40186
  function getProtocolV2WalletSession(device, options) {
40141
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
40187
+ var _a, _b, _c, _d, _e, _f, _g;
40142
40188
  return __awaiter(this, void 0, void 0, function* () {
40143
40189
  const forceWalletSelection = (options === null || options === void 0 ? void 0 : options.forceWalletSelection) === true || (options === null || options === void 0 ? void 0 : options.initSession) === true;
40144
40190
  if (forceWalletSelection) {
@@ -40165,20 +40211,54 @@ function getProtocolV2WalletSession(device, options) {
40165
40211
  : undefined;
40166
40212
  let response;
40167
40213
  let resumed = false;
40214
+ let mainWalletSelected = false;
40215
+ const clearCurrentWalletSession = () => {
40216
+ var _a;
40217
+ if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40218
+ (_a = device.clearStandardInternalState) === null || _a === void 0 ? void 0 : _a.call(device);
40219
+ }
40220
+ else {
40221
+ device.clearInternalState();
40222
+ }
40223
+ };
40224
+ const rejectMismatchedAttachPinWallet = () => __awaiter(this, void 0, void 0, function* () {
40225
+ const features = yield refreshProtocolV2DeviceStatus(device);
40226
+ if (features.unlockedAttachPin !== true) {
40227
+ return;
40228
+ }
40229
+ try {
40230
+ yield device.lockDevice();
40231
+ }
40232
+ catch (_h) {
40233
+ }
40234
+ clearCurrentWalletSession();
40235
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckUnlockTypeError);
40236
+ });
40237
+ const selectMainWallet = (force = false) => __awaiter(this, void 0, void 0, function* () {
40238
+ if (force || !mainWalletSelected) {
40239
+ yield device.unlockDevice(hdTransport.DeviceSessionPinType.Main, {
40240
+ source: 'wallet-session-coordinator',
40241
+ reason: expectedPassphraseState ? 'session-recovery' : 'open-wallet',
40242
+ deviceOnly: true,
40243
+ });
40244
+ mainWalletSelected = true;
40245
+ }
40246
+ });
40168
40247
  if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40169
40248
  expectedPassphraseState = cachedStandardSession === null || cachedStandardSession === void 0 ? void 0 : cachedStandardSession.passphraseState;
40170
40249
  if (cachedStandardSession) {
40171
40250
  try {
40172
- if (((_d = device.features) === null || _d === void 0 ? void 0 : _d.unlockedAttachPin) === true) {
40173
- yield device.unlockDevice(hdTransport.DeviceSessionPinType.Main);
40251
+ if (options === null || options === void 0 ? void 0 : options.selectMainWalletBeforeRestore) {
40252
+ yield selectMainWallet();
40174
40253
  }
40175
40254
  response = yield getDeviceSession(device, {
40176
40255
  session_id: cachedStandardSession.sessionId,
40177
- });
40256
+ btc_test_address: cachedStandardSession.passphraseState,
40257
+ }, options === null || options === void 0 ? void 0 : options.deriveCardano);
40178
40258
  resumed = true;
40179
40259
  }
40180
40260
  catch (error) {
40181
- (_e = device.clearStandardInternalState) === null || _e === void 0 ? void 0 : _e.call(device);
40261
+ (_d = device.clearStandardInternalState) === null || _d === void 0 ? void 0 : _d.call(device);
40182
40262
  if (!isWalletSessionInvalidError(error)) {
40183
40263
  throw error;
40184
40264
  }
@@ -40186,13 +40266,16 @@ function getProtocolV2WalletSession(device, options) {
40186
40266
  }
40187
40267
  }
40188
40268
  if (!response) {
40189
- yield device.unlockDevice(hdTransport.DeviceSessionPinType.Main);
40190
- response = yield getDeviceSession(device, {});
40269
+ yield selectMainWallet();
40270
+ response = yield getDeviceSession(device, {}, options === null || options === void 0 ? void 0 : options.deriveCardano);
40191
40271
  }
40192
40272
  }
40193
40273
  else if (cachedSessionId && expectedPassphraseState) {
40194
40274
  try {
40195
- response = yield getDeviceSession(device, { session_id: cachedSessionId });
40275
+ response = yield getDeviceSession(device, {
40276
+ session_id: cachedSessionId,
40277
+ btc_test_address: expectedPassphraseState,
40278
+ }, options === null || options === void 0 ? void 0 : options.deriveCardano);
40196
40279
  resumed = true;
40197
40280
  }
40198
40281
  catch (error) {
@@ -40203,12 +40286,22 @@ function getProtocolV2WalletSession(device, options) {
40203
40286
  resumed = false;
40204
40287
  }
40205
40288
  }
40289
+ else if (expectedPassphraseState) {
40290
+ try {
40291
+ response = yield getDeviceSession(device, { btc_test_address: expectedPassphraseState }, options === null || options === void 0 ? void 0 : options.deriveCardano);
40292
+ }
40293
+ catch (error) {
40294
+ if ((options === null || options === void 0 ? void 0 : options.resumeOnly) || !isWalletSessionInvalidError(error)) {
40295
+ throw error;
40296
+ }
40297
+ }
40298
+ }
40206
40299
  if (!response) {
40207
40300
  if (options === null || options === void 0 ? void 0 : options.resumeOnly) {
40208
40301
  device.clearInternalState();
40209
40302
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
40210
40303
  }
40211
- response = yield selectDeviceSession(device, expectedPassphraseState);
40304
+ response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano);
40212
40305
  }
40213
40306
  let { message } = response;
40214
40307
  try {
@@ -40216,7 +40309,7 @@ function getProtocolV2WalletSession(device, options) {
40216
40309
  }
40217
40310
  catch (error) {
40218
40311
  if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40219
- (_f = device.clearStandardInternalState) === null || _f === void 0 ? void 0 : _f.call(device);
40312
+ (_e = device.clearStandardInternalState) === null || _e === void 0 ? void 0 : _e.call(device);
40220
40313
  }
40221
40314
  else {
40222
40315
  device.clearInternalState();
@@ -40225,18 +40318,19 @@ function getProtocolV2WalletSession(device, options) {
40225
40318
  }
40226
40319
  if (expectedPassphraseState && expectedPassphraseState !== message.btc_test_address) {
40227
40320
  resumed = false;
40321
+ yield rejectMismatchedAttachPinWallet();
40228
40322
  if (options === null || options === void 0 ? void 0 : options.resumeOnly) {
40229
40323
  device.clearInternalState();
40230
40324
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
40231
40325
  }
40232
40326
  if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40233
- (_g = device.clearStandardInternalState) === null || _g === void 0 ? void 0 : _g.call(device);
40234
- yield device.unlockDevice(hdTransport.DeviceSessionPinType.Main);
40235
- response = yield getDeviceSession(device, {});
40327
+ (_f = device.clearStandardInternalState) === null || _f === void 0 ? void 0 : _f.call(device);
40328
+ yield selectMainWallet(true);
40329
+ response = yield getDeviceSession(device, {}, options === null || options === void 0 ? void 0 : options.deriveCardano);
40236
40330
  }
40237
40331
  else {
40238
40332
  device.clearInternalState();
40239
- response = yield selectDeviceSession(device, expectedPassphraseState);
40333
+ response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano);
40240
40334
  }
40241
40335
  message = response.message;
40242
40336
  try {
@@ -40244,7 +40338,7 @@ function getProtocolV2WalletSession(device, options) {
40244
40338
  }
40245
40339
  catch (error) {
40246
40340
  if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40247
- (_h = device.clearStandardInternalState) === null || _h === void 0 ? void 0 : _h.call(device);
40341
+ (_g = device.clearStandardInternalState) === null || _g === void 0 ? void 0 : _g.call(device);
40248
40342
  }
40249
40343
  else {
40250
40344
  device.clearInternalState();
@@ -40252,12 +40346,8 @@ function getProtocolV2WalletSession(device, options) {
40252
40346
  throw error;
40253
40347
  }
40254
40348
  if (expectedPassphraseState !== message.btc_test_address) {
40255
- if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40256
- (_j = device.clearStandardInternalState) === null || _j === void 0 ? void 0 : _j.call(device);
40257
- }
40258
- else {
40259
- device.clearInternalState();
40260
- }
40349
+ yield rejectMismatchedAttachPinWallet();
40350
+ clearCurrentWalletSession();
40261
40351
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
40262
40352
  }
40263
40353
  }
@@ -40277,16 +40367,17 @@ function getProtocolV2WalletSession(device, options) {
40277
40367
  return {
40278
40368
  passphraseState: message.btc_test_address,
40279
40369
  newSession: message.session_id,
40280
- unlockedAttachPin: (_l = (_k = device.features) === null || _k === void 0 ? void 0 : _k.unlockedAttachPin) !== null && _l !== void 0 ? _l : undefined,
40370
+ unlockedAttachPin: mainWalletSelected ? false : undefined,
40281
40371
  resumed,
40282
40372
  };
40283
40373
  });
40284
40374
  }
40285
- function restoreProtocolV2WalletSession(device, expectedPassphraseState) {
40375
+ function restoreProtocolV2WalletSession(device, expectedPassphraseState, deriveCardano) {
40286
40376
  return __awaiter(this, void 0, void 0, function* () {
40287
40377
  return getProtocolV2WalletSession(device, {
40288
40378
  expectedPassphraseState,
40289
40379
  resumeOnly: true,
40380
+ deriveCardano,
40290
40381
  });
40291
40382
  });
40292
40383
  }
@@ -40351,6 +40442,7 @@ const getPassphraseStateWithRefreshDeviceInfo = (device, options) => __awaiter(v
40351
40442
  initSession: options === null || options === void 0 ? void 0 : options.initSession,
40352
40443
  expectedPassphraseState: options === null || options === void 0 ? void 0 : options.expectPassphraseState,
40353
40444
  onlyMainPin: options === null || options === void 0 ? void 0 : options.onlyMainPin,
40445
+ deriveCardano: options === null || options === void 0 ? void 0 : options.deriveCardano,
40354
40446
  });
40355
40447
  }
40356
40448
  const { features } = device;
@@ -40393,6 +40485,7 @@ const getPassphraseState = (device, options) => __awaiter(void 0, void 0, void 0
40393
40485
  initSession: options === null || options === void 0 ? void 0 : options.initSession,
40394
40486
  expectedPassphraseState: options === null || options === void 0 ? void 0 : options.expectPassphraseState,
40395
40487
  onlyMainPin: options === null || options === void 0 ? void 0 : options.onlyMainPin,
40488
+ deriveCardano: options === null || options === void 0 ? void 0 : options.deriveCardano,
40396
40489
  });
40397
40490
  }
40398
40491
  const supportAttachPinCapability = existCapability(features, hdTransport.Enum_Capability.Capability_AttachToPin);
@@ -43025,8 +43118,10 @@ const PROTOCOL_V2_DEVICE_INFO_TIMEOUT_MS = 10 * 1000;
43025
43118
  function requestProtocolV2ProtocolInfo({ commands, timeoutMs, }) {
43026
43119
  return __awaiter(this, void 0, void 0, function* () {
43027
43120
  const response = timeoutMs === undefined
43028
- ? yield commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {})
43029
- : yield commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {}, { timeoutMs });
43121
+ ? yield commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {
43122
+ eventless_wallet_session: true,
43123
+ })
43124
+ : yield commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', { eventless_wallet_session: true }, { timeoutMs });
43030
43125
  return response.message;
43031
43126
  });
43032
43127
  }
@@ -43054,6 +43149,22 @@ const parseRunOptions = (options) => {
43054
43149
  return options;
43055
43150
  };
43056
43151
  const Log$e = getLogger(exports.LoggerNames.Device);
43152
+ const isProtocolV2DeviceStatusUnsupportedError = (error) => {
43153
+ var _a, _b, _c;
43154
+ if (error instanceof hdShared.HardwareError) {
43155
+ if (error.errorCode === hdShared.HardwareErrorCode.DeviceNotSupportMethod) {
43156
+ return true;
43157
+ }
43158
+ if (((_a = error.params) === null || _a === void 0 ? void 0 : _a.failureCode) === 'Failure_UnexpectedMessage') {
43159
+ return true;
43160
+ }
43161
+ }
43162
+ const message = error instanceof Error
43163
+ ? error.message
43164
+ : String((_c = (_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error) !== null && _c !== void 0 ? _c : '');
43165
+ return (/^Failure_UnexpectedMessage(?:,|\b)/i.test(message) ||
43166
+ /\b(?:unsupported message|handler not registered|message handler not found)\b/i.test(message));
43167
+ };
43057
43168
  function preloadSessionCache(deviceId, passphraseState, sessionId) {
43058
43169
  deviceWalletSessionStore.set(deviceId, passphraseState, sessionId);
43059
43170
  }
@@ -43086,6 +43197,7 @@ class Device extends events.exports {
43086
43197
  this.deviceAcquired = false;
43087
43198
  this.stateStore = new DeviceStateStore();
43088
43199
  this.protocolV2StateNeedsReload = false;
43200
+ this.protocolV2UiInteractionCounter = 0;
43089
43201
  this.externalState = [];
43090
43202
  this.unavailableCapabilities = {};
43091
43203
  this.instance = 0;
@@ -43644,11 +43756,7 @@ class Device extends events.exports {
43644
43756
  }
43645
43757
  }
43646
43758
  if (refresh.has('status') && !initializedWithDeviceInfo) {
43647
- const deviceInfo = refreshedDeviceInfo !== null && refreshedDeviceInfo !== void 0 ? refreshedDeviceInfo : (yield requestProtocolV2DeviceInfo({
43648
- commands: this.commands,
43649
- request: getProtocolV2DeviceInfoRequest(),
43650
- }));
43651
- yield this.probeProtocolV2RuntimeState(deviceInfo);
43759
+ yield this.probeProtocolV2RuntimeState(refreshedDeviceInfo);
43652
43760
  }
43653
43761
  if (refresh.has('settings') && ((_c = this.state) === null || _c === void 0 ? void 0 : _c.status.mode) === 'normal') {
43654
43762
  const { message } = yield this.commands.typedCall('DeviceSettingsGet', 'DeviceSettings', {});
@@ -43708,15 +43816,55 @@ class Device extends events.exports {
43708
43816
  this.updateState(mapFeaturesToState(normalized), source);
43709
43817
  return this.features;
43710
43818
  }
43819
+ ensureProtocolV2RuntimeContext(timeoutMs) {
43820
+ var _a, _b, _c, _d;
43821
+ return __awaiter(this, void 0, void 0, function* () {
43822
+ const cachedProtocolInfo = (_a = this.protocolV2RuntimeContext) !== null && _a !== void 0 ? _a : (!this.protocolV2StateNeedsReload
43823
+ ? (_d = (_c = (_b = this.state) === null || _b === void 0 ? void 0 : _b.raw) === null || _c === void 0 ? void 0 : _c.protocolV2ProtocolInfo) !== null && _d !== void 0 ? _d : undefined
43824
+ : undefined);
43825
+ if (cachedProtocolInfo) {
43826
+ this.protocolV2RuntimeContext = cachedProtocolInfo;
43827
+ return cachedProtocolInfo;
43828
+ }
43829
+ if (this.protocolV2RuntimeContextPromise) {
43830
+ return this.protocolV2RuntimeContextPromise;
43831
+ }
43832
+ const requestToken = {};
43833
+ const pendingRequest = (() => __awaiter(this, void 0, void 0, function* () {
43834
+ const protocolInfo = yield requestProtocolV2ProtocolInfo({
43835
+ commands: this.commands,
43836
+ timeoutMs,
43837
+ });
43838
+ if (this.protocolV2RuntimeContextRequestToken !== requestToken) {
43839
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, 'Protocol V2 runtime context was invalidated while loading.');
43840
+ }
43841
+ this.protocolV2RuntimeContext = protocolInfo;
43842
+ return protocolInfo;
43843
+ }))();
43844
+ this.protocolV2RuntimeContextRequestToken = requestToken;
43845
+ this.protocolV2RuntimeContextPromise = pendingRequest;
43846
+ try {
43847
+ return yield pendingRequest;
43848
+ }
43849
+ finally {
43850
+ if (this.protocolV2RuntimeContextPromise === pendingRequest) {
43851
+ this.protocolV2RuntimeContextPromise = undefined;
43852
+ }
43853
+ if (this.protocolV2RuntimeContextRequestToken === requestToken) {
43854
+ this.protocolV2RuntimeContextRequestToken = undefined;
43855
+ }
43856
+ }
43857
+ });
43858
+ }
43711
43859
  probeProtocolV2RuntimeState(deviceInfo, timeoutMs) {
43712
- var _a;
43860
+ var _a, _b, _c;
43713
43861
  return __awaiter(this, void 0, void 0, function* () {
43714
- const protocolInfo = yield requestProtocolV2ProtocolInfo({
43715
- commands: this.commands,
43716
- timeoutMs,
43717
- });
43862
+ const protocolInfo = yield this.ensureProtocolV2RuntimeContext(timeoutMs);
43718
43863
  const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
43719
- const protocolV2DeviceType = resolveProtocolV2DeviceIdentity((_a = deviceInfo.hw) === null || _a === void 0 ? void 0 : _a.Device_type).deviceType;
43864
+ const runtimeDeviceInfo = deviceInfo !== null && deviceInfo !== void 0 ? deviceInfo : (_b = (_a = this.state) === null || _a === void 0 ? void 0 : _a.raw) === null || _b === void 0 ? void 0 : _b.protocolV2DeviceInfo;
43865
+ const protocolV2DeviceType = runtimeDeviceInfo
43866
+ ? resolveProtocolV2DeviceIdentity((_c = runtimeDeviceInfo.hw) === null || _c === void 0 ? void 0 : _c.Device_type).deviceType
43867
+ : this.getCurrentDeviceType();
43720
43868
  if (runtimeMode === 'romloader' && protocolV2DeviceType !== hdShared.EDeviceType.Pro2) {
43721
43869
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, 'Protocol V2 romloader mode is only supported for Pro2.');
43722
43870
  }
@@ -43730,10 +43878,19 @@ class Device extends events.exports {
43730
43878
  }
43731
43879
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, `Unknown Protocol V2 build fingerprint without DeviceStatusGet capability: ${protocolInfo.build_fingerprint}`);
43732
43880
  }
43733
- const deviceStatus = yield requestProtocolV2DeviceStatus({
43734
- commands: this.commands,
43735
- timeoutMs,
43736
- });
43881
+ let deviceStatus;
43882
+ try {
43883
+ deviceStatus = yield requestProtocolV2DeviceStatus({
43884
+ commands: this.commands,
43885
+ timeoutMs,
43886
+ });
43887
+ }
43888
+ catch (error) {
43889
+ if (runtimeMode === undefined && isProtocolV2DeviceStatusUnsupportedError(error)) {
43890
+ return this.updateProtocolV2Features(deviceInfo, null, 'bootloader', protocolInfo);
43891
+ }
43892
+ throw error;
43893
+ }
43737
43894
  return this.updateProtocolV2Features(deviceInfo, deviceStatus, 'normal', protocolInfo);
43738
43895
  });
43739
43896
  }
@@ -43764,6 +43921,9 @@ class Device extends events.exports {
43764
43921
  if (!this.isProtocolV2())
43765
43922
  return;
43766
43923
  this.protocolV2StateNeedsReload = true;
43924
+ this.protocolV2RuntimeContext = undefined;
43925
+ this.protocolV2RuntimeContextPromise = undefined;
43926
+ this.protocolV2RuntimeContextRequestToken = undefined;
43767
43927
  this.clearPreInitialized();
43768
43928
  }
43769
43929
  invalidateAfterWipe() {
@@ -43771,9 +43931,14 @@ class Device extends events.exports {
43771
43931
  if (deviceId) {
43772
43932
  deviceWalletSessionStore.deleteDevice(deviceId);
43773
43933
  }
43774
- if (this.isProtocolV2() && this.originalDescriptor.path !== deviceId) {
43775
- deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
43934
+ if (this.isProtocolV2()) {
43935
+ if (this.originalDescriptor.path !== deviceId) {
43936
+ deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
43937
+ }
43776
43938
  this.protocolV2StateNeedsReload = true;
43939
+ this.protocolV2RuntimeContext = undefined;
43940
+ this.protocolV2RuntimeContextPromise = undefined;
43941
+ this.protocolV2RuntimeContextRequestToken = undefined;
43777
43942
  }
43778
43943
  this.passphraseState = undefined;
43779
43944
  this.stateStore = new DeviceStateStore();
@@ -43784,6 +43949,9 @@ class Device extends events.exports {
43784
43949
  if (!this.isProtocolV2())
43785
43950
  return;
43786
43951
  this.protocolV2StateNeedsReload = true;
43952
+ this.protocolV2RuntimeContext = undefined;
43953
+ this.protocolV2RuntimeContextPromise = undefined;
43954
+ this.protocolV2RuntimeContextRequestToken = undefined;
43787
43955
  this.clearPreInitialized();
43788
43956
  let loaderMode;
43789
43957
  if (rebootType === hdTransport.DeviceRebootType.Bootloader) {
@@ -44082,6 +44250,55 @@ class Device extends events.exports {
44082
44250
  return res.message;
44083
44251
  });
44084
44252
  }
44253
+ beginProtocolV2UiInteraction() {
44254
+ if (!this.isProtocolV2())
44255
+ return;
44256
+ this.protocolV2UiInteraction = {
44257
+ interactionId: `${this.instanceId}:${Date.now()}:${++this.protocolV2UiInteractionCounter}`,
44258
+ phaseCounter: 0,
44259
+ sequence: 0,
44260
+ opened: false,
44261
+ };
44262
+ }
44263
+ createProtocolV2UiPhaseMetadata(phase, transition, options) {
44264
+ var _a;
44265
+ if (!this.isProtocolV2())
44266
+ return undefined;
44267
+ if (!this.protocolV2UiInteraction)
44268
+ this.beginProtocolV2UiInteraction();
44269
+ const interaction = this.protocolV2UiInteraction;
44270
+ if (!interaction)
44271
+ return undefined;
44272
+ const phaseId = (_a = options === null || options === void 0 ? void 0 : options.phaseId) !== null && _a !== void 0 ? _a : `${interaction.interactionId}:phase-${++interaction.phaseCounter}`;
44273
+ interaction.opened = true;
44274
+ interaction.sequence += 1;
44275
+ return Object.assign(Object.assign({ interactionId: interaction.interactionId, phaseId, sequence: interaction.sequence, phase,
44276
+ transition }, ((options === null || options === void 0 ? void 0 : options.outcome) ? { outcome: options.outcome } : {})), { protocol: 'V2' });
44277
+ }
44278
+ completeProtocolV2UiPhase(phase, outcome = 'succeeded') {
44279
+ return this.createProtocolV2UiPhaseMetadata(phase.phase, 'complete', {
44280
+ phaseId: phase.phaseId,
44281
+ outcome,
44282
+ });
44283
+ }
44284
+ finishProtocolV2UiInteraction(outcome = 'succeeded') {
44285
+ const interaction = this.protocolV2UiInteraction;
44286
+ if (!(interaction === null || interaction === void 0 ? void 0 : interaction.opened)) {
44287
+ this.protocolV2UiInteraction = undefined;
44288
+ return undefined;
44289
+ }
44290
+ const phaseId = `${interaction.interactionId}:phase-${Math.max(interaction.phaseCounter, 1)}`;
44291
+ const metadata = this.createProtocolV2UiPhaseMetadata('processing', 'finish', {
44292
+ phaseId,
44293
+ outcome,
44294
+ });
44295
+ this.protocolV2UiInteraction = undefined;
44296
+ return metadata;
44297
+ }
44298
+ hasOpenProtocolV2UiInteraction() {
44299
+ var _a;
44300
+ return ((_a = this.protocolV2UiInteraction) === null || _a === void 0 ? void 0 : _a.opened) === true;
44301
+ }
44085
44302
  supportUnlockVersionRange() {
44086
44303
  return {
44087
44304
  pro: {
@@ -44089,28 +44306,50 @@ class Device extends events.exports {
44089
44306
  },
44090
44307
  };
44091
44308
  }
44092
- unlockDevice(pinType = hdTransport.DeviceSessionPinType.Main) {
44093
- var _a, _b, _c, _d;
44309
+ unlockDevice(pinType, options) {
44310
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
44094
44311
  return __awaiter(this, void 0, void 0, function* () {
44095
44312
  if (this.isProtocolV2()) {
44313
+ const requestedPinType = pinType !== null && pinType !== void 0 ? pinType : hdTransport.DeviceSessionPinType.Main;
44314
+ const interaction = (_a = options === null || options === void 0 ? void 0 : options.interaction) !== null && _a !== void 0 ? _a : ((options === null || options === void 0 ? void 0 : options.emitUiEvent) === false
44315
+ ? undefined
44316
+ : this.createProtocolV2UiPhaseMetadata('pin', 'start'));
44317
+ if ((options === null || options === void 0 ? void 0 : options.emitUiEvent) !== false) {
44318
+ this.emit(DEVICE.PIN_ON_DEVICE, this, requestedPinType, {
44319
+ source: (_b = options === null || options === void 0 ? void 0 : options.source) !== null && _b !== void 0 ? _b : 'unlock-coordinator',
44320
+ reason: (_c = options === null || options === void 0 ? void 0 : options.reason) !== null && _c !== void 0 ? _c : 'device-unlock',
44321
+ deviceOnly: (_d = options === null || options === void 0 ? void 0 : options.deviceOnly) !== null && _d !== void 0 ? _d : true,
44322
+ completion: options === null || options === void 0 ? void 0 : options.completion,
44323
+ method: options === null || options === void 0 ? void 0 : options.method,
44324
+ page: options === null || options === void 0 ? void 0 : options.page,
44325
+ operation: options === null || options === void 0 ? void 0 : options.operation,
44326
+ interaction: (_e = options === null || options === void 0 ? void 0 : options.interaction) !== null && _e !== void 0 ? _e : interaction,
44327
+ });
44328
+ }
44096
44329
  try {
44097
- yield this.commands.typedCall('DeviceSessionAskPin', 'Success', { type: pinType });
44330
+ yield this.commands.typedCall('DeviceSessionAskPin', 'Success', {
44331
+ type: requestedPinType,
44332
+ });
44098
44333
  }
44099
44334
  catch (error) {
44100
44335
  const errorText = error instanceof Error
44101
44336
  ? `${error.name} ${error.message}`
44102
- : String((_b = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error) !== null && _b !== void 0 ? _b : '');
44337
+ : String((_g = (_f = error === null || error === void 0 ? void 0 : error.message) !== null && _f !== void 0 ? _f : error) !== null && _g !== void 0 ? _g : '');
44103
44338
  if (errorText.includes('Failure_UnexpectedMessage')) {
44104
44339
  throw hdShared.createDeviceNotSupportMethodError('deviceUnlock', this.getCurrentFirmwareType());
44105
44340
  }
44106
44341
  throw error;
44107
44342
  }
44343
+ const completion = interaction ? this.completeProtocolV2UiPhase(interaction) : undefined;
44344
+ if (completion) {
44345
+ this.emit(DEVICE.PIN_ON_DEVICE_COMPLETE, this, completion);
44346
+ }
44108
44347
  const status = yield requestProtocolV2DeviceStatus({ commands: this.commands });
44109
44348
  return this.updateProtocolV2Status(status);
44110
44349
  }
44111
- const firmwareVersion = (_c = this.getCurrentFirmwareVersionString()) !== null && _c !== void 0 ? _c : '0.0.0';
44350
+ const firmwareVersion = (_h = this.getCurrentFirmwareVersionString()) !== null && _h !== void 0 ? _h : '0.0.0';
44112
44351
  const versionRange = this.getCurrentMethodVersionRange(type => this.supportUnlockVersionRange()[type]);
44113
- const supportAttachPinCapability = (_d = this.state) === null || _d === void 0 ? void 0 : _d.capabilities.includes(hdTransport.Enum_Capability.Capability_AttachToPin);
44352
+ const supportAttachPinCapability = (_j = this.state) === null || _j === void 0 ? void 0 : _j.capabilities.includes(hdTransport.Enum_Capability.Capability_AttachToPin);
44114
44353
  const supportUnlock = supportAttachPinCapability ||
44115
44354
  (versionRange &&
44116
44355
  semver__default["default"].valid(firmwareVersion) &&
@@ -44145,7 +44384,7 @@ class Device extends events.exports {
44145
44384
  return Promise.resolve(features);
44146
44385
  });
44147
44386
  }
44148
- checkPassphraseStateSafety(passphraseState, useEmptyPassphrase, skipPassphraseCheck) {
44387
+ checkPassphraseStateSafety(passphraseState, useEmptyPassphrase, skipPassphraseCheck, deriveCardano) {
44149
44388
  return __awaiter(this, void 0, void 0, function* () {
44150
44389
  if (this.isUnacquired())
44151
44390
  return false;
@@ -44153,6 +44392,7 @@ class Device extends events.exports {
44153
44392
  const { passphraseState: newPassphraseState, unlockedAttachPin } = yield getPassphraseStateWithRefreshDeviceInfo(this, {
44154
44393
  expectPassphraseState: expectedPassphraseState,
44155
44394
  onlyMainPin: useEmptyPassphrase,
44395
+ deriveCardano,
44156
44396
  });
44157
44397
  const mainWalletUseAttachPin = unlockedAttachPin && useEmptyPassphrase;
44158
44398
  const useErrorAttachPin = unlockedAttachPin &&
@@ -44837,7 +45077,12 @@ class GetPassphraseState extends BaseMethod {
44837
45077
  if (isProtocolV2 && this.payload.useEmptyPassphrase !== true) {
44838
45078
  const features = yield refreshProtocolV2DeviceStatus(this.device);
44839
45079
  if (features.unlocked === false) {
44840
- yield this.device.unlockDevice();
45080
+ yield this.device.unlockDevice(hdTransport.DeviceSessionPinType.Main, {
45081
+ source: 'unlock-coordinator',
45082
+ reason: 'device-locked',
45083
+ deviceOnly: true,
45084
+ method: 'getPassphraseState',
45085
+ });
44841
45086
  }
44842
45087
  }
44843
45088
  const { passphraseState } = yield getPassphraseStateWithRefreshDeviceInfo(this.device, isProtocolV2
@@ -45112,14 +45357,23 @@ class OpenWalletSession extends BaseMethod {
45112
45357
  });
45113
45358
  const unlockProtocolV2IfLocked = () => __awaiter(this, void 0, void 0, function* () {
45114
45359
  if (isProtocolV2 && state.status.unlocked === false) {
45115
- yield this.device.unlockDevice();
45360
+ yield this.device.unlockDevice(hdTransport.DeviceSessionPinType.Main, {
45361
+ source: 'unlock-coordinator',
45362
+ reason: 'device-locked',
45363
+ deviceOnly: true,
45364
+ method: 'openWalletSession',
45365
+ });
45116
45366
  }
45117
45367
  });
45118
45368
  const protocol = isProtocolV2 ? 'V2' : 'V1';
45119
45369
  if (this.params.mode === OpenWalletSessionMode.Standard) {
45120
45370
  this.device.passphraseState = undefined;
45121
45371
  const session = isProtocolV2
45122
- ? yield getProtocolV2WalletSession(this.device, { onlyMainPin: true })
45372
+ ? yield getProtocolV2WalletSession(this.device, {
45373
+ onlyMainPin: true,
45374
+ deriveCardano: this.payload.deriveCardano,
45375
+ selectMainWalletBeforeRestore: state.status.unlocked === false || state.status.unlockedAttachPin === true,
45376
+ })
45123
45377
  : yield getPassphraseStateWithRefreshDeviceInfo(this.device, {
45124
45378
  onlyMainPin: true,
45125
45379
  initSession: this.payload.initSession,
@@ -45168,6 +45422,7 @@ class OpenWalletSession extends BaseMethod {
45168
45422
  const session = isProtocolV2
45169
45423
  ? yield getProtocolV2WalletSession(this.device, {
45170
45424
  expectedPassphraseState: this.params.passphraseState,
45425
+ deriveCardano: this.payload.deriveCardano,
45171
45426
  })
45172
45427
  : yield getPassphraseStateWithRefreshDeviceInfo(this.device, {
45173
45428
  expectPassphraseState: this.params.passphraseState,
@@ -45182,7 +45437,10 @@ class OpenWalletSession extends BaseMethod {
45182
45437
  this.device.passphraseState = undefined;
45183
45438
  yield unlockProtocolV2IfLocked();
45184
45439
  const session = isProtocolV2
45185
- ? yield getProtocolV2WalletSession(this.device, { forceWalletSelection: true })
45440
+ ? yield getProtocolV2WalletSession(this.device, {
45441
+ forceWalletSelection: true,
45442
+ deriveCardano: this.payload.deriveCardano,
45443
+ })
45186
45444
  : yield getPassphraseStateWithRefreshDeviceInfo(this.device, { initSession: true });
45187
45445
  const deviceId = isProtocolV2 ? yield refreshProtocolV2DeviceId() : requireDeviceId();
45188
45446
  if (isProtocolV2 && this.device.getCurrentPassphraseProtection() !== true) {
@@ -47455,7 +47713,7 @@ class DeviceUnlock extends BaseMethod {
47455
47713
  }
47456
47714
  run() {
47457
47715
  return __awaiter(this, void 0, void 0, function* () {
47458
- return this.device.unlockDevice();
47716
+ return this.device.unlockDevice(undefined, { emitUiEvent: false });
47459
47717
  });
47460
47718
  }
47461
47719
  }
@@ -49143,7 +49401,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
49143
49401
  if (binary.byteLength === 0) {
49144
49402
  throw new Error(`Protocol V2 RESC bundle is empty: ${bundle.name}`);
49145
49403
  }
49146
- if (downloadedFromRemote && (bundle.version || bundle.payloadHash || bundle.headerHash)) {
49404
+ if (downloadedFromRemote) {
49147
49405
  const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(binary));
49148
49406
  if (!header || header.type !== 'RESC') {
49149
49407
  throw new Error(`Invalid Protocol V2 RESC bundle header: ${bundle.name}`);
@@ -49435,14 +49693,22 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
49435
49693
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, `Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${(_a = failedTarget.status) !== null && _a !== void 0 ? _a : 'unknown'} payloadVersion=${(_b = failedTarget.payload_version) !== null && _b !== void 0 ? _b : 'unknown'} path=${(_c = failedTarget.path) !== null && _c !== void 0 ? _c : 'unknown'}`);
49436
49694
  }
49437
49695
  const matchingTargets = statusTargets.filter(target => { var _a; return expectedTargetIds.has((_a = normalizeProtocolV2TargetId(target.target_id)) !== null && _a !== void 0 ? _a : -1); });
49438
- const completedTargets = matchingTargets.filter(target => isProtocolV2TargetStatusFinished(target.status));
49439
- if (completedTargets.length === expectedTargetIds.size && expectedTargetIds.size > 0) {
49696
+ const completedTargetIds = new Set();
49697
+ matchingTargets.forEach(target => {
49698
+ const targetId = normalizeProtocolV2TargetId(target.target_id);
49699
+ if (targetId !== undefined && isProtocolV2TargetStatusFinished(target.status)) {
49700
+ completedTargetIds.add(targetId);
49701
+ }
49702
+ });
49703
+ const allExpectedTargetsCompleted = expectedTargetIds.size > 0 &&
49704
+ Array.from(expectedTargetIds).every(targetId => completedTargetIds.has(targetId));
49705
+ if (allExpectedTargetsCompleted) {
49440
49706
  this.postProgressMessage(100, 'installingFirmware');
49441
49707
  return true;
49442
49708
  }
49443
49709
  if (expectedTargetIds.size > 0 && matchingTargets.length > 0) {
49444
49710
  const hasInProgressTarget = matchingTargets.some(target => isProtocolV2TargetStatusInProgress(target.status));
49445
- const completedProgress = Math.floor((completedTargets.length / expectedTargetIds.size) * 100);
49711
+ const completedProgress = Math.floor((completedTargetIds.size / expectedTargetIds.size) * 100);
49446
49712
  const progress = Math.min(99, Math.max(completedProgress, hasInProgressTarget ? 1 : 0));
49447
49713
  this.postProgressMessage(progress, 'installingFirmware');
49448
49714
  }
@@ -50210,95 +50476,316 @@ class CipherKeyValue extends BaseMethod {
50210
50476
  }
50211
50477
  }
50212
50478
 
50213
- const Mainnet = 'mainnet';
50214
- const networkAliases = {
50215
- tbtc: { name: 'btc', coin: 'Testnet' },
50216
- bch: { name: 'btc', coin: 'Bcash' },
50217
- doge: { name: 'btc', coin: 'Dogecoin' },
50218
- ltc: { name: 'btc', coin: 'Litecoin' },
50219
- neurai: { name: 'btc', coin: 'Neurai' },
50220
- };
50221
- const networkConfigMap = {
50222
- btc: {
50223
- methodName: 'btcGetPublicKey',
50224
- getParams: (baseParams, chainName) => (Object.assign({ coin: chainName }, baseParams)),
50225
- },
50226
- evm: {
50227
- methodName: 'evmGetAddress',
50228
- getParams: (baseParams, chainName) => {
50229
- const { path, showOnOneKey } = baseParams;
50230
- let chainId;
50231
- if (chainName) {
50232
- chainId = parseInt(chainName);
50233
- }
50234
- return {
50235
- chainId,
50236
- path,
50237
- showOnOneKey,
50238
- };
50239
- },
50240
- },
50241
- sol: {
50242
- methodName: 'solGetAddress',
50243
- },
50244
- algo: {
50245
- methodName: 'algoGetAddress',
50246
- },
50247
- near: {
50248
- methodName: 'nearGetAddress',
50249
- },
50250
- stc: {
50251
- methodName: 'starcoinGetAddress',
50252
- },
50253
- cfx: {
50254
- methodName: 'confluxGetAddress',
50255
- getParams: (baseParams, chainName) => {
50256
- const { path, showOnOneKey } = baseParams;
50257
- return {
50258
- chainId: parseInt(chainName !== null && chainName !== void 0 ? chainName : '1029'),
50259
- path,
50260
- showOnOneKey,
50261
- };
50262
- },
50263
- },
50264
- tron: {
50265
- methodName: 'tronGetAddress',
50266
- },
50267
- aptos: {
50268
- methodName: 'aptosGetAddress',
50269
- },
50270
- xrp: {
50271
- methodName: 'xrpGetAddress',
50272
- },
50273
- cosmos: {
50274
- methodName: 'cosmosGetPublicKey',
50275
- getParams: (baseParams) => {
50276
- const { path, prefix, showOnOneKey } = baseParams;
50277
- return {
50278
- hrp: prefix,
50279
- path,
50280
- showOnOneKey,
50281
- };
50282
- },
50283
- },
50284
- ada: {
50285
- methodName: 'cardanoGetAddress',
50286
- getParams: (baseParams, chainName) => {
50287
- const { path, showOnOneKey } = baseParams;
50288
- const addressPath = typeof path === 'string' ? `${path}/0/0` : serializedPath([...path, 0, 0]);
50289
- const stakingPath = typeof path === 'string' ? `${path}/2/0` : serializedPath([...path, 2, 0]);
50290
- let networkId = 1;
50291
- if (chainName) {
50292
- networkId = chainName === Mainnet ? 1 : 0;
50479
+ function isDeviceLockedError(error) {
50480
+ return (typeof error === 'object' &&
50481
+ error !== null &&
50482
+ 'errorCode' in error &&
50483
+ error.errorCode === hdShared.HardwareErrorCode.DeviceLocked);
50484
+ }
50485
+
50486
+ const isProtocolV2UiEnabled = (method) => method.protocolV2UiMode !== 'none';
50487
+ const getDisplayState = (value) => {
50488
+ const visited = new Set();
50489
+ let seen = false;
50490
+ let enabled = false;
50491
+ const visit = (current) => {
50492
+ if (current == null || typeof current !== 'object')
50493
+ return;
50494
+ if (visited.has(current))
50495
+ return;
50496
+ visited.add(current);
50497
+ if (Array.isArray(current)) {
50498
+ current.forEach(visit);
50499
+ return;
50500
+ }
50501
+ Object.entries(current).forEach(([key, item]) => {
50502
+ if ((key === 'show_display' || key === 'showOnOneKey') && typeof item === 'boolean') {
50503
+ seen = true;
50504
+ enabled || (enabled = item);
50505
+ return;
50293
50506
  }
50294
- return {
50295
- addressParameters: {
50296
- addressType: hdTransport.Messages.CardanoAddressType.BASE,
50297
- path: addressPath,
50298
- stakingPath,
50299
- },
50300
- protocolMagic: 764824073,
50301
- networkId,
50507
+ visit(item);
50508
+ });
50509
+ };
50510
+ visit(value);
50511
+ return { seen, enabled };
50512
+ };
50513
+ const createMethodInteraction = (reason, operation) => ({
50514
+ request: 'button',
50515
+ source: 'method-lifecycle',
50516
+ reason,
50517
+ completion: 'operation-completed',
50518
+ deviceOnly: true,
50519
+ operation,
50520
+ });
50521
+ const hasCipherConfirmation = (value) => {
50522
+ if (Array.isArray(value))
50523
+ return value.some(hasCipherConfirmation);
50524
+ if (value == null || typeof value !== 'object')
50525
+ return false;
50526
+ const params = value;
50527
+ return params.encrypt === true ? params.ask_on_encrypt === true : params.ask_on_decrypt === true;
50528
+ };
50529
+ const resolveProtocolV2UiInteraction = (method) => {
50530
+ if (method.protocolV2UiInteraction)
50531
+ return method.protocolV2UiInteraction;
50532
+ const operation = method.name;
50533
+ if (!operation)
50534
+ return undefined;
50535
+ const isAddress = /getAddress(?:ByLoop)?$/i.test(operation);
50536
+ const isPublicKey = /getPublicKey$/i.test(operation);
50537
+ if (isAddress || isPublicKey) {
50538
+ const paramsDisplay = getDisplayState(method.params);
50539
+ const payloadDisplay = getDisplayState(method.payload);
50540
+ const display = paramsDisplay.seen ? paramsDisplay : payloadDisplay;
50541
+ const shouldDisplay = display.seen ? display.enabled : isAddress;
50542
+ if (!shouldDisplay)
50543
+ return undefined;
50544
+ return createMethodInteraction(isAddress ? 'address-confirmation' : 'public-key-confirmation', operation);
50545
+ }
50546
+ if (/sign/i.test(operation) || /verifyMessage$/i.test(operation) || operation === 'lnurlAuth') {
50547
+ return createMethodInteraction('signing-confirmation', operation);
50548
+ }
50549
+ if (operation === 'nostrEncryptMessage' || operation === 'nostrDecryptMessage') {
50550
+ const display = getDisplayState(method.params);
50551
+ if (!display.enabled)
50552
+ return undefined;
50553
+ return createMethodInteraction('signing-confirmation', operation);
50554
+ }
50555
+ if (operation === 'cipherKeyValue' && hasCipherConfirmation(method.params)) {
50556
+ return createMethodInteraction('signing-confirmation', operation);
50557
+ }
50558
+ return undefined;
50559
+ };
50560
+ class ProtocolV2UiInteractionCoordinator {
50561
+ constructor(device, postMessage) {
50562
+ this.opened = false;
50563
+ this.closed = false;
50564
+ this.device = device;
50565
+ this.postMessage = postMessage;
50566
+ }
50567
+ enterMethodInteraction(interaction) {
50568
+ var _a, _b, _c, _d;
50569
+ this.methodInteraction = interaction;
50570
+ if (!interaction)
50571
+ return;
50572
+ const { request } = interaction, metadata = __rest(interaction, ["request"]);
50573
+ const interactionMeta = (_b = (_a = this.device).createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, request === 'pin' ? 'pin' : 'button', 'start');
50574
+ this.emit(request === 'pin' ? UI_REQUEST.REQUEST_PIN : UI_REQUEST.REQUEST_BUTTON, Object.assign(Object.assign({ device: this.device.toMessageObject() }, metadata), (interactionMeta ? { interaction: interactionMeta } : {})), `method:${request}:${interaction.reason}:${(_c = interaction.page) !== null && _c !== void 0 ? _c : ''}:${(_d = interaction.operation) !== null && _d !== void 0 ? _d : ''}`);
50575
+ }
50576
+ enterUnlockInteraction(method) {
50577
+ var _a, _b;
50578
+ const interaction = (_b = (_a = this.device).createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, 'pin', 'start');
50579
+ this.emit(UI_REQUEST.REQUEST_PIN, Object.assign({ device: this.device.toMessageObject(), source: 'unlock-coordinator', reason: 'device-locked', deviceOnly: true, method }, (interaction ? { interaction } : {})), `unlock:${method !== null && method !== void 0 ? method : ''}`);
50580
+ return interaction;
50581
+ }
50582
+ resumeMethodInteraction() {
50583
+ this.enterMethodInteraction(this.methodInteraction);
50584
+ }
50585
+ close() {
50586
+ var _a, _b, _c, _d;
50587
+ if (!this.device.isProtocolV2() ||
50588
+ (!this.opened && !((_b = (_a = this.device).hasOpenProtocolV2UiInteraction) === null || _b === void 0 ? void 0 : _b.call(_a))) ||
50589
+ this.closed)
50590
+ return;
50591
+ this.closed = true;
50592
+ const interaction = (_d = (_c = this.device).finishProtocolV2UiInteraction) === null || _d === void 0 ? void 0 : _d.call(_c);
50593
+ this.postMessage(interaction
50594
+ ? createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW, interaction)
50595
+ : createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW));
50596
+ }
50597
+ emit(type, payload, phase) {
50598
+ if (!this.device.isProtocolV2() || this.closed || this.currentPhase === phase)
50599
+ return;
50600
+ this.currentPhase = phase;
50601
+ this.opened = true;
50602
+ const message = type === UI_REQUEST.REQUEST_BUTTON
50603
+ ? createUiMessage(UI_REQUEST.REQUEST_BUTTON, payload)
50604
+ : createUiMessage(UI_REQUEST.REQUEST_PIN, payload);
50605
+ this.postMessage(message);
50606
+ }
50607
+ }
50608
+
50609
+ const Log$3 = getLogger(exports.LoggerNames.Core);
50610
+ const restoreExpectedWalletSessionAfterUnlock = (method, device) => __awaiter(void 0, void 0, void 0, function* () {
50611
+ var _a, _b, _c;
50612
+ const expectedPassphraseState = ((_a = method.payload) === null || _a === void 0 ? void 0 : _a.useEmptyPassphrase)
50613
+ ? undefined
50614
+ : (_c = (_b = method.payload) === null || _b === void 0 ? void 0 : _b.passphraseState) !== null && _c !== void 0 ? _c : device.passphraseState;
50615
+ if (!method.useDevicePassphraseState ||
50616
+ typeof expectedPassphraseState !== 'string' ||
50617
+ expectedPassphraseState.length === 0) {
50618
+ return;
50619
+ }
50620
+ yield restoreProtocolV2WalletSession(device, expectedPassphraseState);
50621
+ Log$3.debug('Protocol V2 wallet session restored after unlock', { method: method.name });
50622
+ });
50623
+ function runMethodWithUnlockRetry(method, device, uiCoordinator) {
50624
+ var _a, _b, _c, _d, _e;
50625
+ return __awaiter(this, void 0, void 0, function* () {
50626
+ const shouldEmitUi = isProtocolV2UiEnabled(method);
50627
+ const shouldCoordinateUi = shouldEmitUi && uiCoordinator !== undefined;
50628
+ const isProtocolV2 = device.isProtocolV2();
50629
+ const requiresFreshStatus = isProtocolV2 &&
50630
+ method.unlockPolicy === 'unlock-before-run' &&
50631
+ !((_a = device.isBootloader) === null || _a === void 0 ? void 0 : _a.call(device)) &&
50632
+ !((_b = device.isRomloader) === null || _b === void 0 ? void 0 : _b.call(device));
50633
+ if (requiresFreshStatus) {
50634
+ yield refreshProtocolV2DeviceStatus(device);
50635
+ }
50636
+ const shouldUnlockBeforeRun = isProtocolV2 &&
50637
+ method.unlockPolicy !== 'none' &&
50638
+ !((_c = device.isBootloader) === null || _c === void 0 ? void 0 : _c.call(device)) &&
50639
+ !((_d = device.isRomloader) === null || _d === void 0 ? void 0 : _d.call(device)) &&
50640
+ ((_e = device.features) === null || _e === void 0 ? void 0 : _e.unlocked) === false;
50641
+ if (shouldUnlockBeforeRun) {
50642
+ const unlockInteraction = shouldCoordinateUi
50643
+ ? uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterUnlockInteraction(method.name)
50644
+ : undefined;
50645
+ yield device.unlockDevice(undefined, shouldCoordinateUi
50646
+ ? { emitUiEvent: false, interaction: unlockInteraction }
50647
+ : {
50648
+ source: 'unlock-coordinator',
50649
+ reason: 'device-locked',
50650
+ deviceOnly: true,
50651
+ method: method.name,
50652
+ });
50653
+ Log$3.debug('Protocol V2 pre-unlock completed', { method: method.name });
50654
+ yield restoreExpectedWalletSessionAfterUnlock(method, device);
50655
+ if (shouldCoordinateUi) {
50656
+ uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
50657
+ }
50658
+ return method.run();
50659
+ }
50660
+ if (shouldCoordinateUi) {
50661
+ uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
50662
+ }
50663
+ try {
50664
+ return yield method.run();
50665
+ }
50666
+ catch (error) {
50667
+ if (!isProtocolV2 || method.unlockPolicy !== 'retry-on-locked' || !isDeviceLockedError(error)) {
50668
+ throw error;
50669
+ }
50670
+ Log$3.debug('Protocol V2 unlock retry triggered', { method: method.name });
50671
+ const unlockInteraction = shouldCoordinateUi
50672
+ ? uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterUnlockInteraction(method.name)
50673
+ : undefined;
50674
+ yield device.unlockDevice(undefined, shouldCoordinateUi
50675
+ ? { emitUiEvent: false, interaction: unlockInteraction }
50676
+ : {
50677
+ source: 'unlock-coordinator',
50678
+ reason: 'device-locked',
50679
+ deviceOnly: true,
50680
+ method: method.name,
50681
+ });
50682
+ Log$3.debug('Protocol V2 unlock completed', { method: method.name });
50683
+ yield restoreExpectedWalletSessionAfterUnlock(method, device);
50684
+ if (shouldCoordinateUi) {
50685
+ uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.resumeMethodInteraction();
50686
+ }
50687
+ try {
50688
+ const response = yield method.run();
50689
+ Log$3.debug('Protocol V2 method retry completed', { method: method.name, success: true });
50690
+ return response;
50691
+ }
50692
+ catch (retryError) {
50693
+ Log$3.debug('Protocol V2 method retry completed', { method: method.name, success: false });
50694
+ throw retryError;
50695
+ }
50696
+ }
50697
+ });
50698
+ }
50699
+
50700
+ const Mainnet = 'mainnet';
50701
+ const networkAliases = {
50702
+ tbtc: { name: 'btc', coin: 'Testnet' },
50703
+ bch: { name: 'btc', coin: 'Bcash' },
50704
+ doge: { name: 'btc', coin: 'Dogecoin' },
50705
+ ltc: { name: 'btc', coin: 'Litecoin' },
50706
+ neurai: { name: 'btc', coin: 'Neurai' },
50707
+ };
50708
+ const networkConfigMap = {
50709
+ btc: {
50710
+ methodName: 'btcGetPublicKey',
50711
+ getParams: (baseParams, chainName) => (Object.assign({ coin: chainName }, baseParams)),
50712
+ },
50713
+ evm: {
50714
+ methodName: 'evmGetAddress',
50715
+ getParams: (baseParams, chainName) => {
50716
+ const { path, showOnOneKey } = baseParams;
50717
+ let chainId;
50718
+ if (chainName) {
50719
+ chainId = parseInt(chainName);
50720
+ }
50721
+ return {
50722
+ chainId,
50723
+ path,
50724
+ showOnOneKey,
50725
+ };
50726
+ },
50727
+ },
50728
+ sol: {
50729
+ methodName: 'solGetAddress',
50730
+ },
50731
+ algo: {
50732
+ methodName: 'algoGetAddress',
50733
+ },
50734
+ near: {
50735
+ methodName: 'nearGetAddress',
50736
+ },
50737
+ stc: {
50738
+ methodName: 'starcoinGetAddress',
50739
+ },
50740
+ cfx: {
50741
+ methodName: 'confluxGetAddress',
50742
+ getParams: (baseParams, chainName) => {
50743
+ const { path, showOnOneKey } = baseParams;
50744
+ return {
50745
+ chainId: parseInt(chainName !== null && chainName !== void 0 ? chainName : '1029'),
50746
+ path,
50747
+ showOnOneKey,
50748
+ };
50749
+ },
50750
+ },
50751
+ tron: {
50752
+ methodName: 'tronGetAddress',
50753
+ },
50754
+ aptos: {
50755
+ methodName: 'aptosGetAddress',
50756
+ },
50757
+ xrp: {
50758
+ methodName: 'xrpGetAddress',
50759
+ },
50760
+ cosmos: {
50761
+ methodName: 'cosmosGetPublicKey',
50762
+ getParams: (baseParams) => {
50763
+ const { path, prefix, showOnOneKey } = baseParams;
50764
+ return {
50765
+ hrp: prefix,
50766
+ path,
50767
+ showOnOneKey,
50768
+ };
50769
+ },
50770
+ },
50771
+ ada: {
50772
+ methodName: 'cardanoGetAddress',
50773
+ getParams: (baseParams, chainName) => {
50774
+ const { path, showOnOneKey } = baseParams;
50775
+ const addressPath = typeof path === 'string' ? `${path}/0/0` : serializedPath([...path, 0, 0]);
50776
+ const stakingPath = typeof path === 'string' ? `${path}/2/0` : serializedPath([...path, 2, 0]);
50777
+ let networkId = 1;
50778
+ if (chainName) {
50779
+ networkId = chainName === Mainnet ? 1 : 0;
50780
+ }
50781
+ return {
50782
+ addressParameters: {
50783
+ addressType: hdTransport.Messages.CardanoAddressType.BASE,
50784
+ path: addressPath,
50785
+ stakingPath,
50786
+ },
50787
+ protocolMagic: 764824073,
50788
+ networkId,
50302
50789
  derivationType: hdTransport.Messages.CardanoDerivationType.ICARUS,
50303
50790
  showOnOneKey,
50304
50791
  address: '',
@@ -50494,7 +50981,16 @@ class AllNetworkGetAddressBase extends BaseMethod {
50494
50981
  this.temporarySafetyCheckPrompted = true;
50495
50982
  }
50496
50983
  }
50497
- const response = yield method.run();
50984
+ if (this.device.isProtocolV2() && this.payload.passphraseState) {
50985
+ yield ensureProtocolV2WalletSessionUnlocked(this.device);
50986
+ const passphraseStateSafety = yield this.device.checkPassphraseStateSafety(this.payload.passphraseState, false, this.payload.skipPassphraseCheck);
50987
+ if (!passphraseStateSafety) {
50988
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
50989
+ }
50990
+ }
50991
+ const response = this.device.isProtocolV2()
50992
+ ? yield runMethodWithUnlockRetry(method, this.device)
50993
+ : yield method.run();
50498
50994
  if (!Array.isArray(response) || response.length === 0) {
50499
50995
  throw new Error('No response');
50500
50996
  }
@@ -50535,7 +51031,9 @@ class AllNetworkGetAddressBase extends BaseMethod {
50535
51031
  script_type: 'SPENDADDRESS',
50536
51032
  show_display: false,
50537
51033
  });
50538
- this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
51034
+ if (!this.device.isProtocolV2()) {
51035
+ this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
51036
+ }
50539
51037
  if (res.message.root_fingerprint == null) {
50540
51038
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter);
50541
51039
  }
@@ -59849,7 +60347,7 @@ const resolveAfter = (msec, value) => new Promise(resolve => {
59849
60347
  setTimeout(resolve, msec, value);
59850
60348
  });
59851
60349
 
59852
- const Log$3 = getLogger(exports.LoggerNames.DeviceConnector);
60350
+ const Log$2 = getLogger(exports.LoggerNames.DeviceConnector);
59853
60351
  class DeviceConnector {
59854
60352
  constructor() {
59855
60353
  this.listenTimestamp = 0;
@@ -59880,7 +60378,7 @@ class DeviceConnector {
59880
60378
  this.listening = true;
59881
60379
  let descriptors;
59882
60380
  try {
59883
- Log$3.debug('Start listening', current);
60381
+ Log$2.debug('Start listening', current);
59884
60382
  this.listenTimestamp = new Date().getTime();
59885
60383
  descriptors = waitForEvent
59886
60384
  ? yield this.transport.listen(current)
@@ -59888,21 +60386,21 @@ class DeviceConnector {
59888
60386
  if (!this.listening)
59889
60387
  return;
59890
60388
  this.upcoming = descriptors;
59891
- Log$3.debug('Listen result', descriptors);
60389
+ Log$2.debug('Listen result', descriptors);
59892
60390
  this._reportDevicesChange();
59893
60391
  if (this.listening)
59894
60392
  this.listen();
59895
60393
  }
59896
60394
  catch (error) {
59897
60395
  const time = new Date().getTime() - this.listenTimestamp;
59898
- Log$3.debug('Listen error', 'timestamp', time, typeof error);
60396
+ Log$2.debug('Listen error', 'timestamp', time, typeof error);
59899
60397
  if (time > 1100) {
59900
60398
  yield resolveAfter(1000, null);
59901
60399
  if (this.listening)
59902
60400
  this.listen();
59903
60401
  }
59904
60402
  else {
59905
- Log$3.warn('Transport error');
60403
+ Log$2.warn('Transport error');
59906
60404
  }
59907
60405
  }
59908
60406
  });
@@ -59912,7 +60410,7 @@ class DeviceConnector {
59912
60410
  }
59913
60411
  acquire(path, session, forceCleanRunPromise, expectedProtocol, protocolHint) {
59914
60412
  return __awaiter(this, void 0, void 0, function* () {
59915
- Log$3.debug('acquire', path, session, expectedProtocol, protocolHint);
60413
+ Log$2.debug('acquire', path, session, expectedProtocol, protocolHint);
59916
60414
  const env = DataManager.getSettings('env');
59917
60415
  try {
59918
60416
  let res;
@@ -59941,7 +60439,7 @@ class DeviceConnector {
59941
60439
  return res;
59942
60440
  }
59943
60441
  catch (error) {
59944
- Log$3.error('acquire error: ', error.message);
60442
+ Log$2.error('acquire error: ', error.message);
59945
60443
  safeThrowError(error);
59946
60444
  }
59947
60445
  });
@@ -59980,7 +60478,7 @@ class DeviceConnector {
59980
60478
  }
59981
60479
  }
59982
60480
 
59983
- const Log$2 = getLogger(exports.LoggerNames.Core);
60481
+ const Log$1 = getLogger(exports.LoggerNames.Core);
59984
60482
  class RequestQueue {
59985
60483
  constructor() {
59986
60484
  this.requestQueue = new Map();
@@ -60013,7 +60511,7 @@ class RequestQueue {
60013
60511
  abortRequest(requestId) {
60014
60512
  const request = this.requestQueue.get(requestId);
60015
60513
  if (request === null || request === void 0 ? void 0 : request.abortController) {
60016
- Log$2.debug(`Aborting request ${requestId}`);
60514
+ Log$1.debug(`Aborting request ${requestId}`);
60017
60515
  request.abortController.abort();
60018
60516
  return true;
60019
60517
  }
@@ -60065,7 +60563,7 @@ class RequestQueue {
60065
60563
  registerPendingCallbackTask(connectId, callbackPromise) {
60066
60564
  this.pendingCallbackTasks.set(connectId, callbackPromise);
60067
60565
  callbackPromise.promise.finally(() => {
60068
- Log$2.debug(`Callback task completed for connectId: ${connectId}`);
60566
+ Log$1.debug(`Callback task completed for connectId: ${connectId}`);
60069
60567
  if (this.pendingCallbackTasks.get(connectId) === callbackPromise) {
60070
60568
  this.pendingCallbackTasks.delete(connectId);
60071
60569
  }
@@ -60075,7 +60573,7 @@ class RequestQueue {
60075
60573
  return __awaiter(this, void 0, void 0, function* () {
60076
60574
  const pendingTask = this.pendingCallbackTasks.get(connectId);
60077
60575
  if (pendingTask && pendingTask !== exceptTask) {
60078
- Log$2.debug(`Waiting for pending callback task to complete for connectId: ${connectId}`);
60576
+ Log$1.debug(`Waiting for pending callback task to complete for connectId: ${connectId}`);
60079
60577
  yield pendingTask.promise;
60080
60578
  }
60081
60579
  });
@@ -60090,6 +60588,8 @@ class RequestQueue {
60090
60588
 
60091
60589
  function registerHardwareUiEventListeners(device, handlers) {
60092
60590
  device.on(DEVICE.PIN, handlers.pin);
60591
+ device.on(DEVICE.PIN_ON_DEVICE, handlers.pinOnDevice);
60592
+ device.on(DEVICE.PIN_ON_DEVICE_COMPLETE, handlers.pinOnDeviceComplete);
60093
60593
  device.on(DEVICE.BUTTON, handlers.button);
60094
60594
  device.on(DEVICE.PASSPHRASE, handlers.passphrase);
60095
60595
  device.on(DEVICE.PASSPHRASE_ON_DEVICE, handlers.passphraseOnDevice);
@@ -60119,208 +60619,6 @@ const getSynchronize = (mutex) => {
60119
60619
  return (action, lockId) => lock(lockId).then(unlock => Promise.resolve().then(action).finally(unlock));
60120
60620
  };
60121
60621
 
60122
- function isDeviceLockedError(error) {
60123
- return (typeof error === 'object' &&
60124
- error !== null &&
60125
- 'errorCode' in error &&
60126
- error.errorCode === hdShared.HardwareErrorCode.DeviceLocked);
60127
- }
60128
-
60129
- const isProtocolV2UiEnabled = (method) => method.protocolV2UiMode !== 'none';
60130
- const getDisplayState = (value) => {
60131
- const visited = new Set();
60132
- let seen = false;
60133
- let enabled = false;
60134
- const visit = (current) => {
60135
- if (current == null || typeof current !== 'object')
60136
- return;
60137
- if (visited.has(current))
60138
- return;
60139
- visited.add(current);
60140
- if (Array.isArray(current)) {
60141
- current.forEach(visit);
60142
- return;
60143
- }
60144
- Object.entries(current).forEach(([key, item]) => {
60145
- if ((key === 'show_display' || key === 'showOnOneKey') && typeof item === 'boolean') {
60146
- seen = true;
60147
- enabled || (enabled = item);
60148
- return;
60149
- }
60150
- visit(item);
60151
- });
60152
- };
60153
- visit(value);
60154
- return { seen, enabled };
60155
- };
60156
- const createMethodInteraction = (reason, operation) => ({
60157
- request: 'button',
60158
- source: 'method-lifecycle',
60159
- reason,
60160
- completion: 'operation-completed',
60161
- deviceOnly: true,
60162
- operation,
60163
- });
60164
- const hasCipherConfirmation = (value) => {
60165
- if (Array.isArray(value))
60166
- return value.some(hasCipherConfirmation);
60167
- if (value == null || typeof value !== 'object')
60168
- return false;
60169
- const params = value;
60170
- return params.encrypt === true ? params.ask_on_encrypt === true : params.ask_on_decrypt === true;
60171
- };
60172
- const resolveProtocolV2UiInteraction = (method) => {
60173
- if (method.protocolV2UiInteraction)
60174
- return method.protocolV2UiInteraction;
60175
- const operation = method.name;
60176
- if (!operation)
60177
- return undefined;
60178
- const isAddress = /getAddress(?:ByLoop)?$/i.test(operation);
60179
- const isPublicKey = /getPublicKey$/i.test(operation);
60180
- if (isAddress || isPublicKey) {
60181
- const paramsDisplay = getDisplayState(method.params);
60182
- const payloadDisplay = getDisplayState(method.payload);
60183
- const display = paramsDisplay.seen ? paramsDisplay : payloadDisplay;
60184
- const shouldDisplay = display.seen ? display.enabled : isAddress;
60185
- if (!shouldDisplay)
60186
- return undefined;
60187
- return createMethodInteraction(isAddress ? 'address-confirmation' : 'public-key-confirmation', operation);
60188
- }
60189
- if (/sign/i.test(operation) || /verifyMessage$/i.test(operation) || operation === 'lnurlAuth') {
60190
- return createMethodInteraction('signing-confirmation', operation);
60191
- }
60192
- if (operation === 'nostrEncryptMessage' || operation === 'nostrDecryptMessage') {
60193
- const display = getDisplayState(method.params);
60194
- if (!display.enabled)
60195
- return undefined;
60196
- return createMethodInteraction('signing-confirmation', operation);
60197
- }
60198
- if (operation === 'cipherKeyValue' && hasCipherConfirmation(method.params)) {
60199
- return createMethodInteraction('signing-confirmation', operation);
60200
- }
60201
- return undefined;
60202
- };
60203
- class ProtocolV2UiInteractionCoordinator {
60204
- constructor(device, postMessage) {
60205
- this.opened = false;
60206
- this.closed = false;
60207
- this.device = device;
60208
- this.postMessage = postMessage;
60209
- }
60210
- enterMethodInteraction(interaction) {
60211
- var _a, _b;
60212
- this.methodInteraction = interaction;
60213
- if (!interaction)
60214
- return;
60215
- const { request } = interaction, metadata = __rest(interaction, ["request"]);
60216
- this.emit(request === 'pin' ? UI_REQUEST.REQUEST_PIN : UI_REQUEST.REQUEST_BUTTON, Object.assign({ device: this.device.toMessageObject() }, metadata), `method:${request}:${interaction.reason}:${(_a = interaction.page) !== null && _a !== void 0 ? _a : ''}:${(_b = interaction.operation) !== null && _b !== void 0 ? _b : ''}`);
60217
- }
60218
- enterUnlockInteraction(method) {
60219
- this.emit(UI_REQUEST.REQUEST_PIN, {
60220
- device: this.device.toMessageObject(),
60221
- source: 'unlock-coordinator',
60222
- reason: 'device-locked',
60223
- deviceOnly: true,
60224
- method,
60225
- }, `unlock:${method !== null && method !== void 0 ? method : ''}`);
60226
- }
60227
- resumeMethodInteraction() {
60228
- this.enterMethodInteraction(this.methodInteraction);
60229
- }
60230
- close() {
60231
- if (!this.device.isProtocolV2() || !this.opened || this.closed)
60232
- return;
60233
- this.closed = true;
60234
- this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW));
60235
- }
60236
- emit(type, payload, phase) {
60237
- if (!this.device.isProtocolV2() || this.closed || this.currentPhase === phase)
60238
- return;
60239
- this.currentPhase = phase;
60240
- this.opened = true;
60241
- const message = type === UI_REQUEST.REQUEST_BUTTON
60242
- ? createUiMessage(UI_REQUEST.REQUEST_BUTTON, payload)
60243
- : createUiMessage(UI_REQUEST.REQUEST_PIN, payload);
60244
- this.postMessage(message);
60245
- }
60246
- }
60247
-
60248
- const Log$1 = getLogger(exports.LoggerNames.Core);
60249
- const restoreExpectedWalletSessionAfterUnlock = (method, device) => __awaiter(void 0, void 0, void 0, function* () {
60250
- var _a, _b, _c;
60251
- const expectedPassphraseState = ((_a = method.payload) === null || _a === void 0 ? void 0 : _a.useEmptyPassphrase)
60252
- ? undefined
60253
- : (_c = (_b = method.payload) === null || _b === void 0 ? void 0 : _b.passphraseState) !== null && _c !== void 0 ? _c : device.passphraseState;
60254
- if (!method.useDevicePassphraseState ||
60255
- typeof expectedPassphraseState !== 'string' ||
60256
- expectedPassphraseState.length === 0) {
60257
- return;
60258
- }
60259
- yield restoreProtocolV2WalletSession(device, expectedPassphraseState);
60260
- Log$1.debug('Protocol V2 wallet session restored after unlock', { method: method.name });
60261
- });
60262
- function runMethodWithUnlockRetry(method, device, uiCoordinator) {
60263
- var _a, _b, _c, _d, _e;
60264
- return __awaiter(this, void 0, void 0, function* () {
60265
- const shouldEmitUi = isProtocolV2UiEnabled(method);
60266
- const isProtocolV2 = device.isProtocolV2();
60267
- const requiresFreshStatus = isProtocolV2 &&
60268
- method.unlockPolicy === 'unlock-before-run' &&
60269
- !((_a = device.isBootloader) === null || _a === void 0 ? void 0 : _a.call(device)) &&
60270
- !((_b = device.isRomloader) === null || _b === void 0 ? void 0 : _b.call(device));
60271
- if (requiresFreshStatus) {
60272
- yield refreshProtocolV2DeviceStatus(device);
60273
- }
60274
- const shouldUnlockBeforeRun = isProtocolV2 &&
60275
- method.unlockPolicy !== 'none' &&
60276
- !((_c = device.isBootloader) === null || _c === void 0 ? void 0 : _c.call(device)) &&
60277
- !((_d = device.isRomloader) === null || _d === void 0 ? void 0 : _d.call(device)) &&
60278
- ((_e = device.features) === null || _e === void 0 ? void 0 : _e.unlocked) === false;
60279
- if (shouldUnlockBeforeRun) {
60280
- if (shouldEmitUi) {
60281
- uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterUnlockInteraction(method.name);
60282
- }
60283
- yield device.unlockDevice();
60284
- Log$1.debug('Protocol V2 pre-unlock completed', { method: method.name });
60285
- yield restoreExpectedWalletSessionAfterUnlock(method, device);
60286
- if (shouldEmitUi) {
60287
- uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
60288
- }
60289
- return method.run();
60290
- }
60291
- if (shouldEmitUi) {
60292
- uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
60293
- }
60294
- try {
60295
- return yield method.run();
60296
- }
60297
- catch (error) {
60298
- if (!isProtocolV2 || method.unlockPolicy !== 'retry-on-locked' || !isDeviceLockedError(error)) {
60299
- throw error;
60300
- }
60301
- Log$1.debug('Protocol V2 unlock retry triggered', { method: method.name });
60302
- if (shouldEmitUi) {
60303
- uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterUnlockInteraction(method.name);
60304
- }
60305
- yield device.unlockDevice();
60306
- Log$1.debug('Protocol V2 unlock completed', { method: method.name });
60307
- yield restoreExpectedWalletSessionAfterUnlock(method, device);
60308
- if (shouldEmitUi) {
60309
- uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.resumeMethodInteraction();
60310
- }
60311
- try {
60312
- const response = yield method.run();
60313
- Log$1.debug('Protocol V2 method retry completed', { method: method.name, success: true });
60314
- return response;
60315
- }
60316
- catch (retryError) {
60317
- Log$1.debug('Protocol V2 method retry completed', { method: method.name, success: false });
60318
- throw retryError;
60319
- }
60320
- }
60321
- });
60322
- }
60323
-
60324
60622
  const Log = getLogger(exports.LoggerNames.Core);
60325
60623
  const PRE_INITIALIZE_TTL_MS = 60 * 1000;
60326
60624
  const preWarmInflight = new Map();
@@ -60552,6 +60850,8 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
60552
60850
  }
60553
60851
  registerHardwareUiEventListeners(device, {
60554
60852
  pin: onDevicePinHandler,
60853
+ pinOnDevice: onEnterPinOnDeviceHandler,
60854
+ pinOnDeviceComplete: onPinOnDeviceCompleteHandler,
60555
60855
  button: onDeviceButtonHandler,
60556
60856
  passphrase: message.payload.useEmptyPassphrase
60557
60857
  ? onEmptyPassphraseHandler
@@ -60563,6 +60863,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
60563
60863
  device.on(DEVICE.STATE, onDeviceStateHandler);
60564
60864
  device.on(DEVICE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE, onSelectDeviceInBootloaderForWebDeviceHandler);
60565
60865
  const protocolV2UiCoordinator = new ProtocolV2UiInteractionCoordinator(device, postMessage);
60866
+ device.beginProtocolV2UiInteraction();
60566
60867
  device.on(DEVICE.SELECT_DEVICE_FOR_SWITCH_FIRMWARE_WEB_DEVICE, onSelectDeviceForSwitchFirmwareWebDeviceHandler);
60567
60868
  try {
60568
60869
  if (method.connectId) {
@@ -60658,13 +60959,16 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
60658
60959
  require: support.require,
60659
60960
  }));
60660
60961
  }
60661
- const passphraseStateSafety = yield device.checkPassphraseStateSafety((_l = method.payload) === null || _l === void 0 ? void 0 : _l.passphraseState, (_m = method.payload) === null || _m === void 0 ? void 0 : _m.useEmptyPassphrase, (_o = method.payload) === null || _o === void 0 ? void 0 : _o.skipPassphraseCheck);
60962
+ yield ensureProtocolV2WalletSessionUnlocked(device);
60963
+ const passphraseStateSafety = yield device.checkPassphraseStateSafety((_l = method.payload) === null || _l === void 0 ? void 0 : _l.passphraseState, (_m = method.payload) === null || _m === void 0 ? void 0 : _m.useEmptyPassphrase, (_o = method.payload) === null || _o === void 0 ? void 0 : _o.skipPassphraseCheck, hasDeriveCardano(method));
60662
60964
  checkPassphraseEnableState(method, device.features);
60663
60965
  if (!passphraseStateSafety) {
60664
60966
  DevicePool.clearDeviceCache(method.payload.connectId);
60665
60967
  return Promise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError));
60666
60968
  }
60667
- postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
60969
+ if (!device.isProtocolV2()) {
60970
+ postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
60971
+ }
60668
60972
  }
60669
60973
  try {
60670
60974
  yield method.checkSafetyLevelOnTestNet();
@@ -61173,15 +61477,7 @@ const onDeviceStateHandler = (...[_, stateEvent]) => {
61173
61477
  const onDevicePassphraseHandler = (...[device, requestPayload, callback]) => __awaiter(void 0, void 0, void 0, function* () {
61174
61478
  Log.debug('onDevicePassphraseHandler');
61175
61479
  const uiPromise = createUiPromise(UI_RESPONSE.RECEIVE_PASSPHRASE, device);
61176
- postMessage(createUiMessage(UI_REQUEST.REQUEST_PASSPHRASE, {
61177
- device: device.toMessageObject(),
61178
- passphraseState: device.passphraseState,
61179
- existsAttachPinUser: requestPayload.existsAttachPinUser,
61180
- deviceOnly: requestPayload.deviceOnly,
61181
- source: requestPayload.source,
61182
- reason: requestPayload.reason,
61183
- expectedPassphraseState: requestPayload.expectedPassphraseState,
61184
- }));
61480
+ postMessage(createUiMessage(UI_REQUEST.REQUEST_PASSPHRASE, Object.assign({ device: device.toMessageObject(), passphraseState: device.passphraseState, existsAttachPinUser: requestPayload.existsAttachPinUser, deviceOnly: requestPayload.deviceOnly, source: requestPayload.source, reason: requestPayload.reason, expectedPassphraseState: requestPayload.expectedPassphraseState }, (requestPayload.interaction ? { interaction: requestPayload.interaction } : {}))));
61185
61481
  const uiResp = yield uiPromise.promise;
61186
61482
  const { value, passphraseOnDevice, save, attachPinOnDevice } = uiResp.payload;
61187
61483
  callback({
@@ -61196,20 +61492,19 @@ const onEmptyPassphraseHandler = (...[_, , callback]) => {
61196
61492
  callback({ passphrase: '' });
61197
61493
  };
61198
61494
  const onEnterPassphraseOnDeviceHandler = (...[device, requestPayload]) => {
61199
- postMessage(createUiMessage(UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE, {
61200
- device: device.toMessageObject(),
61201
- passphraseState: device.passphraseState,
61202
- source: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.source,
61203
- reason: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.reason,
61204
- }));
61495
+ postMessage(createUiMessage(UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE, Object.assign({ device: device.toMessageObject(), passphraseState: device.passphraseState, source: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.source, reason: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.reason }, ((requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.interaction) ? { interaction: requestPayload.interaction } : {}))));
61205
61496
  };
61206
61497
  const onEnterAttachPinOnDeviceHandler = (...[device, requestPayload]) => {
61207
- postMessage(createUiMessage(UI_REQUEST.REQUEST_PIN, {
61208
- device: device.toMessageObject(),
61209
- type: 'ButtonRequest_AttachPin',
61210
- source: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.source,
61211
- reason: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.reason,
61212
- }));
61498
+ postMessage(createUiMessage(UI_REQUEST.REQUEST_PIN, Object.assign({ device: device.toMessageObject(), type: 'ButtonRequest_AttachPin', source: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.source, reason: requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.reason }, ((requestPayload === null || requestPayload === void 0 ? void 0 : requestPayload.interaction) ? { interaction: requestPayload.interaction } : {}))));
61499
+ };
61500
+ const onEnterPinOnDeviceHandler = (...[device, pinType, metadata]) => {
61501
+ var _a;
61502
+ postMessage(createUiMessage(UI_REQUEST.REQUEST_PIN, Object.assign({ device: device.toMessageObject(), type: pinType === hdTransport.DeviceSessionPinType.AttachToPin
61503
+ ? 'ButtonRequest_AttachPin'
61504
+ : 'ButtonRequest_PinEntry', source: metadata === null || metadata === void 0 ? void 0 : metadata.source, reason: metadata === null || metadata === void 0 ? void 0 : metadata.reason, deviceOnly: (_a = metadata === null || metadata === void 0 ? void 0 : metadata.deviceOnly) !== null && _a !== void 0 ? _a : true, completion: metadata === null || metadata === void 0 ? void 0 : metadata.completion, method: metadata === null || metadata === void 0 ? void 0 : metadata.method, page: metadata === null || metadata === void 0 ? void 0 : metadata.page, operation: metadata === null || metadata === void 0 ? void 0 : metadata.operation }, ((metadata === null || metadata === void 0 ? void 0 : metadata.interaction) ? { interaction: metadata.interaction } : {}))));
61505
+ };
61506
+ const onPinOnDeviceCompleteHandler = (...[_, metadata]) => {
61507
+ postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW, metadata));
61213
61508
  };
61214
61509
  const onSelectDeviceInBootloaderForWebDeviceHandler = (...[device, callback]) => __awaiter(void 0, void 0, void 0, function* () {
61215
61510
  Log.debug('onSelectDeviceInBootloaderForWebDeviceHandler');