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

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 (79) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +5 -1
  2. package/__tests__/deviceUploadNft.test.ts +187 -0
  3. package/__tests__/homescreen.test.ts +41 -1
  4. package/__tests__/logBlockEvent.test.ts +1 -1
  5. package/__tests__/open-wallet-session.test.ts +161 -44
  6. package/__tests__/pro2Nft.test.ts +108 -0
  7. package/__tests__/protocol-v2-unlock-policy.test.ts +86 -35
  8. package/__tests__/protocol-v2.test.ts +168 -444
  9. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  10. package/__tests__/uiProgressThrottle.test.ts +74 -0
  11. package/dist/api/BaseMethod.d.ts +3 -1
  12. package/dist/api/BaseMethod.d.ts.map +1 -1
  13. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  14. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  15. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -1
  16. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  17. package/dist/api/helpers/protocolV2FileWrite.d.ts +2 -0
  18. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  19. package/dist/api/index.d.ts +1 -0
  20. package/dist/api/index.d.ts.map +1 -1
  21. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +30 -0
  22. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/events/logBlockEvent.d.ts.map +1 -1
  25. package/dist/index.d.ts +34 -2
  26. package/dist/index.js +544 -496
  27. package/dist/inject.d.ts.map +1 -1
  28. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  29. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  30. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  31. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  32. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  33. package/dist/types/api/index.d.ts +2 -1
  34. package/dist/types/api/index.d.ts.map +1 -1
  35. package/dist/types/api/protocolV2.d.ts +3 -0
  36. package/dist/types/api/protocolV2.d.ts.map +1 -1
  37. package/dist/utils/homescreen.d.ts +4 -0
  38. package/dist/utils/homescreen.d.ts.map +1 -1
  39. package/dist/utils/index.d.ts +1 -1
  40. package/dist/utils/index.d.ts.map +1 -1
  41. package/dist/utils/patch.d.ts +1 -1
  42. package/dist/utils/patch.d.ts.map +1 -1
  43. package/dist/utils/pro2Nft.d.ts +29 -0
  44. package/dist/utils/pro2Nft.d.ts.map +1 -0
  45. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  46. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  47. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  48. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  49. package/package.json +4 -4
  50. package/src/api/BaseMethod.ts +7 -9
  51. package/src/api/OpenWalletSession.ts +37 -15
  52. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +29 -30
  53. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -7
  54. package/src/api/helpers/protocolV2FileWrite.ts +11 -4
  55. package/src/api/index.ts +1 -0
  56. package/src/api/protocol-v2/DeviceUploadNft.ts +166 -0
  57. package/src/core/index.ts +83 -82
  58. package/src/data/messages/messages-protocol-v2.json +10 -15
  59. package/src/events/logBlockEvent.ts +1 -0
  60. package/src/inject.ts +1 -0
  61. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  62. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +117 -0
  63. package/src/protocols/protocol-v2/walletSession.ts +18 -51
  64. package/src/types/api/index.ts +2 -0
  65. package/src/types/api/protocolV2.ts +13 -0
  66. package/src/utils/homescreen.ts +32 -6
  67. package/src/utils/index.ts +6 -1
  68. package/src/utils/pro2Nft.ts +91 -0
  69. package/src/utils/pro2Wallpaper.ts +35 -8
  70. package/src/utils/uiProgressThrottle.ts +63 -0
  71. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  72. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  73. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  74. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  75. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  76. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  77. package/src/api/firmware/progressThrottle.ts +0 -44
  78. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  79. package/src/protocols/protocol-v2/unlockRetry.ts +0 -131
package/dist/index.js CHANGED
@@ -8,9 +8,9 @@ var hdShared = require('@onekeyfe/hd-shared');
8
8
  var axios = require('axios');
9
9
  var lodash = require('lodash');
10
10
  var ByteBuffer = require('bytebuffer');
11
- var BigNumber = require('bignumber.js');
12
- var utils = require('@noble/hashes/utils');
13
11
  var blake2s = require('@noble/hashes/blake2s');
12
+ var utils = require('@noble/hashes/utils');
13
+ var BigNumber = require('bignumber.js');
14
14
  var sha256 = require('@noble/hashes/sha256');
15
15
  var JSZip = require('jszip');
16
16
  var sha3 = require('@noble/hashes/sha3');
@@ -146,6 +146,7 @@ const createCoreApi = (call) => ({
146
146
  deviceReboot: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'deviceReboot' })),
147
147
  deviceGetOnboardingStatus: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'deviceGetOnboardingStatus' })),
148
148
  deviceUploadWallpaper: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'deviceUploadWallpaper' })),
149
+ deviceUploadNft: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'deviceUploadNft' })),
149
150
  uploadPortfolio: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'uploadPortfolio' })),
150
151
  deviceRecovery: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'deviceRecovery' })),
151
152
  deviceReset: (connectId, params) => call(Object.assign(Object.assign({}, params), { connectId, method: 'deviceReset' })),
@@ -26271,6 +26272,7 @@ var nested = {
26271
26272
  MessageType_DeviceSessionAskPin: 61202,
26272
26273
  MessageType_DeviceSessionAskPassphrase: 61203,
26273
26274
  MessageType_PortfolioUpdate: 61400,
26275
+ MessageType_NftUpdate: 61500,
26274
26276
  MessageType_OnboardingStatusGet: 61600,
26275
26277
  MessageType_OnboardingStatus: 61601
26276
26278
  },
@@ -38049,26 +38051,11 @@ var nested = {
38049
38051
  DeviceSessionError_Busy: 5
38050
38052
  }
38051
38053
  },
38052
- DeviceSessionSeedDomain: {
38053
- values: {
38054
- SeedDomain_Standard: 1,
38055
- SeedDomain_Cardano: 2
38056
- }
38057
- },
38058
38054
  DeviceSessionGet: {
38059
38055
  fields: {
38060
38056
  session_id: {
38061
38057
  type: "bytes",
38062
38058
  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
38072
38059
  }
38073
38060
  }
38074
38061
  },
@@ -38404,6 +38391,15 @@ var nested = {
38404
38391
  }
38405
38392
  }
38406
38393
  },
38394
+ NftUpdate: {
38395
+ fields: {
38396
+ file_name_no_ext: {
38397
+ rule: "required",
38398
+ type: "string",
38399
+ id: 1
38400
+ }
38401
+ }
38402
+ },
38407
38403
  OnboardingStep: {
38408
38404
  values: {
38409
38405
  ONBOARDING_STEP_UNKNOWN: 0,
@@ -39982,6 +39978,7 @@ const LogBlockEvent = new Set([
39982
39978
  ]);
39983
39979
  const LogLabelMethod = new Set([
39984
39980
  'openWalletSession',
39981
+ 'deviceUploadNft',
39985
39982
  'deviceUploadWallpaper',
39986
39983
  'uploadPortfolio',
39987
39984
  'fileWrite',
@@ -40103,41 +40100,15 @@ function refreshProtocolV2DeviceStatus(device) {
40103
40100
  return device.updateProtocolV2Status(status);
40104
40101
  });
40105
40102
  }
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;
40122
- });
40123
- }
40124
40103
  const negotiateEventlessWalletSession = (device) => __awaiter(void 0, void 0, void 0, function* () {
40125
40104
  yield device.ensureProtocolV2RuntimeContext();
40126
40105
  });
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);
40135
- });
40106
+ const getDeviceSession = (device, request) => __awaiter(void 0, void 0, void 0, function* () { return device.commands.typedCall('DeviceSessionGet', 'DeviceSession', request); });
40136
40107
  const askDevicePassphrase = (device, requestPayload) => __awaiter(void 0, void 0, void 0, function* () {
40137
40108
  yield device.commands.typedCall('DeviceSessionAskPassphrase', 'Success', requestPayload);
40138
40109
  yield refreshProtocolV2DeviceStatus(device);
40139
40110
  });
40140
- const selectDeviceSession = (device, expectedPassphraseState, deriveCardano) => __awaiter(void 0, void 0, void 0, function* () {
40111
+ const selectDeviceSession = (device, expectedPassphraseState) => __awaiter(void 0, void 0, void 0, function* () {
40141
40112
  var _a, _b, _c;
40142
40113
  const existsAttachPinUser = ((_a = device.features) === null || _a === void 0 ? void 0 : _a.attachToPinEnabled) === true;
40143
40114
  const metadata = Object.assign({ source: 'wallet-session-coordinator', reason: expectedPassphraseState ? 'session-recovery' : 'open-wallet' }, (expectedPassphraseState ? { expectedPassphraseState } : {}));
@@ -40170,18 +40141,18 @@ const selectDeviceSession = (device, expectedPassphraseState, deriveCardano) =>
40170
40141
  emitUiEvent: false,
40171
40142
  interaction: attachPinInteraction,
40172
40143
  });
40173
- return getDeviceSession(device, {}, deriveCardano);
40144
+ return getDeviceSession(device, {});
40174
40145
  }
40175
40146
  if (hasHostPassphrase) {
40176
40147
  yield askDevicePassphrase(device, {
40177
40148
  passphrase: hostPassphrase,
40178
40149
  on_device: false,
40179
40150
  });
40180
- return getDeviceSession(device, {}, deriveCardano);
40151
+ return getDeviceSession(device, {});
40181
40152
  }
40182
40153
  device.emit(DEVICE.PASSPHRASE_ON_DEVICE, device, Object.assign(Object.assign({}, metadata), (passphraseInteraction ? { interaction: passphraseInteraction } : {})));
40183
40154
  yield askDevicePassphrase(device, { on_device: true });
40184
- return getDeviceSession(device, {}, deriveCardano);
40155
+ return getDeviceSession(device, {});
40185
40156
  });
40186
40157
  function getProtocolV2WalletSession(device, options) {
40187
40158
  var _a, _b, _c, _d, _e, _f, _g;
@@ -40253,8 +40224,7 @@ function getProtocolV2WalletSession(device, options) {
40253
40224
  }
40254
40225
  response = yield getDeviceSession(device, {
40255
40226
  session_id: cachedStandardSession.sessionId,
40256
- btc_test_address: cachedStandardSession.passphraseState,
40257
- }, options === null || options === void 0 ? void 0 : options.deriveCardano);
40227
+ });
40258
40228
  resumed = true;
40259
40229
  }
40260
40230
  catch (error) {
@@ -40267,15 +40237,14 @@ function getProtocolV2WalletSession(device, options) {
40267
40237
  }
40268
40238
  if (!response) {
40269
40239
  yield selectMainWallet();
40270
- response = yield getDeviceSession(device, {}, options === null || options === void 0 ? void 0 : options.deriveCardano);
40240
+ response = yield getDeviceSession(device, {});
40271
40241
  }
40272
40242
  }
40273
40243
  else if (cachedSessionId && expectedPassphraseState) {
40274
40244
  try {
40275
40245
  response = yield getDeviceSession(device, {
40276
40246
  session_id: cachedSessionId,
40277
- btc_test_address: expectedPassphraseState,
40278
- }, options === null || options === void 0 ? void 0 : options.deriveCardano);
40247
+ });
40279
40248
  resumed = true;
40280
40249
  }
40281
40250
  catch (error) {
@@ -40288,7 +40257,7 @@ function getProtocolV2WalletSession(device, options) {
40288
40257
  }
40289
40258
  else if (expectedPassphraseState) {
40290
40259
  try {
40291
- response = yield getDeviceSession(device, { btc_test_address: expectedPassphraseState }, options === null || options === void 0 ? void 0 : options.deriveCardano);
40260
+ response = yield getDeviceSession(device, {});
40292
40261
  }
40293
40262
  catch (error) {
40294
40263
  if ((options === null || options === void 0 ? void 0 : options.resumeOnly) || !isWalletSessionInvalidError(error)) {
@@ -40301,7 +40270,7 @@ function getProtocolV2WalletSession(device, options) {
40301
40270
  device.clearInternalState();
40302
40271
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WalletSessionInvalid);
40303
40272
  }
40304
- response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano);
40273
+ response = yield selectDeviceSession(device, expectedPassphraseState);
40305
40274
  }
40306
40275
  let { message } = response;
40307
40276
  try {
@@ -40326,11 +40295,11 @@ function getProtocolV2WalletSession(device, options) {
40326
40295
  if (options === null || options === void 0 ? void 0 : options.onlyMainPin) {
40327
40296
  (_f = device.clearStandardInternalState) === null || _f === void 0 ? void 0 : _f.call(device);
40328
40297
  yield selectMainWallet(true);
40329
- response = yield getDeviceSession(device, {}, options === null || options === void 0 ? void 0 : options.deriveCardano);
40298
+ response = yield getDeviceSession(device, {});
40330
40299
  }
40331
40300
  else {
40332
40301
  device.clearInternalState();
40333
- response = yield selectDeviceSession(device, expectedPassphraseState, options === null || options === void 0 ? void 0 : options.deriveCardano);
40302
+ response = yield selectDeviceSession(device, expectedPassphraseState);
40334
40303
  }
40335
40304
  message = response.message;
40336
40305
  try {
@@ -40372,15 +40341,6 @@ function getProtocolV2WalletSession(device, options) {
40372
40341
  };
40373
40342
  });
40374
40343
  }
40375
- function restoreProtocolV2WalletSession(device, expectedPassphraseState, deriveCardano) {
40376
- return __awaiter(this, void 0, void 0, function* () {
40377
- return getProtocolV2WalletSession(device, {
40378
- expectedPassphraseState,
40379
- resumeOnly: true,
40380
- deriveCardano,
40381
- });
40382
- });
40383
- }
40384
40344
 
40385
40345
  const getSupportProtocolV1MessageSchema = (features) => {
40386
40346
  var _a;
@@ -40980,7 +40940,8 @@ function asBytes(rgba) {
40980
40940
  function align(value, boundary) {
40981
40941
  return Math.ceil(value / boundary) * boundary;
40982
40942
  }
40983
- function encodePro2Wallpaper(options) {
40943
+ function encodePro2Image(options) {
40944
+ var _a;
40984
40945
  const { width, height } = options;
40985
40946
  if (!Number.isInteger(width) || width <= 0 || width > 0xffff) {
40986
40947
  throw invalidParameter$2('Wallpaper width must be an integer between 1 and 65535.');
@@ -40993,11 +40954,14 @@ function encodePro2Wallpaper(options) {
40993
40954
  if (rgba.byteLength !== expectedLength) {
40994
40955
  throw invalidParameter$2(`Wallpaper RGBA data length must be ${expectedLength} bytes, received ${rgba.byteLength}.`);
40995
40956
  }
40957
+ const alphaMode = (_a = options.alphaMode) !== null && _a !== void 0 ? _a : 'preserve';
40996
40958
  let hasTransparency = false;
40997
- for (let index = 3; index < rgba.length; index += 4) {
40998
- if (rgba[index] !== 0xff) {
40999
- hasTransparency = true;
41000
- break;
40959
+ if (alphaMode === 'preserve') {
40960
+ for (let index = 3; index < rgba.length; index += 4) {
40961
+ if (rgba[index] !== 0xff) {
40962
+ hasTransparency = true;
40963
+ break;
40964
+ }
41001
40965
  }
41002
40966
  }
41003
40967
  const colorFormat = hasTransparency ? 'RGB565A8' : 'RGB565';
@@ -41018,9 +40982,19 @@ function encodePro2Wallpaper(options) {
41018
40982
  for (let x = 0; x < width; x += 1) {
41019
40983
  const sourceOffset = (y * width + x) * 4;
41020
40984
  const thresholdIndex = ((y & 7) << 3) + (x & 7);
41021
- const red = Math.min(rgba[sourceOffset] + RED_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
41022
- const green = Math.min(rgba[sourceOffset + 1] + GREEN_THRESHOLD[thresholdIndex], 0xff) & 0xfc;
41023
- const blue = Math.min(rgba[sourceOffset + 2] + BLUE_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
40985
+ const alpha = rgba[sourceOffset + 3];
40986
+ const redChannel = alphaMode === 'black-background'
40987
+ ? Math.round((rgba[sourceOffset] * alpha) / 0xff)
40988
+ : rgba[sourceOffset];
40989
+ const greenChannel = alphaMode === 'black-background'
40990
+ ? Math.round((rgba[sourceOffset + 1] * alpha) / 0xff)
40991
+ : rgba[sourceOffset + 1];
40992
+ const blueChannel = alphaMode === 'black-background'
40993
+ ? Math.round((rgba[sourceOffset + 2] * alpha) / 0xff)
40994
+ : rgba[sourceOffset + 2];
40995
+ const red = Math.min(redChannel + RED_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
40996
+ const green = Math.min(greenChannel + GREEN_THRESHOLD[thresholdIndex], 0xff) & 0xfc;
40997
+ const blue = Math.min(blueChannel + BLUE_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
41024
40998
  const rgb565 = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
41025
40999
  const rgbOffset = 12 + y * stride + x * 2;
41026
41000
  data[rgbOffset] = rgb565 & 0xff;
@@ -41032,6 +41006,148 @@ function encodePro2Wallpaper(options) {
41032
41006
  }
41033
41007
  return { data, colorFormat };
41034
41008
  }
41009
+ function encodePro2Wallpaper(options) {
41010
+ return encodePro2Image(options);
41011
+ }
41012
+
41013
+ const invalidParameter$1 = (message) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, message);
41014
+ function validateNonEmptyString(value, name) {
41015
+ if (typeof value !== 'string' || value.trim().length === 0) {
41016
+ throw invalidParameter$1(`Parameter [${name}] is required and must be a non-empty string.`);
41017
+ }
41018
+ return value;
41019
+ }
41020
+ const PROTOCOL_V2_FILESYSTEM_VOLUMES = new Set(['vol0', 'vol1']);
41021
+ const MAX_PROTOCOL_V2_FILESYSTEM_PATH_BYTES = 127;
41022
+ function getUtf8ByteLength$1(value) {
41023
+ return Array.from(value).reduce((length, character) => {
41024
+ var _a;
41025
+ const codePoint = (_a = character.codePointAt(0)) !== null && _a !== void 0 ? _a : 0;
41026
+ if (codePoint <= 0x7f)
41027
+ return length + 1;
41028
+ if (codePoint <= 0x7ff)
41029
+ return length + 2;
41030
+ if (codePoint <= 0xffff)
41031
+ return length + 3;
41032
+ return length + 4;
41033
+ }, 0);
41034
+ }
41035
+ function validateProtocolV2FilesystemPath(value, name, options = {}) {
41036
+ const rawPath = validateNonEmptyString(value, name).trim();
41037
+ const containsUnsupportedCharacter = Array.from(rawPath).some(character => {
41038
+ const codePoint = character.charCodeAt(0);
41039
+ return codePoint <= 0x1f || codePoint === 0x7f || character === '\\';
41040
+ });
41041
+ if (containsUnsupportedCharacter) {
41042
+ throw invalidParameter$1(`Parameter [${name}] contains unsupported path characters.`);
41043
+ }
41044
+ const match = /^([a-zA-Z0-9]+):(.*)$/.exec(rawPath);
41045
+ if (!match) {
41046
+ throw invalidParameter$1(`Parameter [${name}] must use a supported Protocol V2 filesystem volume.`);
41047
+ }
41048
+ const volume = match[1].toLowerCase();
41049
+ if (!PROTOCOL_V2_FILESYSTEM_VOLUMES.has(volume)) {
41050
+ throw invalidParameter$1(`Parameter [${name}] uses an unsupported filesystem volume.`);
41051
+ }
41052
+ const rawSuffix = match[2];
41053
+ if (rawSuffix.length === 0) {
41054
+ if (options.allowVolumeRoot)
41055
+ return `${volume}:`;
41056
+ throw invalidParameter$1(`Parameter [${name}] must identify a filesystem entry.`);
41057
+ }
41058
+ const suffix = rawSuffix.startsWith('/') ? rawSuffix : `/${rawSuffix}`;
41059
+ const segments = suffix.slice(1).split('/');
41060
+ if (segments.some(segment => segment.length === 0 || segment === '.' || segment === '..')) {
41061
+ throw invalidParameter$1(`Parameter [${name}] contains an invalid path segment.`);
41062
+ }
41063
+ const canonicalPath = `${volume}:${rawSuffix.startsWith('/') ? '/' : ''}${segments.join('/')}`;
41064
+ if (getUtf8ByteLength$1(canonicalPath) > MAX_PROTOCOL_V2_FILESYSTEM_PATH_BYTES) {
41065
+ throw invalidParameter$1(`Parameter [${name}] exceeds the maximum filesystem path length.`);
41066
+ }
41067
+ return canonicalPath;
41068
+ }
41069
+ function validateNonNegativeInteger(value, name, defaultValue) {
41070
+ if (value === undefined || value === null) {
41071
+ if (defaultValue !== undefined)
41072
+ return defaultValue;
41073
+ throw invalidParameter$1(`Missing required parameter: ${name}`);
41074
+ }
41075
+ const numeric = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;
41076
+ if (typeof numeric !== 'number' || !Number.isSafeInteger(numeric) || numeric < 0) {
41077
+ throw invalidParameter$1(`Parameter [${name}] must be a non-negative integer.`);
41078
+ }
41079
+ return numeric;
41080
+ }
41081
+ function validateOptionalNonNegativeInteger(value, name) {
41082
+ if (value === undefined || value === null)
41083
+ return undefined;
41084
+ return validateNonNegativeInteger(value, name);
41085
+ }
41086
+ function validateOptionalPercentage(value, name) {
41087
+ const numeric = validateOptionalNonNegativeInteger(value, name);
41088
+ if (numeric === undefined)
41089
+ return undefined;
41090
+ if (numeric > 100) {
41091
+ throw invalidParameter$1(`Parameter [${name}] must be between 0 and 100.`);
41092
+ }
41093
+ return numeric;
41094
+ }
41095
+ function validateRequiredData(value, name) {
41096
+ if (value === undefined || value === null) {
41097
+ throw invalidParameter$1(`Missing required parameter: ${name}`);
41098
+ }
41099
+ }
41100
+
41101
+ const PRO2_NFT_IMAGE_WIDTH = 540;
41102
+ const PRO2_NFT_IMAGE_HEIGHT = 540;
41103
+ const PRO2_NFT_THUMBNAIL_WIDTH = 263;
41104
+ const PRO2_NFT_THUMBNAIL_HEIGHT = 263;
41105
+ const PRO2_NFT_DIRECTORY = 'vol1:/nft';
41106
+ const PRO2_NFT_DEFAULT_CHUNK_SIZE = 512;
41107
+ const PRO2_NFT_DEFAULT_PACE_MS = 20;
41108
+ const PRO2_NFT_DEFAULT_TIMEOUT_MS = 15000;
41109
+ const PRO2_NFT_MIN_CHUNK_SIZE = 64;
41110
+ const PRO2_NFT_MAX_CHUNK_SIZE = 2048;
41111
+ function utf8Length(value) {
41112
+ return new TextEncoder().encode(value).byteLength;
41113
+ }
41114
+ function assertImage(name, image, expectedWidth, expectedHeight) {
41115
+ if (image.width !== expectedWidth || image.height !== expectedHeight) {
41116
+ throw invalidParameter$1(`Pro2 NFT ${name} dimensions must be ${expectedWidth}x${expectedHeight}.`);
41117
+ }
41118
+ if (!(image.rgba instanceof ArrayBuffer) && !ArrayBuffer.isView(image.rgba)) {
41119
+ throw invalidParameter$1(`Parameter [${name}.rgba] must be an ArrayBuffer or Uint8Array.`);
41120
+ }
41121
+ }
41122
+ function buildPro2NftBundle(options) {
41123
+ const { image, thumbnail, title, subtitle, timestampMs } = options;
41124
+ assertImage('image', image, PRO2_NFT_IMAGE_WIDTH, PRO2_NFT_IMAGE_HEIGHT);
41125
+ assertImage('thumbnail', thumbnail, PRO2_NFT_THUMBNAIL_WIDTH, PRO2_NFT_THUMBNAIL_HEIGHT);
41126
+ const titleLength = typeof title === 'string' ? utf8Length(title) : 0;
41127
+ const subtitleLength = typeof subtitle === 'string' ? utf8Length(subtitle) : Number.POSITIVE_INFINITY;
41128
+ if (titleLength < 1 || titleLength > 63) {
41129
+ throw invalidParameter$1('Pro2 NFT title must contain 1 to 63 UTF-8 bytes.');
41130
+ }
41131
+ if (subtitleLength > 95) {
41132
+ throw invalidParameter$1('Pro2 NFT subtitle must contain at most 95 UTF-8 bytes.');
41133
+ }
41134
+ if (!Number.isSafeInteger(timestampMs) || timestampMs <= 0) {
41135
+ throw invalidParameter$1('Parameter [timestampMs] must be a positive safe integer.');
41136
+ }
41137
+ const encodedImage = encodePro2Image(Object.assign(Object.assign({}, image), { alphaMode: 'black-background' })).data;
41138
+ const encodedThumbnail = encodePro2Image(Object.assign(Object.assign({}, thumbnail), { alphaMode: 'black-background' })).data;
41139
+ const metadata = new TextEncoder().encode(JSON.stringify({ title, subtitle }));
41140
+ if (metadata.byteLength === 0 || metadata.byteLength > 512) {
41141
+ throw invalidParameter$1('Pro2 NFT metadata must contain 1 to 512 UTF-8 bytes.');
41142
+ }
41143
+ const hash8 = utils.bytesToHex(blake2s.blake2s(encodedImage)).slice(0, 8);
41144
+ return {
41145
+ basename: `nft-${hash8}-${timestampMs}`,
41146
+ image: encodedImage,
41147
+ thumbnail: encodedThumbnail,
41148
+ metadata,
41149
+ };
41150
+ }
41035
41151
 
41036
41152
  const getT1Data = () => ({
41037
41153
  default: {
@@ -41315,14 +41431,27 @@ const getHomeScreenDefaultList = (features) => {
41315
41431
  }
41316
41432
  return Object.keys(data);
41317
41433
  };
41434
+ const getNftSize = ({ deviceType, thumbnail, }) => {
41435
+ var _a;
41436
+ const sizes = {
41437
+ touch: {
41438
+ full: { width: 480, height: 800 },
41439
+ thumbnail: { width: 238, height: 238 },
41440
+ },
41441
+ pro: {
41442
+ full: { width: 480, height: 800 },
41443
+ thumbnail: { width: 226, height: 226, radius: 40 },
41444
+ },
41445
+ pro2: {
41446
+ full: { width: PRO2_NFT_IMAGE_WIDTH, height: PRO2_NFT_IMAGE_HEIGHT },
41447
+ thumbnail: { width: PRO2_NFT_THUMBNAIL_WIDTH, height: PRO2_NFT_THUMBNAIL_HEIGHT },
41448
+ },
41449
+ };
41450
+ return (_a = sizes[deviceType]) === null || _a === void 0 ? void 0 : _a[thumbnail ? 'thumbnail' : 'full'];
41451
+ };
41318
41452
  const getHomeScreenSize = ({ deviceType, homeScreenType, thumbnail, }) => {
41319
41453
  if (deviceType === hdShared.EDeviceType.Pro2) {
41320
- return thumbnail
41321
- ? undefined
41322
- : {
41323
- width: PRO2_WALLPAPER_WIDTH,
41324
- height: PRO2_WALLPAPER_HEIGHT,
41325
- };
41454
+ return thumbnail ? undefined : { width: PRO2_WALLPAPER_WIDTH, height: PRO2_WALLPAPER_HEIGHT };
41326
41455
  }
41327
41456
  const sizes = {
41328
41457
  touch: {
@@ -44537,101 +44666,6 @@ const getBootloaderReleaseInfo = ({ features, willUpdateFirmwareVersion, firmwar
44537
44666
  };
44538
44667
  };
44539
44668
 
44540
- const PROTOCOL_V2_RETRY_ON_LOCKED_METHODS = [
44541
- 'cipherKeyValue',
44542
- 'allNetworkGetAddress',
44543
- 'allNetworkGetAddressByLoop',
44544
- 'btcGetAddress',
44545
- 'btcGetPublicKey',
44546
- 'btcSignMessage',
44547
- 'btcSignPsbt',
44548
- 'btcSignTransaction',
44549
- 'btcVerifyMessage',
44550
- 'confluxGetAddress',
44551
- 'confluxSignMessage',
44552
- 'confluxSignTransaction',
44553
- 'evmGetAddress',
44554
- 'evmGetPublicKey',
44555
- 'evmSignMessage',
44556
- 'evmSignTransaction',
44557
- 'evmSignTypedData',
44558
- 'evmVerifyMessage',
44559
- 'starcoinGetAddress',
44560
- 'starcoinGetPublicKey',
44561
- 'starcoinSignMessage',
44562
- 'starcoinSignTransaction',
44563
- 'starcoinVerifyMessage',
44564
- 'nemGetAddress',
44565
- 'nemSignTransaction',
44566
- 'solGetAddress',
44567
- 'solSignTransaction',
44568
- 'solSignOffchainMessage',
44569
- 'solSignMessage',
44570
- 'stellarGetAddress',
44571
- 'stellarSignTransaction',
44572
- 'tronGetAddress',
44573
- 'tronSignMessage',
44574
- 'tronSignTransaction',
44575
- 'nearGetAddress',
44576
- 'nearSignTransaction',
44577
- 'aptosGetAddress',
44578
- 'aptosGetPublicKey',
44579
- 'aptosSignTransaction',
44580
- 'aptosSignMessage',
44581
- 'aptosSignInMessage',
44582
- 'algoGetAddress',
44583
- 'algoSignTransaction',
44584
- 'cosmosGetAddress',
44585
- 'cosmosGetPublicKey',
44586
- 'cosmosSignTransaction',
44587
- 'xrpGetAddress',
44588
- 'xrpSignTransaction',
44589
- 'suiGetAddress',
44590
- 'suiGetPublicKey',
44591
- 'suiSignMessage',
44592
- 'suiSignTransaction',
44593
- 'cardanoGetAddress',
44594
- 'cardanoGetPublicKey',
44595
- 'cardanoSignTransaction',
44596
- 'cardanoSignMessage',
44597
- 'filecoinGetAddress',
44598
- 'filecoinSignTransaction',
44599
- 'polkadotGetAddress',
44600
- 'polkadotSignTransaction',
44601
- 'kaspaGetAddress',
44602
- 'kaspaSignTransaction',
44603
- 'nexaGetAddress',
44604
- 'nexaSignTransaction',
44605
- 'nostrGetPublicKey',
44606
- 'nostrSignEvent',
44607
- 'nostrEncryptMessage',
44608
- 'nostrDecryptMessage',
44609
- 'nostrSignSchnorr',
44610
- 'lnurlAuth',
44611
- 'nervosGetAddress',
44612
- 'nervosSignTransaction',
44613
- 'dnxGetAddress',
44614
- 'dnxSignTransaction',
44615
- 'tonGetAddress',
44616
- 'tonSignMessage',
44617
- 'tonSignProof',
44618
- 'tonSignData',
44619
- 'scdoGetAddress',
44620
- 'scdoSignTransaction',
44621
- 'scdoSignMessage',
44622
- 'alephiumGetAddress',
44623
- 'alephiumSignTransaction',
44624
- 'alephiumSignMessage',
44625
- 'benfenGetAddress',
44626
- 'benfenGetPublicKey',
44627
- 'benfenSignMessage',
44628
- 'benfenSignTransaction',
44629
- 'neoGetAddress',
44630
- 'neoSignTransaction',
44631
- ];
44632
- const retryOnLockedMethods = new Set(PROTOCOL_V2_RETRY_ON_LOCKED_METHODS);
44633
- const getProtocolV2UnlockPolicy = (methodName) => retryOnLockedMethods.has(methodName) ? 'retry-on-locked' : 'none';
44634
-
44635
44669
  const Log$d = getLogger(exports.LoggerNames.Method);
44636
44670
  const isEvmLedgerLegacyPathWithHighIndex = (path) => {
44637
44671
  let addressN;
@@ -44709,7 +44743,6 @@ class BaseMethod {
44709
44743
  this.useDevice = true;
44710
44744
  this.allowDeviceMode = [UI_REQUEST.NOT_INITIALIZE];
44711
44745
  this.requireDeviceMode = [];
44712
- this.unlockPolicy = getProtocolV2UnlockPolicy(this.name);
44713
44746
  }
44714
44747
  getVersionRange() {
44715
44748
  return {};
@@ -44847,7 +44880,7 @@ class TestInitializeDeviceDuration extends BaseMethod {
44847
44880
  }
44848
44881
 
44849
44882
  const PROTOCOL_V2_PING_MAX_MESSAGE_BYTES = 63;
44850
- const getUtf8ByteLength$1 = (value) => Array.from(value).reduce((length, character) => {
44883
+ const getUtf8ByteLength = (value) => Array.from(value).reduce((length, character) => {
44851
44884
  var _a;
44852
44885
  const codePoint = (_a = character.codePointAt(0)) !== null && _a !== void 0 ? _a : 0;
44853
44886
  if (codePoint <= 0x7f)
@@ -44863,7 +44896,7 @@ function validateProtocolV2PingMessage(value) {
44863
44896
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 Ping message must be a string.');
44864
44897
  }
44865
44898
  const message = value !== null && value !== void 0 ? value : '';
44866
- if (getUtf8ByteLength$1(message) > PROTOCOL_V2_PING_MAX_MESSAGE_BYTES) {
44899
+ if (getUtf8ByteLength(message) > PROTOCOL_V2_PING_MAX_MESSAGE_BYTES) {
44867
44900
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, `Protocol V2 Ping message must not exceed ${PROTOCOL_V2_PING_MAX_MESSAGE_BYTES} UTF-8 bytes.`);
44868
44901
  }
44869
44902
  return message;
@@ -45183,37 +45216,37 @@ function parseChainId(chainId) {
45183
45216
  throw new Error(`Invalid chainId ${chainId}`);
45184
45217
  }
45185
45218
 
45186
- const invalidParameter$1 = (message) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, message);
45219
+ const invalidParameter = (message) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, message);
45187
45220
  const invalidResponse = (message) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodError, message);
45188
45221
  const validateParams = (values, fields) => {
45189
45222
  fields.forEach(field => {
45190
45223
  const existsProp = Object.prototype.hasOwnProperty.call(values, field.name);
45191
45224
  if (!existsProp && field.required) {
45192
- throw invalidParameter$1(`Missing required parameter: ${field.name}`);
45225
+ throw invalidParameter(`Missing required parameter: ${field.name}`);
45193
45226
  }
45194
45227
  const value = values[field.name];
45195
45228
  if (value && field.type) {
45196
45229
  switch (field.type) {
45197
45230
  case 'array':
45198
45231
  if (!Array.isArray(value)) {
45199
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45232
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45200
45233
  }
45201
45234
  else if (!field.allowEmpty && value.length < 1) {
45202
- throw invalidParameter$1(`Parameter "${field.name}" is empty.`);
45235
+ throw invalidParameter(`Parameter "${field.name}" is empty.`);
45203
45236
  }
45204
45237
  break;
45205
45238
  case 'uint':
45206
45239
  if (typeof value !== 'string' && typeof value !== 'number') {
45207
- throw invalidParameter$1(`Parameter [${field.name}] has invalid type. "string|number" expected.`);
45240
+ throw invalidParameter(`Parameter [${field.name}] has invalid type. "string|number" expected.`);
45208
45241
  }
45209
45242
  if ((typeof value === 'number' && !Number.isSafeInteger(value)) ||
45210
45243
  !/^(?:[1-9]\d*|\d)$/.test(value.toString().replace(/^-/, field.allowNegative ? '' : '-'))) {
45211
- throw invalidParameter$1(`Parameter [${field.name}] has invalid value "${value}". Integer representation expected.`);
45244
+ throw invalidParameter(`Parameter [${field.name}] has invalid value "${value}". Integer representation expected.`);
45212
45245
  }
45213
45246
  break;
45214
45247
  case 'bigNumber':
45215
45248
  if (typeof value !== 'string') {
45216
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [string].`);
45249
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [string].`);
45217
45250
  }
45218
45251
  try {
45219
45252
  const bn = new BigNumber__default["default"](value);
@@ -45222,12 +45255,12 @@ const validateParams = (values, fields) => {
45222
45255
  }
45223
45256
  }
45224
45257
  catch (error) {
45225
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45258
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45226
45259
  }
45227
45260
  break;
45228
45261
  case 'buffer': {
45229
45262
  if (typeof value === 'undefined' || value === null) {
45230
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [buffer].`);
45263
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [buffer].`);
45231
45264
  }
45232
45265
  const isNodeBuffer = typeof Buffer !== 'undefined' &&
45233
45266
  typeof Buffer.isBuffer === 'function' &&
@@ -45240,18 +45273,18 @@ const validateParams = (values, fields) => {
45240
45273
  typeof ArrayBuffer.isView === 'function' &&
45241
45274
  ArrayBuffer.isView(value);
45242
45275
  if (!isNodeBuffer && !isCustomBuffer && !isArrayBuffer && !isArrayBufferView) {
45243
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [buffer].`);
45276
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [buffer].`);
45244
45277
  }
45245
45278
  break;
45246
45279
  }
45247
45280
  case 'hexString':
45248
45281
  if (typeof value !== 'string' || !isHexString(addHexPrefix(value))) {
45249
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45282
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45250
45283
  }
45251
45284
  break;
45252
45285
  default:
45253
45286
  if (typeof value !== field.type) {
45254
- throw invalidParameter$1(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45287
+ throw invalidParameter(`Parameter [${field.name}] is of type invalid and should be [${field.type}].`);
45255
45288
  }
45256
45289
  break;
45257
45290
  }
@@ -45285,10 +45318,10 @@ function validateResult(result, nonNullableFields, options) {
45285
45318
 
45286
45319
  const requiredString = (value, name) => {
45287
45320
  if (value === undefined || value === null) {
45288
- throw invalidParameter$1(`Missing required parameter: ${name}`);
45321
+ throw invalidParameter(`Missing required parameter: ${name}`);
45289
45322
  }
45290
45323
  if (typeof value !== 'string' || !value.trim()) {
45291
- throw invalidParameter$1(`Parameter [${name}] must be a non-empty string.`);
45324
+ throw invalidParameter(`Parameter [${name}] must be a non-empty string.`);
45292
45325
  }
45293
45326
  return value.trim();
45294
45327
  };
@@ -45306,20 +45339,20 @@ const requireHiddenWalletResponse = (session) => {
45306
45339
  };
45307
45340
  const normalizeParams = (payload) => {
45308
45341
  if (payload.mode === undefined) {
45309
- throw invalidParameter$1('Parameter [mode] is required.');
45342
+ throw invalidParameter('Parameter [mode] is required.');
45310
45343
  }
45311
45344
  if (payload.mode !== OpenWalletSessionMode.Standard &&
45312
45345
  payload.mode !== OpenWalletSessionMode.SelectHidden &&
45313
45346
  payload.mode !== OpenWalletSessionMode.ResumeHidden) {
45314
- throw invalidParameter$1('Parameter [mode] must be one of standard, select-hidden, or resume-hidden.');
45347
+ throw invalidParameter('Parameter [mode] must be one of standard, select-hidden, or resume-hidden.');
45315
45348
  }
45316
45349
  if (payload.useEmptyPassphrase !== undefined || payload.initSession !== undefined) {
45317
- throw invalidParameter$1('Legacy parameters [useEmptyPassphrase] and [initSession] are not supported by openWalletSession.');
45350
+ throw invalidParameter('Legacy parameters [useEmptyPassphrase] and [initSession] are not supported by openWalletSession.');
45318
45351
  }
45319
45352
  if (payload.mode === OpenWalletSessionMode.Standard ||
45320
45353
  payload.mode === OpenWalletSessionMode.SelectHidden) {
45321
45354
  if (payload.deviceId !== undefined || payload.passphraseState !== undefined) {
45322
- throw invalidParameter$1('Parameters [deviceId] and [passphraseState] are only allowed with mode [resume-hidden].');
45355
+ throw invalidParameter('Parameters [deviceId] and [passphraseState] are only allowed with mode [resume-hidden].');
45323
45356
  }
45324
45357
  return { mode: payload.mode };
45325
45358
  }
@@ -45342,28 +45375,39 @@ class OpenWalletSession extends BaseMethod {
45342
45375
  run() {
45343
45376
  return __awaiter(this, void 0, void 0, function* () {
45344
45377
  const isProtocolV2 = this.device.isProtocolV2();
45345
- const state = yield this.device.getDeviceState({ refreshSections: ['status'] });
45378
+ let state = yield this.device.getDeviceState({ refreshSections: ['status'] });
45346
45379
  let currentDeviceId = state.identity.deviceId;
45380
+ const hasAuthoritativeProtocolV2WalletStatus = (candidate) => candidate.status.unlocked === true &&
45381
+ typeof candidate.status.passphraseProtection === 'boolean' &&
45382
+ typeof candidate.status.unlockedAttachPin === 'boolean';
45383
+ const requireAuthoritativeProtocolV2WalletStatus = (candidate) => {
45384
+ if (!hasAuthoritativeProtocolV2WalletStatus(candidate)) {
45385
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed);
45386
+ }
45387
+ return candidate;
45388
+ };
45347
45389
  const requireDeviceId = () => {
45348
45390
  if (!currentDeviceId) {
45349
45391
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed);
45350
45392
  }
45351
45393
  return currentDeviceId;
45352
45394
  };
45353
- const refreshProtocolV2DeviceId = () => __awaiter(this, void 0, void 0, function* () {
45354
- const refreshedState = yield this.device.getDeviceState({ refreshSections: ['status'] });
45355
- currentDeviceId = refreshedState.identity.deviceId;
45356
- return requireDeviceId();
45395
+ const refreshProtocolV2DeviceState = () => __awaiter(this, void 0, void 0, function* () {
45396
+ state = yield this.device.getDeviceState({ refreshSections: ['status'] });
45397
+ currentDeviceId = state.identity.deviceId;
45398
+ return state;
45357
45399
  });
45358
- const unlockProtocolV2IfLocked = () => __awaiter(this, void 0, void 0, function* () {
45359
- if (isProtocolV2 && state.status.unlocked === false) {
45400
+ const ensureProtocolV2WalletStatus = () => __awaiter(this, void 0, void 0, function* () {
45401
+ if (isProtocolV2 && !hasAuthoritativeProtocolV2WalletStatus(state)) {
45360
45402
  yield this.device.unlockDevice(hdTransport.DeviceSessionPinType.Main, {
45361
45403
  source: 'unlock-coordinator',
45362
45404
  reason: 'device-locked',
45363
45405
  deviceOnly: true,
45364
45406
  method: 'openWalletSession',
45365
45407
  });
45408
+ requireAuthoritativeProtocolV2WalletStatus(yield refreshProtocolV2DeviceState());
45366
45409
  }
45410
+ return state;
45367
45411
  });
45368
45412
  const protocol = isProtocolV2 ? 'V2' : 'V1';
45369
45413
  if (this.params.mode === OpenWalletSessionMode.Standard) {
@@ -45372,14 +45416,19 @@ class OpenWalletSession extends BaseMethod {
45372
45416
  ? yield getProtocolV2WalletSession(this.device, {
45373
45417
  onlyMainPin: true,
45374
45418
  deriveCardano: this.payload.deriveCardano,
45375
- selectMainWalletBeforeRestore: state.status.unlocked === false || state.status.unlockedAttachPin === true,
45419
+ selectMainWalletBeforeRestore: !hasAuthoritativeProtocolV2WalletStatus(state) ||
45420
+ state.status.unlockedAttachPin === true,
45376
45421
  })
45377
45422
  : yield getPassphraseStateWithRefreshDeviceInfo(this.device, {
45378
45423
  onlyMainPin: true,
45379
45424
  initSession: this.payload.initSession,
45380
45425
  });
45381
- const deviceId = isProtocolV2 ? yield refreshProtocolV2DeviceId() : requireDeviceId();
45382
- if (session.unlockedAttachPin) {
45426
+ const refreshedState = isProtocolV2
45427
+ ? requireAuthoritativeProtocolV2WalletStatus(yield refreshProtocolV2DeviceState())
45428
+ : state;
45429
+ const deviceId = requireDeviceId();
45430
+ if (session.unlockedAttachPin ||
45431
+ (isProtocolV2 && refreshedState.status.unlockedAttachPin === true)) {
45383
45432
  try {
45384
45433
  yield this.device.lockDevice();
45385
45434
  }
@@ -45398,8 +45447,8 @@ class OpenWalletSession extends BaseMethod {
45398
45447
  }
45399
45448
  if (this.params.mode === OpenWalletSessionMode.ResumeHidden) {
45400
45449
  if (isProtocolV2) {
45401
- yield unlockProtocolV2IfLocked();
45402
- const refreshedDeviceId = yield refreshProtocolV2DeviceId();
45450
+ yield ensureProtocolV2WalletStatus();
45451
+ const refreshedDeviceId = requireDeviceId();
45403
45452
  if (refreshedDeviceId !== this.params.deviceId) {
45404
45453
  deviceWalletSessionStore.delete(this.params.deviceId, this.params.passphraseState);
45405
45454
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
@@ -45435,15 +45484,18 @@ class OpenWalletSession extends BaseMethod {
45435
45484
  return Object.assign(Object.assign({ protocol, walletType: 'hidden', deviceId }, requireHiddenWalletResponse(session)), { resumed: wasResumed(session) || (!isProtocolV2 && session.newSession === cachedSessionId) });
45436
45485
  }
45437
45486
  this.device.passphraseState = undefined;
45438
- yield unlockProtocolV2IfLocked();
45487
+ yield ensureProtocolV2WalletStatus();
45439
45488
  const session = isProtocolV2
45440
45489
  ? yield getProtocolV2WalletSession(this.device, {
45441
45490
  forceWalletSelection: true,
45442
45491
  deriveCardano: this.payload.deriveCardano,
45443
45492
  })
45444
45493
  : yield getPassphraseStateWithRefreshDeviceInfo(this.device, { initSession: true });
45445
- const deviceId = isProtocolV2 ? yield refreshProtocolV2DeviceId() : requireDeviceId();
45446
- if (isProtocolV2 && this.device.getCurrentPassphraseProtection() !== true) {
45494
+ const refreshedState = isProtocolV2
45495
+ ? requireAuthoritativeProtocolV2WalletStatus(yield refreshProtocolV2DeviceState())
45496
+ : state;
45497
+ const deviceId = requireDeviceId();
45498
+ if (isProtocolV2 && refreshedState.status.passphraseProtection !== true) {
45447
45499
  this.device.clearInternalState();
45448
45500
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotOpenedPassphrase);
45449
45501
  }
@@ -45487,7 +45539,7 @@ class GetLogs extends BaseMethod {
45487
45539
  class ClearSessionCache extends BaseMethod {
45488
45540
  init() {
45489
45541
  if (this.payload.passphraseState !== undefined && !this.payload.deviceId) {
45490
- throw invalidParameter$1('Parameter [deviceId] is required with [passphraseState].');
45542
+ throw invalidParameter('Parameter [deviceId] is required with [passphraseState].');
45491
45543
  }
45492
45544
  this.useDevice = false;
45493
45545
  this.useDevicePassphraseState = false;
@@ -45977,94 +46029,6 @@ class DeviceBackup extends BaseMethod {
45977
46029
  }
45978
46030
  }
45979
46031
 
45980
- const invalidParameter = (message) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, message);
45981
- function validateNonEmptyString(value, name) {
45982
- if (typeof value !== 'string' || value.trim().length === 0) {
45983
- throw invalidParameter(`Parameter [${name}] is required and must be a non-empty string.`);
45984
- }
45985
- return value;
45986
- }
45987
- const PROTOCOL_V2_FILESYSTEM_VOLUMES = new Set(['vol0', 'vol1']);
45988
- const MAX_PROTOCOL_V2_FILESYSTEM_PATH_BYTES = 127;
45989
- function getUtf8ByteLength(value) {
45990
- return Array.from(value).reduce((length, character) => {
45991
- var _a;
45992
- const codePoint = (_a = character.codePointAt(0)) !== null && _a !== void 0 ? _a : 0;
45993
- if (codePoint <= 0x7f)
45994
- return length + 1;
45995
- if (codePoint <= 0x7ff)
45996
- return length + 2;
45997
- if (codePoint <= 0xffff)
45998
- return length + 3;
45999
- return length + 4;
46000
- }, 0);
46001
- }
46002
- function validateProtocolV2FilesystemPath(value, name, options = {}) {
46003
- const rawPath = validateNonEmptyString(value, name).trim();
46004
- const containsUnsupportedCharacter = Array.from(rawPath).some(character => {
46005
- const codePoint = character.charCodeAt(0);
46006
- return codePoint <= 0x1f || codePoint === 0x7f || character === '\\';
46007
- });
46008
- if (containsUnsupportedCharacter) {
46009
- throw invalidParameter(`Parameter [${name}] contains unsupported path characters.`);
46010
- }
46011
- const match = /^([a-zA-Z0-9]+):(.*)$/.exec(rawPath);
46012
- if (!match) {
46013
- throw invalidParameter(`Parameter [${name}] must use a supported Protocol V2 filesystem volume.`);
46014
- }
46015
- const volume = match[1].toLowerCase();
46016
- if (!PROTOCOL_V2_FILESYSTEM_VOLUMES.has(volume)) {
46017
- throw invalidParameter(`Parameter [${name}] uses an unsupported filesystem volume.`);
46018
- }
46019
- const rawSuffix = match[2];
46020
- if (rawSuffix.length === 0) {
46021
- if (options.allowVolumeRoot)
46022
- return `${volume}:`;
46023
- throw invalidParameter(`Parameter [${name}] must identify a filesystem entry.`);
46024
- }
46025
- const suffix = rawSuffix.startsWith('/') ? rawSuffix : `/${rawSuffix}`;
46026
- const segments = suffix.slice(1).split('/');
46027
- if (segments.some(segment => segment.length === 0 || segment === '.' || segment === '..')) {
46028
- throw invalidParameter(`Parameter [${name}] contains an invalid path segment.`);
46029
- }
46030
- const canonicalPath = `${volume}:${rawSuffix.startsWith('/') ? '/' : ''}${segments.join('/')}`;
46031
- if (getUtf8ByteLength(canonicalPath) > MAX_PROTOCOL_V2_FILESYSTEM_PATH_BYTES) {
46032
- throw invalidParameter(`Parameter [${name}] exceeds the maximum filesystem path length.`);
46033
- }
46034
- return canonicalPath;
46035
- }
46036
- function validateNonNegativeInteger(value, name, defaultValue) {
46037
- if (value === undefined || value === null) {
46038
- if (defaultValue !== undefined)
46039
- return defaultValue;
46040
- throw invalidParameter(`Missing required parameter: ${name}`);
46041
- }
46042
- const numeric = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;
46043
- if (typeof numeric !== 'number' || !Number.isSafeInteger(numeric) || numeric < 0) {
46044
- throw invalidParameter(`Parameter [${name}] must be a non-negative integer.`);
46045
- }
46046
- return numeric;
46047
- }
46048
- function validateOptionalNonNegativeInteger(value, name) {
46049
- if (value === undefined || value === null)
46050
- return undefined;
46051
- return validateNonNegativeInteger(value, name);
46052
- }
46053
- function validateOptionalPercentage(value, name) {
46054
- const numeric = validateOptionalNonNegativeInteger(value, name);
46055
- if (numeric === undefined)
46056
- return undefined;
46057
- if (numeric > 100) {
46058
- throw invalidParameter(`Parameter [${name}] must be between 0 and 100.`);
46059
- }
46060
- return numeric;
46061
- }
46062
- function validateRequiredData(value, name) {
46063
- if (value === undefined || value === null) {
46064
- throw invalidParameter(`Missing required parameter: ${name}`);
46065
- }
46066
- }
46067
-
46068
46032
  class DeviceChangePin extends BaseMethod {
46069
46033
  getSupportedProtocols() {
46070
46034
  return ['V1', 'V2'];
@@ -46089,7 +46053,7 @@ class DeviceChangePin extends BaseMethod {
46089
46053
  return __awaiter(this, void 0, void 0, function* () {
46090
46054
  if (this.device.isProtocolV2()) {
46091
46055
  if (this.params.remove) {
46092
- throw invalidParameter('Parameter [remove=true] is not supported by the Pro2 device PIN page.');
46056
+ throw invalidParameter$1('Parameter [remove=true] is not supported by the Pro2 device PIN page.');
46093
46057
  }
46094
46058
  const res = yield this.device.commands.typedCall('DeviceSettingsPageShow', 'Success', {
46095
46059
  page: hdTransport.DeviceSettingsPage.DevicePinChange,
@@ -46298,7 +46262,7 @@ const getProtocolV2SettingsBehavior = (operation) => {
46298
46262
  const assertSettingsSupported = (payload, unsupported, protocol) => {
46299
46263
  const provided = unsupported.filter(key => payload[key] !== undefined);
46300
46264
  if (provided.length > 0) {
46301
- throw invalidParameter(`${protocol} does not support settings: ${provided.join(', ')}.`);
46265
+ throw invalidParameter$1(`${protocol} does not support settings: ${provided.join(', ')}.`);
46302
46266
  }
46303
46267
  };
46304
46268
  const assertProtocolV2SettingValues = (payload, capabilities) => {
@@ -46306,7 +46270,7 @@ const assertProtocolV2SettingValues = (payload, capabilities) => {
46306
46270
  if (payload.brightness !== undefined &&
46307
46271
  brightnessRange &&
46308
46272
  (payload.brightness < brightnessRange.min || payload.brightness > brightnessRange.max)) {
46309
- throw invalidParameter(`Protocol V2 brightness must be between ${brightnessRange.min} and ${brightnessRange.max}.`);
46273
+ throw invalidParameter$1(`Protocol V2 brightness must be between ${brightnessRange.min} and ${brightnessRange.max}.`);
46310
46274
  }
46311
46275
  const delayFields = [
46312
46276
  ['autoLockDelayMs', capabilities.autoLockDelayOptions],
@@ -46315,7 +46279,7 @@ const assertProtocolV2SettingValues = (payload, capabilities) => {
46315
46279
  delayFields.forEach(([field, options]) => {
46316
46280
  const value = payload[field];
46317
46281
  if (value !== undefined && !options.some(option => option.valueMs === value)) {
46318
- throw invalidParameter(`Protocol V2 ${field} must be one of: ${options.map(option => option.valueMs).join(', ')}.`);
46282
+ throw invalidParameter$1(`Protocol V2 ${field} must be one of: ${options.map(option => option.valueMs).join(', ')}.`);
46319
46283
  }
46320
46284
  });
46321
46285
  };
@@ -46403,10 +46367,10 @@ class DeviceSettings extends BaseMethod {
46403
46367
  const hasPassphrasePage = requestedPassphrase !== undefined;
46404
46368
  const hasAirgapPage = requestedAirgap !== undefined;
46405
46369
  if (hasPassphrasePage && hasAirgapPage) {
46406
- throw invalidParameter('Protocol V2 passphrase and air-gap settings must be changed in separate calls.');
46370
+ throw invalidParameter$1('Protocol V2 passphrase and air-gap settings must be changed in separate calls.');
46407
46371
  }
46408
46372
  if ((hasPassphrasePage || hasAirgapPage) && Object.keys(settings).length > 0) {
46409
- throw invalidParameter('Protocol V2 on-device settings must not be combined with direct settings.');
46373
+ throw invalidParameter$1('Protocol V2 on-device settings must not be combined with direct settings.');
46410
46374
  }
46411
46375
  if (requestedPassphrase !== undefined) {
46412
46376
  const current = yield this.device.getDeviceState({ refreshSections: ['status'] });
@@ -46441,7 +46405,7 @@ class DeviceSettings extends BaseMethod {
46441
46405
  return res.message;
46442
46406
  }
46443
46407
  if (Object.keys(settings).length === 0) {
46444
- throw invalidParameter('No Protocol V2 compatible setting provided.');
46408
+ throw invalidParameter$1('No Protocol V2 compatible setting provided.');
46445
46409
  }
46446
46410
  const res = yield this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
46447
46411
  settings,
@@ -46453,7 +46417,7 @@ class DeviceSettings extends BaseMethod {
46453
46417
  const capabilities = getDeviceSettingsCapabilities(this.device.getCurrentDeviceType(), 'V1');
46454
46418
  if (this.payload.safetyChecks !== undefined &&
46455
46419
  !capabilities.safetyCheckOptions.some(option => option.value === this.payload.safetyChecks)) {
46456
- throw invalidParameter(`Protocol V1 safetyChecks must be one of: ${capabilities.safetyCheckOptions
46420
+ throw invalidParameter$1(`Protocol V1 safetyChecks must be one of: ${capabilities.safetyCheckOptions
46457
46421
  .map(option => option.value)
46458
46422
  .join(', ')}.`);
46459
46423
  }
@@ -47228,35 +47192,6 @@ class DeviceFullyUploadResource extends BaseMethod {
47228
47192
  }
47229
47193
  }
47230
47194
 
47231
- const DEFAULT_FIRMWARE_PROGRESS_INTERVAL_MS = 250;
47232
- const createFirmwareProgressThrottle = (intervalMs = DEFAULT_FIRMWARE_PROGRESS_INTERVAL_MS) => {
47233
- const stateByType = new Map();
47234
- return (progress, progressType) => {
47235
- if (progressType !== 'transferData') {
47236
- return true;
47237
- }
47238
- const normalizedProgress = Math.max(0, Math.min(100, Math.floor(progress)));
47239
- if (normalizedProgress === 0 || normalizedProgress === 100) {
47240
- stateByType.set(progressType, {
47241
- lastEmittedAt: Date.now(),
47242
- lastProgress: normalizedProgress,
47243
- });
47244
- return true;
47245
- }
47246
- const now = Date.now();
47247
- const state = stateByType.get(progressType);
47248
- if (state &&
47249
- (state.lastProgress === normalizedProgress || now - state.lastEmittedAt < intervalMs)) {
47250
- return false;
47251
- }
47252
- stateByType.set(progressType, {
47253
- lastEmittedAt: now,
47254
- lastProgress: normalizedProgress,
47255
- });
47256
- return true;
47257
- };
47258
- };
47259
-
47260
47195
  const Log$9 = getLogger(exports.LoggerNames.Method);
47261
47196
  const SESSION_ERROR$1 = 'session not found';
47262
47197
  const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
@@ -47270,7 +47205,6 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
47270
47205
  constructor() {
47271
47206
  super(...arguments);
47272
47207
  this.checkPromise = null;
47273
- this.shouldPostFirmwareProgress = createFirmwareProgressThrottle();
47274
47208
  this.postTipMessage = (message) => {
47275
47209
  this.postMessage(createUiMessage(UI_REQUEST.FIRMWARE_TIP, {
47276
47210
  device: this.device.toMessageObject(),
@@ -47285,9 +47219,6 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
47285
47219
  }));
47286
47220
  };
47287
47221
  this.postProgressMessage = (progress, progressType) => {
47288
- if (!this.shouldPostFirmwareProgress(progress, progressType)) {
47289
- return;
47290
- }
47291
47222
  this.postMessage(createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
47292
47223
  device: this.device.toMessageObject(),
47293
47224
  progress,
@@ -50118,14 +50049,15 @@ class DeviceGetOnboardingStatus extends BaseMethod {
50118
50049
  }
50119
50050
 
50120
50051
  const MIN_FILE_CHUNK_SIZE = 64;
50121
- function isRetryableFileWriteTimeout(error) {
50052
+ function isProtocolV2ResponseTimeout(error) {
50122
50053
  var _a, _b;
50123
50054
  if (!error || typeof error !== 'object')
50124
50055
  return false;
50125
50056
  const candidate = error;
50126
50057
  const code = (_a = candidate.errorCode) !== null && _a !== void 0 ? _a : candidate.code;
50127
50058
  return (code === hdShared.HardwareErrorCode.BleTimeoutError ||
50128
- /Lowlevel response timeout/i.test((_b = candidate.message) !== null && _b !== void 0 ? _b : ''));
50059
+ code === 'response-timeout' ||
50060
+ /(?:BLE|Lowlevel|Protocol V2) response timeout/i.test((_b = candidate.message) !== null && _b !== void 0 ? _b : ''));
50129
50061
  }
50130
50062
  function getProtocolV2FileChunkLimit() {
50131
50063
  const env = DataManager.getSettings('env');
@@ -50212,7 +50144,7 @@ function writeProtocolV2File(options) {
50212
50144
  isWritePending = false;
50213
50145
  }
50214
50146
  catch (error) {
50215
- if (retryCount >= maxChunkRetries || !isRetryableFileWriteTimeout(error))
50147
+ if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error))
50216
50148
  throw error;
50217
50149
  retryCount += 1;
50218
50150
  (_h = options.throwIfAborted) === null || _h === void 0 ? void 0 : _h.call(options);
@@ -50243,6 +50175,11 @@ function writeProtocolV2File(options) {
50243
50175
  rateBytesPerSecond: elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
50244
50176
  elapsedMs,
50245
50177
  });
50178
+ if (options.paceMs && options.paceMs > 0) {
50179
+ yield new Promise(resolve => {
50180
+ setTimeout(resolve, options.paceMs);
50181
+ });
50182
+ }
50246
50183
  }
50247
50184
  return Object.assign(Object.assign({}, lastMessage), { path: options.path, offset: startOffset, total_size: totalSize, processed_byte: startOffset + written, chunks });
50248
50185
  });
@@ -50252,7 +50189,7 @@ const WALLPAPER_DIRECTORY = 'vol1:/wallpapers';
50252
50189
  const SAFE_FILE_NAME = /^[A-Za-z0-9_-]+(?:\.bin)?$/;
50253
50190
  function normalizeFileName(fileName, data) {
50254
50191
  if (fileName !== undefined && (!fileName || !SAFE_FILE_NAME.test(fileName))) {
50255
- throw invalidParameter('Parameter [fileName] may only contain letters, numbers, underscores, hyphens and an optional .bin suffix.');
50192
+ throw invalidParameter$1('Parameter [fileName] may only contain letters, numbers, underscores, hyphens and an optional .bin suffix.');
50256
50193
  }
50257
50194
  const baseName = fileName !== null && fileName !== void 0 ? fileName : `wallpaper-${utils.bytesToHex(blake2s.blake2s(data)).slice(0, 12)}`;
50258
50195
  return baseName.endsWith('.bin') ? baseName : `${baseName}.bin`;
@@ -50270,13 +50207,13 @@ class DeviceUploadWallpaper extends BaseMethod {
50270
50207
  init() {
50271
50208
  const { width, height, rgba, fileName, chunkSize } = this.payload;
50272
50209
  if (width !== PRO2_WALLPAPER_WIDTH || height !== PRO2_WALLPAPER_HEIGHT) {
50273
- throw invalidParameter(`Pro2 wallpaper dimensions must be ${PRO2_WALLPAPER_WIDTH}x${PRO2_WALLPAPER_HEIGHT}.`);
50210
+ throw invalidParameter$1(`Pro2 wallpaper dimensions must be ${PRO2_WALLPAPER_WIDTH}x${PRO2_WALLPAPER_HEIGHT}.`);
50274
50211
  }
50275
50212
  if (!(rgba instanceof ArrayBuffer) && !ArrayBuffer.isView(rgba)) {
50276
- throw invalidParameter('Parameter [rgba] must be an ArrayBuffer or Uint8Array.');
50213
+ throw invalidParameter$1('Parameter [rgba] must be an ArrayBuffer or Uint8Array.');
50277
50214
  }
50278
50215
  if (chunkSize !== undefined && (!Number.isInteger(chunkSize) || chunkSize <= 0)) {
50279
- throw invalidParameter('Parameter [chunkSize] must be a positive integer.');
50216
+ throw invalidParameter$1('Parameter [chunkSize] must be a positive integer.');
50280
50217
  }
50281
50218
  const rgbaBytes = rgba instanceof ArrayBuffer
50282
50219
  ? rgba
@@ -50311,7 +50248,7 @@ class DeviceUploadWallpaper extends BaseMethod {
50311
50248
  return;
50312
50249
  const { encoded } = this;
50313
50250
  if (!encoded)
50314
- throw invalidParameter('Wallpaper data has not been initialized.');
50251
+ throw invalidParameter$1('Wallpaper data has not been initialized.');
50315
50252
  yield writeProtocolV2File({
50316
50253
  commands: this.device.commands,
50317
50254
  path: this.path,
@@ -50336,7 +50273,7 @@ class DeviceUploadWallpaper extends BaseMethod {
50336
50273
  return __awaiter(this, void 0, void 0, function* () {
50337
50274
  const { encoded } = this;
50338
50275
  if (!encoded)
50339
- throw invalidParameter('Wallpaper data has not been initialized.');
50276
+ throw invalidParameter$1('Wallpaper data has not been initialized.');
50340
50277
  yield this.ensureDirectory();
50341
50278
  yield this.upload();
50342
50279
  const response = yield this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
@@ -50352,6 +50289,108 @@ class DeviceUploadWallpaper extends BaseMethod {
50352
50289
  }
50353
50290
  }
50354
50291
 
50292
+ const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
50293
+ const NFT_UPDATE_MESSAGE_TYPE = 61500;
50294
+ class DeviceUploadNft extends BaseMethod {
50295
+ getSupportedProtocols() {
50296
+ return ['V2'];
50297
+ }
50298
+ init() {
50299
+ const { image, thumbnail, title, subtitle, timestampMs = Date.now(), chunkSize = PRO2_NFT_DEFAULT_CHUNK_SIZE, paceMs = PRO2_NFT_DEFAULT_PACE_MS, timeoutMs = PRO2_NFT_DEFAULT_TIMEOUT_MS, } = this.payload;
50300
+ if (!Number.isInteger(chunkSize) ||
50301
+ chunkSize < PRO2_NFT_MIN_CHUNK_SIZE ||
50302
+ chunkSize > PRO2_NFT_MAX_CHUNK_SIZE) {
50303
+ throw invalidParameter$1(`Parameter [chunkSize] must be an integer between ${PRO2_NFT_MIN_CHUNK_SIZE} and ${PRO2_NFT_MAX_CHUNK_SIZE}.`);
50304
+ }
50305
+ if (!Number.isInteger(paceMs) || paceMs < 0) {
50306
+ throw invalidParameter$1('Parameter [paceMs] must be a non-negative integer.');
50307
+ }
50308
+ if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
50309
+ throw invalidParameter$1('Parameter [timeoutMs] must be a positive integer.');
50310
+ }
50311
+ this.bundle = buildPro2NftBundle({ image, thumbnail, title, subtitle, timestampMs });
50312
+ this.params = { image, thumbnail, title, subtitle, timestampMs, chunkSize, paceMs, timeoutMs };
50313
+ this.unlockPolicy = 'none';
50314
+ this.skipForceUpdateCheck = true;
50315
+ this.useDevicePassphraseState = false;
50316
+ }
50317
+ assertCapabilities() {
50318
+ return __awaiter(this, void 0, void 0, function* () {
50319
+ const protocolInfo = yield this.device.ensureProtocolV2RuntimeContext();
50320
+ const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE);
50321
+ const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
50322
+ if (!hasFileWrite || !hasNftUpdate) {
50323
+ throw hdShared.createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
50324
+ }
50325
+ });
50326
+ }
50327
+ updateNft(basename) {
50328
+ return __awaiter(this, void 0, void 0, function* () {
50329
+ const params = { file_name_no_ext: basename };
50330
+ const options = { timeoutMs: this.params.timeoutMs };
50331
+ try {
50332
+ return yield this.device.commands.typedCall('NftUpdate', 'Success', params, options);
50333
+ }
50334
+ catch (error) {
50335
+ if (!isProtocolV2ResponseTimeout(error)) {
50336
+ throw error;
50337
+ }
50338
+ this.throwIfAborted();
50339
+ return this.device.commands.typedCall('NftUpdate', 'Success', params, options);
50340
+ }
50341
+ });
50342
+ }
50343
+ run() {
50344
+ var _a;
50345
+ return __awaiter(this, void 0, void 0, function* () {
50346
+ const { bundle } = this;
50347
+ if (!bundle)
50348
+ throw invalidParameter$1('NFT data has not been initialized.');
50349
+ yield this.assertCapabilities();
50350
+ const files = [
50351
+ { path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.bin`, data: bundle.image },
50352
+ { path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}_m.bin`, data: bundle.thumbnail },
50353
+ { path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.json`, data: bundle.metadata },
50354
+ ];
50355
+ const totalSize = files.reduce((sum, file) => sum + file.data.byteLength, 0);
50356
+ let transferredBeforeFile = 0;
50357
+ for (const file of files) {
50358
+ const transferredAtFileStart = transferredBeforeFile;
50359
+ yield writeProtocolV2File({
50360
+ commands: this.device.commands,
50361
+ path: file.path,
50362
+ data: file.data,
50363
+ totalSize: file.data.byteLength,
50364
+ chunkSize: this.params.chunkSize,
50365
+ timeoutMs: this.params.timeoutMs,
50366
+ paceMs: this.params.paceMs,
50367
+ overwrite: true,
50368
+ append: false,
50369
+ throwIfAborted: () => this.throwIfAborted(),
50370
+ onProgress: progress => {
50371
+ if (typeof this.postMessage !== 'function')
50372
+ return;
50373
+ const transferredBytes = transferredAtFileStart + progress.transferredBytes;
50374
+ this.postMessage(createUiMessage(UI_REQUEST.DEVICE_PROGRESS, Object.assign(Object.assign({}, progress), { progress: Math.floor((transferredBytes / totalSize) * 100), transferredBytes, totalBytes: totalSize })));
50375
+ },
50376
+ });
50377
+ transferredBeforeFile += file.data.byteLength;
50378
+ }
50379
+ this.throwIfAborted();
50380
+ const response = yield this.updateNft(bundle.basename);
50381
+ return {
50382
+ basename: bundle.basename,
50383
+ imagePath: files[0].path,
50384
+ thumbnailPath: files[1].path,
50385
+ metadataPath: files[2].path,
50386
+ totalSize,
50387
+ nftUpdated: true,
50388
+ message: (_a = response.message) === null || _a === void 0 ? void 0 : _a.message,
50389
+ };
50390
+ });
50391
+ }
50392
+ }
50393
+
50355
50394
  class FileWrite extends BaseMethod {
50356
50395
  getSupportedProtocols() {
50357
50396
  return ['V2'];
@@ -50476,13 +50515,6 @@ class CipherKeyValue extends BaseMethod {
50476
50515
  }
50477
50516
  }
50478
50517
 
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
50518
  const isProtocolV2UiEnabled = (method) => method.protocolV2UiMode !== 'none';
50487
50519
  const getDisplayState = (value) => {
50488
50520
  const visited = new Set();
@@ -50607,93 +50639,51 @@ class ProtocolV2UiInteractionCoordinator {
50607
50639
  }
50608
50640
 
50609
50641
  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 });
50642
+ const createProtocolV2UnlockContext = () => ({
50643
+ preflightCompleted: false,
50622
50644
  });
50623
- function runMethodWithUnlockRetry(method, device, uiCoordinator) {
50624
- var _a, _b, _c, _d, _e;
50645
+ function runMethodWithUnlockPolicy(method, device, options = {}) {
50646
+ var _a, _b;
50625
50647
  return __awaiter(this, void 0, void 0, function* () {
50648
+ const { context = createProtocolV2UnlockContext(), uiCoordinator, afterStatusBeforeUnlock, prepare, run: configuredRun, } = options;
50649
+ const run = configuredRun !== null && configuredRun !== void 0 ? configuredRun : (() => method.run());
50650
+ method.protocolV2UnlockContext = context;
50626
50651
  const shouldEmitUi = isProtocolV2UiEnabled(method);
50627
50652
  const shouldCoordinateUi = shouldEmitUi && uiCoordinator !== undefined;
50628
- const isProtocolV2 = device.isProtocolV2();
50629
- const requiresFreshStatus = isProtocolV2 &&
50630
- method.unlockPolicy === 'unlock-before-run' &&
50653
+ const requiresPreUnlock = device.isProtocolV2() &&
50654
+ (method.useDevicePassphraseState || method.unlockPolicy === 'unlock-before-run') &&
50631
50655
  !((_a = device.isBootloader) === null || _a === void 0 ? void 0 : _a.call(device)) &&
50632
50656
  !((_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
+ if (requiresPreUnlock && !context.preflightCompleted) {
50658
+ const status = yield refreshProtocolV2DeviceStatus(device);
50659
+ if (typeof (status === null || status === void 0 ? void 0 : status.unlocked) !== 'boolean') {
50660
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 DeviceStatus did not report an explicit unlock state.');
50661
+ }
50662
+ yield (afterStatusBeforeUnlock === null || afterStatusBeforeUnlock === void 0 ? void 0 : afterStatusBeforeUnlock());
50663
+ if (!status.unlocked) {
50664
+ const unlockInteraction = shouldCoordinateUi
50665
+ ? uiCoordinator.enterUnlockInteraction(method.name)
50666
+ : undefined;
50667
+ const unlockedStatus = yield device.unlockDevice(undefined, shouldCoordinateUi
50668
+ ? { emitUiEvent: false, interaction: unlockInteraction }
50669
+ : {
50670
+ source: 'unlock-coordinator',
50671
+ reason: 'device-locked',
50672
+ deviceOnly: true,
50673
+ method: method.name,
50674
+ });
50675
+ if ((unlockedStatus === null || unlockedStatus === void 0 ? void 0 : unlockedStatus.unlocked) !== true) {
50676
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 device remained locked after the unlock flow.');
50677
+ }
50678
+ Log$3.debug('Protocol V2 pre-unlock completed', { method: method.name });
50657
50679
  }
50658
- return method.run();
50680
+ context.preflightCompleted = true;
50659
50681
  }
50682
+ yield (prepare === null || prepare === void 0 ? void 0 : prepare());
50660
50683
  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
- }
50684
+ uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
50696
50685
  }
50686
+ return run();
50697
50687
  });
50698
50688
  }
50699
50689
 
@@ -50972,25 +50962,26 @@ class AllNetworkGetAddressBase extends BaseMethod {
50972
50962
  this.device.on(DEVICE.PIN, onSignalAbort);
50973
50963
  this.device.on(DEVICE.PASSPHRASE, onSignalAbort);
50974
50964
  preCheckDeviceSupport(this.device, method);
50975
- if (this.temporarySafetyCheckPrompted) {
50976
- method.temporarySafetyCheckPrompted = true;
50977
- }
50978
- else {
50979
- const appliedTemporarySafetyCheck = yield method.checkSafetyLevelOnTestNet();
50980
- if (appliedTemporarySafetyCheck) {
50981
- this.temporarySafetyCheckPrompted = true;
50982
- }
50983
- }
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();
50965
+ const response = yield runMethodWithUnlockPolicy(method, this.device, {
50966
+ context: this.protocolV2UnlockContext,
50967
+ prepare: () => __awaiter(this, void 0, void 0, function* () {
50968
+ if (this.temporarySafetyCheckPrompted) {
50969
+ method.temporarySafetyCheckPrompted = true;
50970
+ }
50971
+ else {
50972
+ const appliedTemporarySafetyCheck = yield method.checkSafetyLevelOnTestNet();
50973
+ if (appliedTemporarySafetyCheck) {
50974
+ this.temporarySafetyCheckPrompted = true;
50975
+ }
50976
+ }
50977
+ if (this.device.isProtocolV2() && this.payload.passphraseState) {
50978
+ const passphraseStateSafety = yield this.device.checkPassphraseStateSafety(this.payload.passphraseState, false, this.payload.skipPassphraseCheck);
50979
+ if (!passphraseStateSafety) {
50980
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
50981
+ }
50982
+ }
50983
+ }),
50984
+ });
50994
50985
  if (!Array.isArray(response) || response.length === 0) {
50995
50986
  throw new Error('No response');
50996
50987
  }
@@ -60235,6 +60226,7 @@ var ApiMethods = /*#__PURE__*/Object.freeze({
60235
60226
  deviceReboot: DeviceReboot,
60236
60227
  deviceGetOnboardingStatus: DeviceGetOnboardingStatus,
60237
60228
  deviceUploadWallpaper: DeviceUploadWallpaper,
60229
+ deviceUploadNft: DeviceUploadNft,
60238
60230
  uploadPortfolio: UploadPortfolio,
60239
60231
  cipherKeyValue: CipherKeyValue,
60240
60232
  allNetworkGetAddress: AllNetworkGetAddress,
@@ -60619,6 +60611,44 @@ const getSynchronize = (mutex) => {
60619
60611
  return (action, lockId) => lock(lockId).then(unlock => Promise.resolve().then(action).finally(unlock));
60620
60612
  };
60621
60613
 
60614
+ const DEFAULT_UI_PROGRESS_INTERVAL_MS = 250;
60615
+ const normalizeProgress = (progress) => {
60616
+ if (typeof progress !== 'number' || !Number.isFinite(progress)) {
60617
+ return undefined;
60618
+ }
60619
+ return Math.max(0, Math.min(100, Math.floor(progress)));
60620
+ };
60621
+ const createUiProgressMessageFilter = (intervalMs = DEFAULT_UI_PROGRESS_INTERVAL_MS, now = Date.now) => {
60622
+ const stateByType = new Map();
60623
+ return (message) => {
60624
+ if (!('event' in message) ||
60625
+ message.event !== UI_EVENT ||
60626
+ (message.type !== UI_REQUEST.DEVICE_PROGRESS && message.type !== UI_REQUEST.FIRMWARE_PROGRESS)) {
60627
+ return true;
60628
+ }
60629
+ const key = message.type === UI_REQUEST.FIRMWARE_PROGRESS
60630
+ ? `${message.type}:${message.payload.progressType}`
60631
+ : message.type;
60632
+ const progress = normalizeProgress(message.payload.progress);
60633
+ const currentTime = now();
60634
+ const state = stateByType.get(key);
60635
+ if (!state) {
60636
+ stateByType.set(key, { lastEmittedAt: currentTime, lastProgress: progress });
60637
+ return true;
60638
+ }
60639
+ const isBoundary = progress === 0 || progress === 100;
60640
+ if (isBoundary && progress === state.lastProgress) {
60641
+ return false;
60642
+ }
60643
+ const startsNewPhase = progress !== undefined && state.lastProgress !== undefined && progress < state.lastProgress;
60644
+ if (!isBoundary && !startsNewPhase && currentTime - state.lastEmittedAt < intervalMs) {
60645
+ return false;
60646
+ }
60647
+ stateByType.set(key, { lastEmittedAt: currentTime, lastProgress: progress });
60648
+ return true;
60649
+ };
60650
+ };
60651
+
60622
60652
  const Log = getLogger(exports.LoggerNames.Core);
60623
60653
  const PRE_INITIALIZE_TTL_MS = 60 * 1000;
60624
60654
  const preWarmInflight = new Map();
@@ -60684,7 +60714,12 @@ const callAPI = (context, message) => __awaiter(void 0, void 0, void 0, function
60684
60714
  try {
60685
60715
  method = findMethod(message);
60686
60716
  method.connector = _connector;
60687
- method.postMessage = postMessage;
60717
+ const shouldPostMessage = createUiProgressMessageFilter();
60718
+ method.postMessage = event => {
60719
+ if (shouldPostMessage(event)) {
60720
+ postMessage(event);
60721
+ }
60722
+ };
60688
60723
  (_a = method.setContext) === null || _a === void 0 ? void 0 : _a.call(method, context);
60689
60724
  method.requestContext = createRequestContext(method.responseID, method.name, {
60690
60725
  sdkInstanceId: context.sdkInstanceId,
@@ -60871,7 +60906,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
60871
60906
  }
60872
60907
  yield waitForPendingPromise(getPrePendingCallPromise, setPrePendingCallPromise);
60873
60908
  const inner = () => __awaiter(void 0, void 0, void 0, function* () {
60874
- var _j, _k, _l, _m, _o, _p, _q;
60909
+ var _j, _k;
60875
60910
  method.assertProtocolSupported(device.getProtocol(), device.getCurrentFirmwareType());
60876
60911
  const versionRange = device.getCurrentMethodVersionRange(type => method.getVersionRange()[type]);
60877
60912
  const currentFirmwareVersion = (_j = device.getCurrentFirmwareVersionString()) !== null && _j !== void 0 ? _j : '0.0.0';
@@ -60940,48 +60975,60 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
60940
60975
  }
60941
60976
  return Promise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceUnexpectedMode, unexpectedMode));
60942
60977
  }
60943
- if (method.deviceId && method.checkDeviceId) {
60944
- const isSameDeviceID = yield checkLiveDeviceId(device, method.deviceId);
60945
- if (!isSameDeviceID) {
60946
- return Promise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError));
60947
- }
60948
- }
60949
- method.checkFirmwareRelease();
60950
- method.checkDeviceSupportFeature();
60951
- if (_deviceList && device.features && !device.isProtocolV2()) {
60952
- yield TransportManager.reconfigure(device.features);
60953
- }
60954
- checkPassphraseEnableState(method, device.features);
60955
- if (shouldCheckPassphraseState(method, device)) {
60956
- const support = device.supportNewPassphrase();
60957
- if (!support.support) {
60958
- return Promise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportPassphrase, `Device not support passphrase, please update to ${support.require}`, {
60959
- require: support.require,
60960
- }));
60961
- }
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));
60964
- checkPassphraseEnableState(method, device.features);
60965
- if (!passphraseStateSafety) {
60966
- DevicePool.clearDeviceCache(method.payload.connectId);
60967
- return Promise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError));
60968
- }
60969
- if (!device.isProtocolV2()) {
60970
- postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
60971
- }
60972
- }
60973
- try {
60974
- yield method.checkSafetyLevelOnTestNet();
60975
- }
60976
- catch (e) {
60977
- const error = e instanceof hdShared.HardwareError
60978
- ? e
60979
- : hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'open safety check failed.');
60980
- throw error;
60981
- }
60982
- (_q = (_p = method.device) === null || _p === void 0 ? void 0 : _p.commands) === null || _q === void 0 ? void 0 : _q.checkDisposed();
60983
60978
  try {
60984
- const response = yield runMethodWithUnlockRetry(method, device, protocolV2UiCoordinator);
60979
+ let deviceIdCheckedDuringUnlockPreflight = false;
60980
+ const response = yield runMethodWithUnlockPolicy(method, device, {
60981
+ uiCoordinator: protocolV2UiCoordinator,
60982
+ afterStatusBeforeUnlock: () => {
60983
+ if (method.deviceId && method.checkDeviceId) {
60984
+ if (!device.checkDeviceId(method.deviceId)) {
60985
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
60986
+ }
60987
+ deviceIdCheckedDuringUnlockPreflight = true;
60988
+ }
60989
+ },
60990
+ prepare: () => __awaiter(void 0, void 0, void 0, function* () {
60991
+ var _l, _m, _o, _p, _q;
60992
+ if (method.deviceId && method.checkDeviceId && !deviceIdCheckedDuringUnlockPreflight) {
60993
+ const isSameDeviceID = yield checkLiveDeviceId(device, method.deviceId);
60994
+ if (!isSameDeviceID) {
60995
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
60996
+ }
60997
+ }
60998
+ method.checkFirmwareRelease();
60999
+ method.checkDeviceSupportFeature();
61000
+ if (_deviceList && device.features && !device.isProtocolV2()) {
61001
+ yield TransportManager.reconfigure(device.features);
61002
+ }
61003
+ checkPassphraseEnableState(method, device.features);
61004
+ if (shouldCheckPassphraseState(method, device)) {
61005
+ const support = device.supportNewPassphrase();
61006
+ if (!support.support) {
61007
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportPassphrase, `Device not support passphrase, please update to ${support.require}`, {
61008
+ require: support.require,
61009
+ });
61010
+ }
61011
+ 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));
61012
+ checkPassphraseEnableState(method, device.features);
61013
+ if (!passphraseStateSafety) {
61014
+ DevicePool.clearDeviceCache(method.payload.connectId);
61015
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckPassphraseStateError);
61016
+ }
61017
+ if (!device.isProtocolV2()) {
61018
+ postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
61019
+ }
61020
+ }
61021
+ try {
61022
+ yield method.checkSafetyLevelOnTestNet();
61023
+ }
61024
+ catch (e) {
61025
+ throw e instanceof hdShared.HardwareError
61026
+ ? e
61027
+ : hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'open safety check failed.');
61028
+ }
61029
+ (_q = (_p = method.device) === null || _p === void 0 ? void 0 : _p.commands) === null || _q === void 0 ? void 0 : _q.checkDisposed();
61030
+ }),
61031
+ });
60985
61032
  messageResponse = createResponseMessage(method.responseID, true, response);
60986
61033
  requestQueue.resolveRequest(method.responseID, messageResponse);
60987
61034
  completeMethodRequestContext(method);
@@ -61820,6 +61867,7 @@ exports.getLog = getLog;
61820
61867
  exports.getLogBlockLabel = getLogBlockLabel;
61821
61868
  exports.getLogger = getLogger;
61822
61869
  exports.getMethodVersionRange = getMethodVersionRange;
61870
+ exports.getNftSize = getNftSize;
61823
61871
  exports.getOutputScriptType = getOutputScriptType;
61824
61872
  exports.getSDKVersion = getSDKVersion;
61825
61873
  exports.getSafeLogPayload = getSafeLogPayload;