Skip to content

Commit 2b369e4

Browse files
[DDW-717] Update Trezor logic to cover upcoming breaking changes (#2629)
* [DDW-717] Intorduce Trezor logic improvement which covers Trezor firmware breaking changes * [DDW-717] Add signingMode (ordinary transaction) to the Trezor tx signing method * [DDW-717] Update trezor-connect to 8.1.30 BETA unreleased version and logic / params improvement * [DDW-717] Remove blake2b from yarn.lock * [DDW-717] Update storybook node version to 14.17.0 * [DDW-717] Downgrate netlify node version to 12.13.0 * [DDW-717] Change ieee754 yarn.lock entries * [DDW-717] Reverting yarn.lock ieee changes * [DDW-717] Update trezor-connect to unreleased 8.1.30-RC2 version * [DDW-717] Replace trezor-connect package with RC borc free pre-release version * [DDW-717] Update trezor-connect to the 8.1.30-beta.3 version * [DDW-717] Reverting trezor-connect package to the borc free RC * [DDW-717] Update netlify.toml node version * [DDW-717] Update trezor-connect to 8.1.30-beta.4 * [DDW-717] Revert changes to trezor-connect-v8.1.30-rc.2-tx-streaming-extended-borc-patch package * [DDW-717] Add cbor-web external * [DDW-717] Add cbor-web to webpack.config * [DDW-717] Add cbor-web to MacInstaller * [DDW-717] Remove cbor-web from externals Co-authored-by: Nikola Glumac <[email protected]>
1 parent ae19834 commit 2b369e4

File tree

11 files changed

+267
-135
lines changed

11 files changed

+267
-135
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Changelog
1717

1818
### Chores
1919

20+
- Covered Trezor firmware breaking changes ([PR 2629](https://github.com/input-output-hk/daedalus/pull/2629))
2021
- Updated `cardano-wallet` to revision `9ae2d48b` which enables hardware wallet support in Alonzo era ([PR 2663](https://github.com/input-output-hk/daedalus/issues/2663))
2122
- Updated `cardano-wallet` to version `2021-08-27` which includes `cardano-node` 1.29.0 ([PR 2650](https://github.com/input-output-hk/daedalus/pull/2650))
2223
- Updated `cardano-wallet` to version `2021-08-11` which includes `cardano-node` alonzo-purple-1.0.1 ([PR 2641](https://github.com/input-output-hk/daedalus/pull/2641))

installers/common/MacInstaller.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ buildElectronApp darwinConfig@DarwinConfig{dcAppName, dcAppNameApp} installerCon
282282
, "int64-buffer"
283283
, "call-bind"
284284
, "get-intrinsic"
285+
, "cbor-web"
285286
]
286287
mapM_ (\lib -> do
287288
cptree ("../node_modules" </> lib) ((fromText pathtoapp) </> "Contents/Resources/app/node_modules" </> lib)

netlify.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[build]
2-
environment = { YARN_VERSION = "1.22.4" }
2+
environment = { YARN_VERSION = "1.22.4", NODE_VERSION = "12.19.0" }

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@
245245
"source-map-support": "0.5.19",
246246
"spectron-fake-dialog": "0.0.1",
247247
"tcp-port-used": "1.0.1",
248-
"trezor-connect": "8.1.27-extended",
248+
"trezor-connect": "8.1.30-beta.4",
249249
"unorm": "1.6.0",
250250
"validator": "13.1.17"
251251
},

source/common/types/hardware-wallets.types.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ export type TrezorSignTransactionRequest = {
276276
reset?: boolean,
277277
devicePath: string,
278278
validityIntervalStartStr?: string,
279+
signingMode: number,
279280
auxiliaryData: ?TrezorAuxiliaryDataType,
280281
};
281282

@@ -289,11 +290,29 @@ export type LedgerSignTransactionResponse = {
289290
},
290291
};
291292

293+
export type TrezorWitness = {|
294+
type: number,
295+
pubKey: string,
296+
signature: string,
297+
chainCode: ?string,
298+
|};
299+
300+
export type TrezorSerializedTxPayload = {|
301+
serializedTx: string,
302+
|};
303+
304+
export type TrezorRawTxPayload = {
305+
witnesses: Array<TrezorWitness>,
306+
auxiliaryDataSupplement?: {
307+
type: number,
308+
auxiliaryDataHash: string,
309+
catalystSignature: string,
310+
},
311+
};
312+
292313
export type TrezorSignTransactionResponse = {
293314
success: boolean,
294-
payload: {
295-
serializedTx: string,
296-
},
315+
payload: TrezorSerializedTxPayload | TrezorRawTxPayload,
297316
};
298317

299318
export type HardwareWalletConnectionRequest = {

source/main/ipc/getHardwareWalletChannel.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,7 @@ export const handleHardwareWalletRequests = async (
741741
validityIntervalStartStr,
742742
withdrawals,
743743
auxiliaryData,
744+
signingMode,
744745
} = params;
745746

746747
if (!TrezorConnect) {
@@ -759,6 +760,7 @@ export const handleHardwareWalletRequests = async (
759760
withdrawals,
760761
validityIntervalStartStr,
761762
auxiliaryData,
763+
signingMode,
762764
};
763765
const signedTransaction = await TrezorConnect.cardanoSignTransaction({
764766
device: { path: devicePath },

source/renderer/app/stores/HardwareWalletsStore.js

Lines changed: 173 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
prepareTrezorCertificate,
5959
prepareTrezorWithdrawal,
6060
prepareTrezorAuxiliaryData,
61+
TrezorTransactionSigningMode,
6162
} from '../utils/shelleyTrezor';
6263
import {
6364
DeviceModels,
@@ -93,6 +94,7 @@ import type {
9394
HardwareWalletExtendedPublicKeyResponse,
9495
HardwareWalletConnectionRequest,
9596
Witness,
97+
TrezorWitness,
9698
} from '../../../common/types/hardware-wallets.types';
9799

98100
import { logger } from '../utils/logging';
@@ -1645,27 +1647,95 @@ export default class HardwareWalletsStore extends Store {
16451647
throw new Error(`Missing Coins Selection for wallet: ${walletId}`);
16461648
}
16471649

1648-
const { inputs, outputs, fee, certificates, withdrawals } = coinSelection;
1650+
const {
1651+
inputs,
1652+
outputs,
1653+
fee: flatFee,
1654+
certificates,
1655+
withdrawals,
1656+
} = coinSelection;
1657+
1658+
logger.debug('[HW-DEBUG] HWStore - sign transaction Trezor: ', {
1659+
walletId,
1660+
});
1661+
1662+
const hardwareWalletConnectionData = get(
1663+
this.hardwareWalletsConnectionData,
1664+
walletId
1665+
);
1666+
1667+
// Guard against potential null value
1668+
if (!hardwareWalletConnectionData)
1669+
throw new Error('Wallet not paired or Device not connected');
16491670

1671+
const publicKeyHex = get(hardwareWalletConnectionData, [
1672+
'extendedPublicKey',
1673+
'publicKeyHex',
1674+
]);
1675+
const chainCodeHex = get(hardwareWalletConnectionData, [
1676+
'extendedPublicKey',
1677+
'chainCodeHex',
1678+
]);
1679+
const xpubHex = `${publicKeyHex}${chainCodeHex}`;
1680+
1681+
const unsignedTxInputs = [];
16501682
const inputsData = map(inputs, (input) => {
1683+
const shelleyTxInput = ShelleyTxInputFromUtxo(input);
1684+
unsignedTxInputs.push(shelleyTxInput);
16511685
return prepareTrezorInput(input);
16521686
});
16531687

1654-
const outputsData = map(outputs, (output) => {
1655-
return prepareTrezorOutput(output);
1656-
});
1688+
const unsignedTxOutputs = [];
1689+
const outputsData = [];
1690+
for (const output of outputs) {
1691+
const {
1692+
address_style: addressStyle,
1693+
} = await this.stores.addresses._inspectAddress({
1694+
addressId: output.address,
1695+
});
1696+
const shelleyTxOutput = ShelleyTxOutput(output, addressStyle);
1697+
unsignedTxOutputs.push(shelleyTxOutput);
1698+
const ledgerOutput = prepareTrezorOutput(output);
1699+
outputsData.push(ledgerOutput);
1700+
}
16571701

1658-
const withdrawalsData = map(withdrawals, (withdrawal) => {
1659-
return prepareTrezorWithdrawal(withdrawal);
1702+
// Construct certificates
1703+
const unsignedTxCerts = [];
1704+
const _certificatesData = map(certificates, async (certificate) => {
1705+
const accountAddress = await this._getRewardAccountAddress(
1706+
walletId,
1707+
certificate.rewardAccountPath
1708+
);
1709+
const shelleyTxCert = ShelleyTxCert({
1710+
accountAddress,
1711+
pool: certificate.pool,
1712+
type: CERTIFICATE_TYPE[certificate.certificateType],
1713+
});
1714+
unsignedTxCerts.push(shelleyTxCert);
1715+
return prepareTrezorCertificate(certificate);
16601716
});
1717+
const certificatesData = await Promise.all(_certificatesData);
16611718

1662-
const certificatesData = map(certificates, (certificate) =>
1663-
prepareTrezorCertificate(certificate)
1719+
// Construct Withdrawals
1720+
const _withdrawalsData = map(withdrawals, async (withdrawal) =>
1721+
prepareTrezorWithdrawal(withdrawal)
16641722
);
1723+
const withdrawalsData = await Promise.all(_withdrawalsData);
16651724

1725+
let unsignedTxAuxiliaryData = null;
16661726
let auxiliaryData = null;
16671727
if (this.votingData) {
1668-
const { votingKey, nonce } = this.votingData;
1728+
const { stakeAddress, stakeKey, votingKey, nonce } = this.votingData;
1729+
unsignedTxAuxiliaryData = {
1730+
nonce, // unique increaseable number e.g. current epoch number or absolute slot number ( identifies unique tx / vote registration )
1731+
rewardDestinationAddress: {
1732+
address: stakeAddress,
1733+
stakingPath: [2147485500, 2147485463, 2147483648, 2, 0],
1734+
},
1735+
stakePubKey: stakeKey,
1736+
type: CATALYST_VOTING_REGISTRATION_TYPE,
1737+
votingPubKey: votingKey,
1738+
};
16691739
auxiliaryData = prepareTrezorAuxiliaryData({
16701740
votingKey,
16711741
nonce: nonce.toString(),
@@ -1715,15 +1785,16 @@ export default class HardwareWalletsStore extends Store {
17151785
});
17161786
}
17171787

1718-
const { isMainnet } = this.environment;
1788+
const fee = formattedAmountToLovelace(flatFee.toString());
17191789
const ttl = this._getTtl();
17201790
const absoluteSlotNumber = this._getAbsoluteSlotNumber();
1791+
const { isMainnet } = this.environment;
17211792

17221793
try {
17231794
const signedTransaction = await signTransactionTrezorChannel.request({
17241795
inputs: inputsData,
17251796
outputs: outputsData,
1726-
fee: formattedAmountToLovelace(fee.toString()).toString(),
1797+
fee: fee.toString(),
17271798
ttl: ttl.toString(),
17281799
validityIntervalStartStr: absoluteSlotNumber.toString(),
17291800
networkId: isMainnet
@@ -1735,21 +1806,78 @@ export default class HardwareWalletsStore extends Store {
17351806
certificates: certificatesData,
17361807
withdrawals: withdrawalsData,
17371808
devicePath: recognizedDevicePath,
1809+
signingMode: TrezorTransactionSigningMode.ORDINARY_TRANSACTION,
17381810
auxiliaryData,
17391811
});
17401812

1741-
if (!signedTransaction.success) {
1813+
if (signedTransaction && !signedTransaction.success) {
17421814
throw signedTransaction.payload;
17431815
}
1816+
// Compatible with old firmwares
1817+
const serializedTx = get(signedTransaction, ['payload', 'serializedTx']);
17441818

1745-
runInAction(
1746-
'HardwareWalletsStore:: transaction successfully signed',
1747-
() => {
1748-
this.txBody = signedTransaction.payload.serializedTx;
1749-
this.hwDeviceStatus =
1750-
HwDeviceStatuses.VERIFYING_TRANSACTION_SUCCEEDED;
1751-
}
1819+
if (serializedTx) {
1820+
runInAction(
1821+
'HardwareWalletsStore:: transaction successfully signed',
1822+
() => {
1823+
this.txBody = serializedTx;
1824+
this.hwDeviceStatus =
1825+
HwDeviceStatuses.VERIFYING_TRANSACTION_SUCCEEDED;
1826+
}
1827+
);
1828+
return;
1829+
}
1830+
1831+
const unsignedTxWithdrawals =
1832+
withdrawals.length > 0 ? ShelleyTxWithdrawal(withdrawals) : null;
1833+
1834+
// Prepare unsigned transaction structure for serialzation
1835+
let txAuxData = {
1836+
txInputs: unsignedTxInputs,
1837+
txOutputs: unsignedTxOutputs,
1838+
fee,
1839+
ttl,
1840+
certificates: unsignedTxCerts,
1841+
withdrawals: unsignedTxWithdrawals,
1842+
};
1843+
1844+
let txAuxiliaryData = null;
1845+
const auxiliaryDataSupplement = get(signedTransaction, [
1846+
'payload',
1847+
'auxiliaryDataSupplement',
1848+
]);
1849+
if (unsignedTxAuxiliaryData && auxiliaryDataSupplement) {
1850+
txAuxData = {
1851+
...txAuxData,
1852+
txAuxiliaryData: unsignedTxAuxiliaryData,
1853+
txAuxiliaryDataHash: auxiliaryDataSupplement.auxiliaryDataHash,
1854+
};
1855+
txAuxiliaryData = cborizeTxAuxiliaryVotingData(
1856+
unsignedTxAuxiliaryData,
1857+
auxiliaryDataSupplement.catalystSignature
1858+
);
1859+
}
1860+
1861+
const unsignedTx = prepareTxAux(txAuxData);
1862+
const witnesses = get(signedTransaction, ['payload', 'witnesses'], []);
1863+
const signedWitnesses = await this._signWitnesses(witnesses, xpubHex);
1864+
const txWitnesses = new Map();
1865+
if (signedWitnesses.length > 0) {
1866+
txWitnesses.set(0, signedWitnesses);
1867+
}
1868+
1869+
// Prepare serialized transaction with unsigned data and signed witnesses
1870+
const txBody = await prepareBody(
1871+
unsignedTx,
1872+
txWitnesses,
1873+
txAuxiliaryData
17521874
);
1875+
1876+
runInAction('HardwareWalletsStore:: set Transaction verified', () => {
1877+
this.hwDeviceStatus = HwDeviceStatuses.VERIFYING_TRANSACTION_SUCCEEDED;
1878+
this.txBody = txBody;
1879+
this.activeDevicePath = null;
1880+
});
17531881
} catch (error) {
17541882
runInAction(
17551883
'HardwareWalletsStore:: set Transaction verifying failed',
@@ -1758,15 +1886,17 @@ export default class HardwareWalletsStore extends Store {
17581886
this.isTransactionInitiated = false;
17591887
}
17601888
);
1761-
// @TODO - Maybe we should handle this case as separated message in tx dialog
17621889
if (error.code === 'Device_CallInProgress') {
17631890
throw new Error('Device is busy - reconnect device and try again');
17641891
}
17651892
throw error;
17661893
}
17671894
};
17681895

1769-
_signWitnesses = async (witnesses: Array<Witness>, xpubHex: string) => {
1896+
_signWitnesses = async (
1897+
witnesses: Array<TrezorWitness | Witness>,
1898+
xpubHex: string
1899+
) => {
17701900
const signedWitnesses = [];
17711901
for (const witness of witnesses) {
17721902
const signedWitness = await this.ShelleyWitness(witness, xpubHex);
@@ -1775,11 +1905,25 @@ export default class HardwareWalletsStore extends Store {
17751905
return signedWitnesses;
17761906
};
17771907

1778-
ShelleyWitness = async (witness: Witness, xpubHex: string) => {
1779-
const xpub = await this._deriveXpub(witness.path, xpubHex);
1780-
const publicKey = xpub.slice(0, 32);
1781-
const signature = Buffer.from(witness.witnessSignatureHex, 'hex');
1782-
return ShelleyTxWitnessShelley(publicKey, signature);
1908+
ShelleyWitness = async (
1909+
witness: TrezorWitness | Witness,
1910+
xpubHex: string
1911+
) => {
1912+
let publicKey;
1913+
let witnessSignatureHex;
1914+
if (witness.pubKey && witness.signature) {
1915+
publicKey = Buffer.from(witness.pubKey, 'hex');
1916+
witnessSignatureHex = witness.signature;
1917+
} else if (witness.path && witness.witnessSignatureHex) {
1918+
const xpub = await this._deriveXpub(witness.path, xpubHex);
1919+
publicKey = xpub.slice(0, 32);
1920+
witnessSignatureHex = witness.witnessSignatureHex;
1921+
}
1922+
if (witnessSignatureHex && publicKey) {
1923+
const signature = Buffer.from(witnessSignatureHex, 'hex');
1924+
return ShelleyTxWitnessShelley(publicKey, signature);
1925+
}
1926+
return null;
17831927
};
17841928

17851929
_deriveXpub = CachedDeriveXpubFactory(async (xpubHex) => {
@@ -1944,6 +2088,7 @@ export default class HardwareWalletsStore extends Store {
19442088
let txAuxiliaryData = null;
19452089
if (
19462090
unsignedTxAuxiliaryData &&
2091+
signedTransaction &&
19472092
signedTransaction.auxiliaryDataSupplement
19482093
) {
19492094
txAuxData = {
@@ -1961,10 +2106,8 @@ export default class HardwareWalletsStore extends Store {
19612106

19622107
const unsignedTx = prepareTxAux(txAuxData);
19632108

1964-
const signedWitnesses = await this._signWitnesses(
1965-
signedTransaction.witnesses,
1966-
xpubHex
1967-
);
2109+
const witnesses = get(signedTransaction, 'witnesses', []);
2110+
const signedWitnesses = await this._signWitnesses(witnesses, xpubHex);
19682111
const txWitnesses = new Map();
19692112
if (signedWitnesses.length > 0) {
19702113
txWitnesses.set(0, signedWitnesses);

source/renderer/app/utils/shelleyLedger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const derivationScheme = {
104104

105105
// Constructors
106106
export const ShelleyTxWitnessShelley = (
107-
publicKey: string,
107+
publicKey: Buffer,
108108
signature: Buffer
109109
) => {
110110
function encodeCBOR(encoder: any) {

0 commit comments

Comments
 (0)