@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.
- package/CHANGELOG.md +29 -11
- package/README.md +1 -1
- package/lib/api/applyFlags.js +1 -0
- package/lib/api/applySettings.js +1 -0
- package/lib/api/authenticateDevice.js +1 -0
- package/lib/api/backupDevice.js +1 -0
- package/lib/api/bitcoin/signtxVerify.d.ts +10 -4
- package/lib/api/bitcoin/signtxVerify.js +23 -72
- package/lib/api/bleUnpair.js +1 -0
- package/lib/api/changeLanguage.js +1 -0
- package/lib/api/changePin.js +1 -0
- package/lib/api/changeWipeCode.js +1 -0
- package/lib/api/composeTransaction.js +15 -6
- package/lib/api/ethereum/api/ethereumSignTypedData.js +1 -1
- package/lib/api/firmware/uploadFirmware.js +5 -0
- package/lib/api/loadDevice.js +1 -0
- package/lib/api/recoveryDevice.js +1 -0
- package/lib/api/resetDevice.js +1 -0
- package/lib/api/setBrightness.js +1 -0
- package/lib/api/setBusy.js +1 -0
- package/lib/api/signTransaction.js +19 -6
- package/lib/api/wipeDevice.js +1 -0
- package/lib/constants/errors.d.ts +1 -0
- package/lib/constants/errors.js +1 -0
- package/lib/core/AbstractMethod.js +1 -1
- package/lib/core/onCallFirmwareUpdate.js +1 -3
- package/lib/data/DataManager.d.ts +2 -1
- package/lib/data/DataManager.js +7 -6
- package/lib/data/coinInfo.d.ts +0 -64
- package/lib/data/coinInfo.js +1 -40
- package/lib/data/firmwareInfo.d.ts +1 -1
- package/lib/data/firmwareInfo.js +5 -3
- package/lib/data/version.d.ts +1 -1
- package/lib/data/version.js +1 -1
- package/lib/device/Device.d.ts +10 -10
- package/lib/device/Device.js +53 -62
- package/lib/device/DeviceCurrentSession.d.ts +38 -1
- package/lib/device/DeviceCurrentSession.js +28 -4
- package/lib/device/DeviceList.js +23 -39
- package/lib/device/TransportList.d.ts +2 -2
- package/lib/device/thp/index.d.ts +3 -0
- package/lib/device/thp/index.js +11 -0
- package/lib/device/workflow/handshake.d.ts +10 -0
- package/lib/device/workflow/handshake.js +57 -0
- package/lib/events/index.d.ts +1 -0
- package/lib/events/ui-request.d.ts +6 -1
- package/lib/events/ui-request.js +1 -0
- package/lib/tsconfig.lib.tsbuildinfo +1 -1
- package/lib/utils/assetUtils.d.ts +2 -1
- package/lib/utils/assetUtils.js +2 -1
- package/lib/utils/firmwareReleaseConfigUtils.d.ts +7 -0
- package/lib/utils/firmwareReleaseConfigUtils.js +83 -0
- package/package.json +20 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,36 @@
|
|
|
1
|
-
| Package | Stable |
|
|
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 |
|
|
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.
|
|
3
|
+
API version 9.6.2-beta.2
|
|
4
4
|
|
|
5
5
|
[](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml)
|
|
6
6
|
[](https://www.npmjs.org/package/@trezor/connect)
|
package/lib/api/applyFlags.js
CHANGED
|
@@ -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 = {
|
package/lib/api/applySettings.js
CHANGED
|
@@ -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;
|
package/lib/api/backupDevice.js
CHANGED
|
@@ -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 {
|
|
4
|
-
type GetHDNode = ReturnType<typeof DeviceCommands>['getHDNode']
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
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.
|
|
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,
|
|
6
|
+
const derivePubKeyHash = async (getHDNode, address_n, network) => {
|
|
7
7
|
if (address_n.length === 5) {
|
|
8
|
-
const response = await getHDNode(
|
|
9
|
-
const node = utxo_lib_1.bip32.fromBase58(response.xpub,
|
|
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(
|
|
13
|
-
return utxo_lib_1.bip32.fromBase58(response.xpub,
|
|
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,
|
|
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,
|
|
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,
|
|
29
|
-
const payment = { hash: node.identifier, 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
|
|
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
|
-
|
|
56
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
81
|
+
exports.verifyTx = verifyTx;
|
|
131
82
|
//# sourceMappingURL=signtxVerify.js.map
|
package/lib/api/bleUnpair.js
CHANGED
|
@@ -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);
|
package/lib/api/changePin.js
CHANGED
|
@@ -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 } =
|
|
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,
|
|
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
|
|
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 =
|
|
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
|
-
|
|
260
|
-
|
|
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(() => {
|
package/lib/api/loadDevice.js
CHANGED
|
@@ -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);
|
package/lib/api/resetDevice.js
CHANGED
|
@@ -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);
|
package/lib/api/setBrightness.js
CHANGED
|
@@ -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);
|
package/lib/api/setBusy.js
CHANGED
|
@@ -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 =
|
|
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
|
|
232
|
-
outputs
|
|
244
|
+
inputs,
|
|
245
|
+
outputs,
|
|
233
246
|
});
|
|
234
247
|
}
|
|
235
248
|
if (params.push) {
|
|
236
|
-
(0, BlockchainLink_1.isBackendSupported)(
|
|
237
|
-
const blockchain = await (0, BlockchainLink_1.initBlockchain)(
|
|
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,
|
package/lib/api/wipeDevice.js
CHANGED
|
@@ -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";
|
package/lib/constants/errors.js
CHANGED
|
@@ -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 :
|
|
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
|
-
[
|
|
4
|
+
[K in AssetKeys]?: Record<string, any>;
|
|
4
5
|
};
|
|
5
6
|
export declare class DataManager {
|
|
6
7
|
static assets: AssetCollection;
|
package/lib/data/DataManager.js
CHANGED
|
@@ -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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
38
|
-
|
|
37
|
+
const modelReleases = this.assets[firmwareKey];
|
|
38
|
+
if (modelReleases) {
|
|
39
|
+
(0, firmwareInfo_1.parseFirmwareReleases)(modelReleases, modelType);
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
}
|