@trezor/connect 9.6.1 → 9.6.2-beta.2

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 (53) hide show
  1. package/CHANGELOG.md +29 -11
  2. package/README.md +1 -1
  3. package/lib/api/applyFlags.js +1 -0
  4. package/lib/api/applySettings.js +1 -0
  5. package/lib/api/authenticateDevice.js +1 -0
  6. package/lib/api/backupDevice.js +1 -0
  7. package/lib/api/bitcoin/signtxVerify.d.ts +10 -4
  8. package/lib/api/bitcoin/signtxVerify.js +23 -72
  9. package/lib/api/bleUnpair.js +1 -0
  10. package/lib/api/changeLanguage.js +1 -0
  11. package/lib/api/changePin.js +1 -0
  12. package/lib/api/changeWipeCode.js +1 -0
  13. package/lib/api/composeTransaction.js +15 -6
  14. package/lib/api/ethereum/api/ethereumSignTypedData.js +1 -1
  15. package/lib/api/firmware/uploadFirmware.js +5 -0
  16. package/lib/api/loadDevice.js +1 -0
  17. package/lib/api/recoveryDevice.js +1 -0
  18. package/lib/api/resetDevice.js +1 -0
  19. package/lib/api/setBrightness.js +1 -0
  20. package/lib/api/setBusy.js +1 -0
  21. package/lib/api/signTransaction.js +19 -6
  22. package/lib/api/wipeDevice.js +1 -0
  23. package/lib/constants/errors.d.ts +1 -0
  24. package/lib/constants/errors.js +1 -0
  25. package/lib/core/AbstractMethod.js +1 -1
  26. package/lib/core/onCallFirmwareUpdate.js +1 -3
  27. package/lib/data/DataManager.d.ts +2 -1
  28. package/lib/data/DataManager.js +7 -6
  29. package/lib/data/coinInfo.d.ts +0 -64
  30. package/lib/data/coinInfo.js +1 -40
  31. package/lib/data/firmwareInfo.d.ts +1 -1
  32. package/lib/data/firmwareInfo.js +5 -3
  33. package/lib/data/version.d.ts +1 -1
  34. package/lib/data/version.js +1 -1
  35. package/lib/device/Device.d.ts +10 -10
  36. package/lib/device/Device.js +53 -62
  37. package/lib/device/DeviceCurrentSession.d.ts +38 -1
  38. package/lib/device/DeviceCurrentSession.js +28 -4
  39. package/lib/device/DeviceList.js +23 -39
  40. package/lib/device/TransportList.d.ts +2 -2
  41. package/lib/device/thp/index.d.ts +3 -0
  42. package/lib/device/thp/index.js +11 -0
  43. package/lib/device/workflow/handshake.d.ts +10 -0
  44. package/lib/device/workflow/handshake.js +57 -0
  45. package/lib/events/index.d.ts +1 -0
  46. package/lib/events/ui-request.d.ts +6 -1
  47. package/lib/events/ui-request.js +1 -0
  48. package/lib/tsconfig.lib.tsbuildinfo +1 -1
  49. package/lib/utils/assetUtils.d.ts +2 -1
  50. package/lib/utils/assetUtils.js +2 -1
  51. package/lib/utils/firmwareReleaseConfigUtils.d.ts +7 -0
  52. package/lib/utils/firmwareReleaseConfigUtils.js +83 -0
  53. package/package.json +20 -17
package/CHANGELOG.md CHANGED
@@ -1,16 +1,36 @@
1
- | Package | Stable | Canary |
2
- | :------------------------------: | :----: | :----: |
3
- | npm @trezor/connect | 9.6.1 | - |
4
- | npm @trezor/connect-web | 9.6.1 | - |
5
- | npm @trezor/connect-webextension | 9.6.1 | - |
6
- | npm @trezor/connect-mobile | 9.6.1 | - |
1
+ | Package | Stable | Canary |
2
+ | :------------------------------: | :----: | :----------: |
3
+ | npm @trezor/connect | 9.6.1 | 9.6.2-beta.2 |
4
+ | npm @trezor/connect-web | 9.6.1 | 9.6.2-beta.2 |
5
+ | npm @trezor/connect-webextension | 9.6.1 | 9.6.2-beta.2 |
6
+ | npm @trezor/connect-mobile | 9.6.1 | 9.6.2-beta.2 |
7
7
 
8
- | Deployment | Stable | Canary |
9
- | :----------------: | :----: | :----: |
10
- | connect.trezor.io/ | 9.6.1 | - |
8
+ | Deployment | Stable | Canary |
9
+ | :----------------: | :----: | :----------: |
10
+ | connect.trezor.io/ | 9.6.1 | 9.6.2-beta.2 |
11
11
 
12
12
  Use the persistent link [connect.trezor.io/9](https://connect.trezor.io/9/) to access the latest stable version of Connect Explorer.
13
13
 
14
+ # 9.6.2-beta.2
15
+
16
+ This release is important for smooth support of 2.9.0 trezor firmware, namely commits:
17
+
18
+ - feat(connect): change default for skipFinalReload (86d982e)
19
+ - feat(connect): reorganize order of getHDNode and SingTx calls; remove decred verification (906d835)
20
+
21
+ Improvement of ethereumSignTypedData
22
+
23
+ - fix(connect): button request data in ethereumSignTypedData (a0a2f1c)
24
+
25
+ Other than that only refactorings and chores are present:
26
+
27
+ - refactor(connect): improved pendingTransportEvent (f965980)
28
+ - refactor(connect): add devices after handshake (da4893b)
29
+ - refactor(connect): lifecycle changed to emitter (742d1c1)
30
+ - feat(connect): included bundled releases (8230255)
31
+ - fix(connect-common): reduce bsc block time (90e2b55)
32
+ - feat(connect): create THP devices in handshake process (5f07f57)
33
+
14
34
  # 9.6.1
15
35
 
16
36
  Minor improvements and fixes regarding the [New Connect flow in Trezor Suite](https://connect.trezor.io/9/guides/new-connect-flow-in-trezor-suite/).
@@ -426,14 +446,12 @@ If you are still seeing issues with USB types, please add `w3c-web-usb` to your
426
446
  - Fixing an issue with typescript not being able to resolve @sinclair/typebox and USB types correctly (98d6437)
427
447
  - Fixing regression that made it impossible to acquire (steal) device session over webusb (5cf83b4)
428
448
  - Couple of other fixes and improvements of device handling:
429
-
430
449
  - fix(connect): pending transport event fix (231899f)
431
450
  - fix(connect): DeviceList create devices sequentially (b4a915b)
432
451
  - chore(connect): use cancelableAction instead of \_cancelableRequestBySend (66c9beb)
433
452
  - fix(connect): Device prompts cancel action (pin, word, passphrase) (e8257f4)
434
453
 
435
454
  - Connect Explorer fixes:
436
-
437
455
  - fix(connect-explorer): icons on index page (fef3791)
438
456
  - fix(connect-explorer): Button as Link not working (d788a06)
439
457
  - chore(connect-explorer): improve fallback schema illustration (d0619b7)
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @trezor/connect
2
2
 
3
- API version 9.6.1
3
+ API version 9.6.2-beta.2
4
4
 
5
5
  [![Build Status](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml/badge.svg)](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml)
6
6
  [![NPM](https://img.shields.io/npm/v/@trezor/connect.svg)](https://www.npmjs.org/package/@trezor/connect)
@@ -7,6 +7,7 @@ class ApplyFlags extends AbstractMethod_1.AbstractMethod {
7
7
  init() {
8
8
  this.requiredPermissions = ['management'];
9
9
  this.useDeviceState = false;
10
+ this.skipFinalReload = false;
10
11
  const { payload } = this;
11
12
  (0, schema_utils_1.Assert)(constants_1.PROTO.ApplyFlags, payload);
12
13
  this.params = {
@@ -7,6 +7,7 @@ class ApplySettings extends AbstractMethod_1.AbstractMethod {
7
7
  init() {
8
8
  this.requiredPermissions = ['management'];
9
9
  this.useDeviceState = false;
10
+ this.skipFinalReload = false;
10
11
  const { payload } = this;
11
12
  (0, schema_utils_1.Assert)(applySettings_1.ApplySettings, payload);
12
13
  this.params = {
@@ -12,6 +12,7 @@ class AuthenticateDevice extends AbstractMethod_1.AbstractMethod {
12
12
  this.useEmptyPassphrase = true;
13
13
  this.allowDeviceMode = [events_1.UI.INITIALIZE, events_1.UI.SEEDLESS];
14
14
  this.requiredPermissions = ['management'];
15
+ this.skipFinalReload = false;
15
16
  this.useDeviceState = false;
16
17
  this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, null, this.firmwareRange);
17
18
  const { payload } = this;
@@ -6,6 +6,7 @@ const AbstractMethod_1 = require("../core/AbstractMethod");
6
6
  class BackupDevice extends AbstractMethod_1.AbstractMethod {
7
7
  init() {
8
8
  this.requiredPermissions = ['management'];
9
+ this.skipFinalReload = false;
9
10
  this.useDeviceState = false;
10
11
  const { payload } = this;
11
12
  (0, schema_utils_1.Assert)(constants_1.PROTO.BackupDevice, payload);
@@ -1,8 +1,14 @@
1
+ import { Transaction as BitcoinJsTransaction } from '@trezor/utxo-lib';
1
2
  import { PROTO } from '../../constants';
2
3
  import type { DeviceCommands } from '../../device/DeviceCommands';
3
- import type { BitcoinNetworkInfo } from '../../types';
4
- type GetHDNode = ReturnType<typeof DeviceCommands>['getHDNode'];
5
- export declare const verifyTx: (getHDNode: GetHDNode, inputs: PROTO.TxInputType[], outputs: PROTO.TxOutputType[], serializedTx: string, coinInfo: BitcoinNetworkInfo, unlockPath?: PROTO.UnlockPath) => Promise<import("@trezor/utxo-lib/lib/transaction/base").TransactionBase<undefined> | import("@trezor/utxo-lib/lib/transaction/base").TransactionBase<import("@trezor/utxo-lib/lib/transaction/dash").DashSpecific> | import("@trezor/utxo-lib/lib/transaction/base").TransactionBase<import("@trezor/utxo-lib/lib/transaction/zcash").ZcashSpecific>>;
6
- export declare const verifyTicketTx: (getHDNode: GetHDNode, inputs: PROTO.TxInputType[], outputs: PROTO.TxOutputType[], serializedTx: string, coinInfo: BitcoinNetworkInfo) => Promise<void>;
4
+ import type { Network } from '../../types';
5
+ type GetHDNode = (address_n: number[]) => ReturnType<ReturnType<typeof DeviceCommands>['getHDNode']>;
6
+ export declare const deriveOutputScript: (getHDNode: GetHDNode, output: PROTO.TxOutputType, network: Network) => Promise<Buffer<ArrayBufferLike> | undefined>;
7
+ export declare const verifyTx: (serializedTx: string, params: {
8
+ inputs: PROTO.TxInputType[];
9
+ outputs: PROTO.TxOutputType[];
10
+ outputScripts: Awaited<ReturnType<typeof deriveOutputScript>>[];
11
+ network: Network;
12
+ }) => BitcoinJsTransaction;
7
13
  export {};
8
14
  //# sourceMappingURL=signtxVerify.d.ts.map
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyTicketTx = exports.verifyTx = void 0;
3
+ exports.verifyTx = exports.deriveOutputScript = void 0;
4
4
  const utxo_lib_1 = require("@trezor/utxo-lib");
5
5
  const constants_1 = require("../../constants");
6
- const derivePubKeyHash = async (getHDNode, address_n, coinInfo, unlockPath) => {
6
+ const derivePubKeyHash = async (getHDNode, address_n, network) => {
7
7
  if (address_n.length === 5) {
8
- const response = await getHDNode({ address_n: address_n.slice(0, 4) }, { coinInfo, unlockPath });
9
- const node = utxo_lib_1.bip32.fromBase58(response.xpub, coinInfo.network);
8
+ const response = await getHDNode(address_n.slice(0, 4));
9
+ const node = utxo_lib_1.bip32.fromBase58(response.xpub, network);
10
10
  return node.derive(address_n[address_n.length - 1]);
11
11
  }
12
- const response = await getHDNode({ address_n }, { coinInfo, unlockPath });
13
- return utxo_lib_1.bip32.fromBase58(response.xpub, coinInfo.network);
12
+ const response = await getHDNode(address_n);
13
+ return utxo_lib_1.bip32.fromBase58(response.xpub, network);
14
14
  };
15
- const deriveOutputScript = async (getHDNode, output, coinInfo, unlockPath) => {
15
+ const deriveOutputScript = async (getHDNode, output, network) => {
16
16
  if ('multisig' in output)
17
17
  return;
18
18
  if ('op_return_data' in output) {
@@ -20,13 +20,13 @@ const deriveOutputScript = async (getHDNode, output, coinInfo, unlockPath) => {
20
20
  .output;
21
21
  }
22
22
  if (output.address) {
23
- return utxo_lib_1.address.toOutputScript(output.address, coinInfo.network);
23
+ return utxo_lib_1.address.toOutputScript(output.address, network);
24
24
  }
25
25
  if (!output.address_n) {
26
26
  throw constants_1.ERRORS.TypedError('Runtime', 'deriveOutputScript: Neither address or address_n is set');
27
27
  }
28
- const node = await derivePubKeyHash(getHDNode, output.address_n, coinInfo, unlockPath);
29
- const payment = { hash: node.identifier, network: coinInfo.network };
28
+ const node = await derivePubKeyHash(getHDNode, output.address_n, network);
29
+ const payment = { hash: node.identifier, network };
30
30
  if (output.script_type === 'PAYTOADDRESS') {
31
31
  return utxo_lib_1.payments.p2pkh(payment).output;
32
32
  }
@@ -44,7 +44,7 @@ const deriveOutputScript = async (getHDNode, output, coinInfo, unlockPath) => {
44
44
  if (output.script_type === 'PAYTOTAPROOT') {
45
45
  return utxo_lib_1.payments.p2tr({
46
46
  pubkey: node.publicKey,
47
- network: coinInfo.network,
47
+ network,
48
48
  }).output;
49
49
  }
50
50
  if (output.script_type === 'PAYTOMULTISIG') {
@@ -52,80 +52,31 @@ const deriveOutputScript = async (getHDNode, output, coinInfo, unlockPath) => {
52
52
  }
53
53
  throw constants_1.ERRORS.TypedError('Runtime', `deriveOutputScript: Unknown script type ${output.script_type}`);
54
54
  };
55
- const verifyTx = async (getHDNode, inputs, outputs, serializedTx, coinInfo, unlockPath) => {
56
- const bitcoinTx = utxo_lib_1.Transaction.fromHex(serializedTx, { network: coinInfo.network });
55
+ exports.deriveOutputScript = deriveOutputScript;
56
+ const verifyTx = (serializedTx, params) => {
57
+ const { inputs, outputs, outputScripts, network } = params;
58
+ const bitcoinTx = utxo_lib_1.Transaction.fromHex(serializedTx, { network });
57
59
  if (inputs.length !== bitcoinTx.ins.length) {
58
60
  throw constants_1.ERRORS.TypedError('Runtime', 'verifyTx: Signed transaction inputs invalid length');
59
61
  }
60
62
  if (outputs.length !== bitcoinTx.outs.length) {
61
63
  throw constants_1.ERRORS.TypedError('Runtime', 'verifyTx: Signed transaction outputs invalid length');
62
64
  }
63
- for (let i = 0; i < outputs.length; i++) {
64
- const scriptB = bitcoinTx.outs[i].script;
65
- if (outputs[i].amount) {
66
- const { amount } = outputs[i];
67
- if (amount.toString() !== bitcoinTx.outs[i].value) {
68
- throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Wrong output amount at output ${i}. Requested: ${amount}, signed: ${bitcoinTx.outs[i].value}`);
65
+ outputs.forEach((output, i) => {
66
+ if (output.amount) {
67
+ if (output.amount.toString() !== bitcoinTx.outs[i].value) {
68
+ throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Wrong output amount at output ${i}. Requested: ${output.amount}, signed: ${bitcoinTx.outs[i].value}`);
69
69
  }
70
70
  }
71
- const scriptA = await deriveOutputScript(getHDNode, outputs[i], coinInfo, unlockPath);
72
- if (scriptA && scriptA.compare(scriptB) !== 0) {
73
- throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Output ${i} scripts differ`);
74
- }
75
- }
76
- return bitcoinTx;
77
- };
78
- exports.verifyTx = verifyTx;
79
- const verifyTicketTx = async (getHDNode, inputs, outputs, serializedTx, coinInfo) => {
80
- const bitcoinTx = utxo_lib_1.Transaction.fromHex(serializedTx, { network: coinInfo.network });
81
- if (inputs.length !== bitcoinTx.ins.length) {
82
- throw constants_1.ERRORS.TypedError('Runtime', 'verifyTicketTx: Signed transaction inputs invalid length');
83
- }
84
- if (outputs.length !== bitcoinTx.outs.length || outputs.length !== 3) {
85
- throw constants_1.ERRORS.TypedError('Runtime', 'verifyTicketTx: Signed transaction outputs invalid length');
86
- }
71
+ });
87
72
  for (let i = 0; i < outputs.length; i++) {
88
73
  const scriptB = bitcoinTx.outs[i].script;
89
- const output = outputs[i];
90
- let scriptA;
91
- if (i === 0) {
92
- const { amount } = output;
93
- if (amount !== bitcoinTx.outs[i].value) {
94
- throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Wrong output amount at output ${i}. Requested: ${amount}, signed: ${bitcoinTx.outs[i].value}`);
95
- }
96
- scriptA = utxo_lib_1.payments.sstxpkh({
97
- address: output.address,
98
- network: coinInfo.network,
99
- }).output;
100
- }
101
- else if (i === 1) {
102
- if (output.address) {
103
- throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Output 1 should not have address.`);
104
- }
105
- if (!output.address_n) {
106
- throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Output 1 should have address_n.`);
107
- }
108
- const node = await derivePubKeyHash(getHDNode, output.address_n, coinInfo);
109
- scriptA = utxo_lib_1.payments.sstxcommitment({
110
- hash: node.identifier,
111
- amount: output.amount.toString(),
112
- network: coinInfo.network,
113
- }).output;
114
- }
115
- else {
116
- const { amount } = output;
117
- if (amount !== bitcoinTx.outs[i].value) {
118
- throw constants_1.ERRORS.TypedError('Runtime', `verifyTicketTx: Wrong output amount at output ${i}. Requested: ${amount}, signed: ${bitcoinTx.outs[i].value}`);
119
- }
120
- scriptA = utxo_lib_1.payments.sstxchange({
121
- address: output.address,
122
- network: coinInfo.network,
123
- }).output;
124
- }
74
+ const scriptA = outputScripts[i];
125
75
  if (scriptA && scriptA.compare(scriptB) !== 0) {
126
76
  throw constants_1.ERRORS.TypedError('Runtime', `verifyTx: Output ${i} scripts differ`);
127
77
  }
128
78
  }
79
+ return bitcoinTx;
129
80
  };
130
- exports.verifyTicketTx = verifyTicketTx;
81
+ exports.verifyTx = verifyTx;
131
82
  //# sourceMappingURL=signtxVerify.js.map
@@ -9,6 +9,7 @@ class BleUnpair extends AbstractMethod_1.AbstractMethod {
9
9
  init() {
10
10
  this.allowDeviceMode = [events_1.UI.INITIALIZE, events_1.UI.SEEDLESS];
11
11
  this.requiredPermissions = ['management'];
12
+ this.skipFinalReload = false;
12
13
  this.useDeviceState = false;
13
14
  this.skipFinalReload = true;
14
15
  const { payload } = this;
@@ -9,6 +9,7 @@ class ChangeLanguage extends AbstractMethod_1.AbstractMethod {
9
9
  this.allowDeviceMode = [events_1.UI.INITIALIZE, events_1.UI.SEEDLESS];
10
10
  this.useEmptyPassphrase = true;
11
11
  this.requiredPermissions = ['management'];
12
+ this.skipFinalReload = false;
12
13
  this.useDeviceState = false;
13
14
  const { payload } = this;
14
15
  (0, schema_utils_1.Assert)(changeLanguage_1.ChangeLanguage, payload);
@@ -7,6 +7,7 @@ class ChangePin extends AbstractMethod_1.AbstractMethod {
7
7
  init() {
8
8
  this.requiredPermissions = ['management'];
9
9
  this.useDeviceState = false;
10
+ this.skipFinalReload = false;
10
11
  const { payload } = this;
11
12
  (0, schema_utils_1.Assert)(constants_1.PROTO.ChangePin, payload);
12
13
  this.params = {
@@ -5,6 +5,7 @@ const paramsValidator_1 = require("./common/paramsValidator");
5
5
  class ChangeWipeCode extends AbstractMethod_1.AbstractMethod {
6
6
  init() {
7
7
  this.requiredPermissions = ['management'];
8
+ this.skipFinalReload = false;
8
9
  this.useDeviceState = false;
9
10
  const { payload } = this;
10
11
  (0, paramsValidator_1.validateParams)(payload, [{ name: 'remove', type: 'boolean' }]);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const bigNumber_1 = require("@trezor/utils/lib/bigNumber");
5
+ const promiseAllSequence_1 = require("@trezor/utils/lib/promiseAllSequence");
5
6
  const resolveAfter_1 = require("@trezor/utils/lib/resolveAfter");
6
7
  const BlockchainLink_1 = require("../backend/BlockchainLink");
7
8
  const constants_1 = require("../constants");
@@ -229,11 +230,12 @@ class ComposeTransaction extends AbstractMethod_1.AbstractMethod {
229
230
  }
230
231
  }
231
232
  async _sign(tx) {
233
+ const { device, params } = this;
232
234
  if (tx.type !== 'final')
233
235
  throw constants_1.ERRORS.TypedError('Runtime', 'ComposeTransaction: Trying to sign unfinished tx');
234
- const { coinInfo } = this.params;
236
+ const { coinInfo } = params;
235
237
  const options = (0, bitcoin_1.enhanceSignTx)({}, coinInfo);
236
- const inputs = tx.inputs.map(inp => (0, bitcoin_1.inputToTrezor)(inp, this.params.sequence));
238
+ const inputs = tx.inputs.map(inp => (0, bitcoin_1.inputToTrezor)(inp, params.sequence));
237
239
  const outputs = tx.outputs.map(bitcoin_1.outputToTrezor);
238
240
  let refTxs = [];
239
241
  const requiredRefTxs = (0, bitcoin_1.requireReferencedTransactions)(inputs, options, coinInfo);
@@ -244,10 +246,12 @@ class ComposeTransaction extends AbstractMethod_1.AbstractMethod {
244
246
  .then((0, bitcoin_1.parseTransactionHexes)(coinInfo.network))
245
247
  .then(bitcoin_1.transformReferencedTransactions);
246
248
  }
247
- const signTxMethod = !this.device.unavailableCapabilities.replaceTransaction
249
+ const getHDNode = (address_n) => device.getCommands().getHDNode({ address_n }, { coinInfo: params.coinInfo });
250
+ const outputScripts = await (0, promiseAllSequence_1.promiseAllSequence)(outputs.map(output => () => (0, bitcoin_1.deriveOutputScript)(getHDNode, output, coinInfo.network)));
251
+ const signTxMethod = !device.unavailableCapabilities.replaceTransaction
248
252
  ? bitcoin_1.signTx
249
253
  : bitcoin_1.signTxLegacy;
250
- const cmd = this.device.getCommands();
254
+ const cmd = device.getCommands();
251
255
  const response = await signTxMethod({
252
256
  typedCall: cmd.typedCall,
253
257
  inputs,
@@ -256,8 +260,13 @@ class ComposeTransaction extends AbstractMethod_1.AbstractMethod {
256
260
  options,
257
261
  coinInfo,
258
262
  });
259
- await (0, bitcoin_1.verifyTx)(cmd.getHDNode, inputs, outputs, response.serializedTx, coinInfo);
260
- if (this.params.push) {
263
+ (0, bitcoin_1.verifyTx)(response.serializedTx, {
264
+ inputs,
265
+ outputs,
266
+ outputScripts,
267
+ network: coinInfo.network,
268
+ });
269
+ if (params.push) {
261
270
  const blockchain = await this.getBlockchain();
262
271
  const txid = await blockchain.pushTransaction(response.serializedTx);
263
272
  return {
@@ -75,7 +75,7 @@ class EthereumSignTypedData extends AbstractMethod_1.AbstractMethod {
75
75
  return (0, ethereumUtils_1.getNetworkLabel)('Sign #NETWORK typed data', (0, coinInfo_1.getEthereumNetwork)(this.params.address_n));
76
76
  }
77
77
  getButtonRequestData(code) {
78
- if (code === 'ButtonRequest_Other') {
78
+ if (code === 'ButtonRequest_Other' || code === 'ButtonRequest_SignTx') {
79
79
  return {
80
80
  type: 'message',
81
81
  coin: this.params.network?.shortcut ?? 'ETH',
@@ -15,10 +15,15 @@ const postProgressMessage = (device, progress, postMessage) => {
15
15
  progress,
16
16
  }));
17
17
  };
18
+ const FIRMWARE_ERASE_TIMEOUT_MILLISECONDS = 15_000;
18
19
  const uploadFirmware = async (typedCall, postMessage, device, { payload }) => {
19
20
  if (device.features.major_version === 1) {
20
21
  postConfirmationMessage(device);
22
+ const timeoutId = setTimeout(() => {
23
+ postMessage((0, events_1.createUiMessage)(events_1.UI.FIRMWARE_PROGRESS_UNEXPECTED_DELAY, {}));
24
+ }, FIRMWARE_ERASE_TIMEOUT_MILLISECONDS);
21
25
  await typedCall('FirmwareErase', 'Success', {});
26
+ clearTimeout(timeoutId);
22
27
  postProgressMessage(device, 0, postMessage);
23
28
  let i = 0;
24
29
  const progressTimer = setInterval(() => {
@@ -10,6 +10,7 @@ class LoadDevice extends AbstractMethod_1.AbstractMethod {
10
10
  this.allowDeviceMode = [events_1.UI.INITIALIZE];
11
11
  this.useDeviceState = false;
12
12
  this.requiredPermissions = ['management'];
13
+ this.skipFinalReload = false;
13
14
  this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, null, this.firmwareRange);
14
15
  const { payload } = this;
15
16
  (0, schema_utils_1.Assert)(constants_1.PROTO.LoadDevice, payload);
@@ -7,6 +7,7 @@ const recoveryDevice_1 = require("../types/api/recoveryDevice");
7
7
  class RecoveryDevice extends AbstractMethod_1.AbstractMethod {
8
8
  init() {
9
9
  this.requiredPermissions = ['management'];
10
+ this.skipFinalReload = false;
10
11
  this.useEmptyPassphrase = true;
11
12
  const { payload } = this;
12
13
  (0, schema_utils_1.Assert)(recoveryDevice_1.RecoveryDevice, payload);
@@ -13,6 +13,7 @@ class ResetDevice extends AbstractMethod_1.AbstractMethod {
13
13
  this.allowDeviceMode = [events_1.UI.INITIALIZE, events_1.UI.SEEDLESS];
14
14
  this.useDeviceState = false;
15
15
  this.requiredPermissions = ['management'];
16
+ this.skipFinalReload = false;
16
17
  this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, null, this.firmwareRange);
17
18
  const { payload } = this;
18
19
  (0, schema_utils_1.Assert)(constants_1.PROTO.ResetDevice, payload);
@@ -6,6 +6,7 @@ const AbstractMethod_1 = require("../core/AbstractMethod");
6
6
  class SetBrightness extends AbstractMethod_1.AbstractMethod {
7
7
  init() {
8
8
  this.requiredPermissions = ['management'];
9
+ this.skipFinalReload = false;
9
10
  this.useDeviceState = false;
10
11
  const { payload } = this;
11
12
  (0, schema_utils_1.Assert)(constants_1.PROTO.SetBrightness, payload);
@@ -9,6 +9,7 @@ class SetBusy extends AbstractMethod_1.AbstractMethod {
9
9
  init() {
10
10
  this.useDeviceState = false;
11
11
  this.requiredPermissions = ['management'];
12
+ this.skipFinalReload = false;
12
13
  const { payload } = this;
13
14
  (0, schema_utils_1.Assert)(constants_1.PROTO.SetBusy, payload);
14
15
  this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, undefined, this.firmwareRange);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const bigNumber_1 = require("@trezor/utils/lib/bigNumber");
4
+ const promiseAllSequence_1 = require("@trezor/utils/lib/promiseAllSequence");
4
5
  const constants_1 = require("../constants");
5
6
  const bitcoin_1 = require("./bitcoin");
6
7
  const BlockchainLink_1 = require("../backend/BlockchainLink");
@@ -198,8 +199,16 @@ class SignTransaction extends AbstractMethod_1.AbstractMethod {
198
199
  }
199
200
  async run() {
200
201
  const { device, params } = this;
202
+ const { inputs, outputs, coinInfo } = params;
201
203
  const useLegacySignProcess = !!device.unavailableCapabilities.replaceTransaction;
202
204
  const refTxs = params.refTxs ?? (await this.fetchRefTxs(useLegacySignProcess));
205
+ let outputScripts = [];
206
+ if (params.options.serialize !== false) {
207
+ const getHDNode = (address_n) => device
208
+ .getCommands()
209
+ .getHDNode({ address_n }, { coinInfo, unlockPath: params.unlockPath });
210
+ outputScripts = await (0, promiseAllSequence_1.promiseAllSequence)(outputs.map(output => () => (0, bitcoin_1.deriveOutputScript)(getHDNode, output, coinInfo.network)));
211
+ }
203
212
  if (this.preauthorized) {
204
213
  await device.getCommands().preauthorize(true);
205
214
  }
@@ -217,10 +226,14 @@ class SignTransaction extends AbstractMethod_1.AbstractMethod {
217
226
  }
218
227
  let bitcoinTx;
219
228
  if (params.options.decred_staking_ticket) {
220
- await (0, bitcoin_1.verifyTicketTx)(device.getCommands().getHDNode, params.inputs, params.outputs, response.serializedTx, params.coinInfo);
221
229
  }
222
230
  else {
223
- bitcoinTx = await (0, bitcoin_1.verifyTx)(device.getCommands().getHDNode, params.inputs, params.outputs, response.serializedTx, params.coinInfo, params.unlockPath);
231
+ bitcoinTx = (0, bitcoin_1.verifyTx)(response.serializedTx, {
232
+ inputs,
233
+ outputs,
234
+ outputScripts,
235
+ network: coinInfo.network,
236
+ });
224
237
  if (bitcoinTx.hasWitnesses()) {
225
238
  response.witnesses = bitcoinTx.ins.map((_, i) => bitcoinTx?.getWitness(i)?.toString('hex'));
226
239
  }
@@ -228,13 +241,13 @@ class SignTransaction extends AbstractMethod_1.AbstractMethod {
228
241
  if (bitcoinTx && params.addresses) {
229
242
  response.signedTransaction = (0, bitcoin_1.createPendingTransaction)(bitcoinTx, {
230
243
  addresses: params.addresses,
231
- inputs: params.inputs,
232
- outputs: params.outputs,
244
+ inputs,
245
+ outputs,
233
246
  });
234
247
  }
235
248
  if (params.push) {
236
- (0, BlockchainLink_1.isBackendSupported)(params.coinInfo);
237
- const blockchain = await (0, BlockchainLink_1.initBlockchain)(params.coinInfo, this.postMessage, params.identity);
249
+ (0, BlockchainLink_1.isBackendSupported)(coinInfo);
250
+ const blockchain = await (0, BlockchainLink_1.initBlockchain)(coinInfo, this.postMessage, params.identity);
238
251
  const txid = await blockchain.pushTransaction(response.serializedTx);
239
252
  return {
240
253
  ...response,
@@ -8,6 +8,7 @@ class WipeDevice extends AbstractMethod_1.AbstractMethod {
8
8
  this.allowDeviceMode = [events_1.UI.INITIALIZE, events_1.UI.SEEDLESS, events_1.UI.BOOTLOADER];
9
9
  this.useDeviceState = false;
10
10
  this.requiredPermissions = ['management'];
11
+ this.skipFinalReload = false;
11
12
  this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, null, this.firmwareRange);
12
13
  }
13
14
  get confirmation() {
@@ -36,6 +36,7 @@ export declare const ERROR_CODES: {
36
36
  readonly Device_MissingCapability: "Device is missing capability";
37
37
  readonly Device_MissingCapabilityBtcOnly: "Device is missing capability (BTC only)";
38
38
  readonly Device_ThpPairingTagInvalid: "Pairing tag mismatch";
39
+ readonly Device_ThpStateMissing: "ThpState missing";
39
40
  readonly Failure_ActionCancelled: "Action cancelled by user";
40
41
  readonly Failure_FirmwareError: "Firmware installation failed";
41
42
  readonly Failure_UnknownCode: "Unknown error";
@@ -39,6 +39,7 @@ exports.ERROR_CODES = {
39
39
  Device_MissingCapability: 'Device is missing capability',
40
40
  Device_MissingCapabilityBtcOnly: 'Device is missing capability (BTC only)',
41
41
  Device_ThpPairingTagInvalid: 'Pairing tag mismatch',
42
+ Device_ThpStateMissing: 'ThpState missing',
42
43
  Failure_ActionCancelled: 'Action cancelled by user',
43
44
  Failure_FirmwareError: 'Firmware installation failed',
44
45
  Failure_UnknownCode: 'Unknown error',
@@ -94,7 +94,7 @@ class AbstractMethod {
94
94
  : false;
95
95
  this.keepSession = typeof payload.keepSession === 'boolean' ? payload.keepSession : false;
96
96
  this.skipFinalReload =
97
- typeof payload.skipFinalReload === 'boolean' ? payload.skipFinalReload : false;
97
+ typeof payload.skipFinalReload === 'boolean' ? payload.skipFinalReload : true;
98
98
  this.skipFirmwareCheck = false;
99
99
  this.overridePreviousCall =
100
100
  typeof payload.override === 'boolean' ? payload.override : false;
@@ -39,9 +39,7 @@ const waitForReconnectedDevice = async ({ bootloader, method, intermediary }, {
39
39
  }
40
40
  catch {
41
41
  }
42
- if (reconnectedDevice &&
43
- !reconnectedDevice.features &&
44
- reconnectedDevice.handshakeFinished) {
42
+ if (reconnectedDevice && !reconnectedDevice.features) {
45
43
  log.debug('onCallFirmwareUpdate', 'we were unable to read device.features on the first interaction after seeing it, retrying...');
46
44
  try {
47
45
  registerEvents(reconnectedDevice);
@@ -1,6 +1,7 @@
1
1
  import type { ConnectSettings, LocalFirmwares } from '../types/settings';
2
+ type AssetKeys = `firmware-${string}` | 'coins' | 'coinsEth';
2
3
  type AssetCollection = {
3
- [key: string]: Record<string, any>;
4
+ [K in AssetKeys]?: Record<string, any>;
4
5
  };
5
6
  export declare class DataManager {
6
7
  static assets: AssetCollection;
@@ -21,10 +21,10 @@ class DataManager {
21
21
  const assetsMap = {
22
22
  coins: coins_json_1.default,
23
23
  coinsEth: coins_eth_json_1.default,
24
- ...Object.fromEntries(Object.entries(assetUtils_1.firmwareAssets).map(([key, value]) => [
25
- `firmware-${key.toLowerCase()}`,
26
- value,
27
- ])),
24
+ ...Object.fromEntries(Object.entries(assetUtils_1.firmwareAssets).map(([key, value]) => {
25
+ const release = Array.isArray(value) ? value : [];
26
+ return [`firmware-${key.toLowerCase()}`, release];
27
+ })),
28
28
  };
29
29
  Object.assign(this.assets, assetsMap);
30
30
  (0, coinInfo_1.parseCoinsJson)({
@@ -34,8 +34,9 @@ class DataManager {
34
34
  for (const model in device_utils_1.DeviceModelInternal) {
35
35
  const firmwareKey = `firmware-${model.toLowerCase()}`;
36
36
  const modelType = device_utils_1.DeviceModelInternal[model];
37
- if (this.assets[firmwareKey]) {
38
- (0, firmwareInfo_1.parseFirmwareReleases)(this.assets[firmwareKey], modelType);
37
+ const modelReleases = this.assets[firmwareKey];
38
+ if (modelReleases) {
39
+ (0, firmwareInfo_1.parseFirmwareReleases)(modelReleases, modelType);
39
40
  }
40
41
  }
41
42
  }