@ledgerhq/hw-app-btc 10.0.1 → 10.0.2-next.0

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 (165) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/Btc.d.ts.map +1 -1
  3. package/lib/Btc.js +72 -97
  4. package/lib/Btc.js.map +1 -1
  5. package/lib/BtcNew.js +217 -313
  6. package/lib/BtcNew.js.map +1 -1
  7. package/lib/BtcOld.js +46 -106
  8. package/lib/BtcOld.js.map +1 -1
  9. package/lib/bip32.js +12 -12
  10. package/lib/bip32.js.map +1 -1
  11. package/lib/buffertools.js +66 -69
  12. package/lib/buffertools.js.map +1 -1
  13. package/lib/compressPublicKey.js +3 -3
  14. package/lib/compressPublicKey.js.map +1 -1
  15. package/lib/constants.js +1 -1
  16. package/lib/createTransaction.d.ts +1 -1
  17. package/lib/createTransaction.d.ts.map +1 -1
  18. package/lib/createTransaction.js +285 -398
  19. package/lib/createTransaction.js.map +1 -1
  20. package/lib/debug.js +11 -13
  21. package/lib/debug.js.map +1 -1
  22. package/lib/finalizeInput.js +23 -62
  23. package/lib/finalizeInput.js.map +1 -1
  24. package/lib/getAppAndVersion.d.ts +1 -1
  25. package/lib/getAppAndVersion.d.ts.map +1 -1
  26. package/lib/getAppAndVersion.js +29 -72
  27. package/lib/getAppAndVersion.js.map +1 -1
  28. package/lib/getTrustedInput.js +108 -251
  29. package/lib/getTrustedInput.js.map +1 -1
  30. package/lib/getTrustedInputBIP143.js +9 -10
  31. package/lib/getTrustedInputBIP143.js.map +1 -1
  32. package/lib/getWalletPublicKey.d.ts +1 -1
  33. package/lib/getWalletPublicKey.d.ts.map +1 -1
  34. package/lib/getWalletPublicKey.js +27 -73
  35. package/lib/getWalletPublicKey.js.map +1 -1
  36. package/lib/hashPublicKey.js +4 -4
  37. package/lib/hashPublicKey.js.map +1 -1
  38. package/lib/index.js +3 -3
  39. package/lib/index.js.map +1 -1
  40. package/lib/newops/accounttype.d.ts +2 -2
  41. package/lib/newops/accounttype.d.ts.map +1 -1
  42. package/lib/newops/accounttype.js +85 -125
  43. package/lib/newops/accounttype.js.map +1 -1
  44. package/lib/newops/appClient.js +98 -205
  45. package/lib/newops/appClient.js.map +1 -1
  46. package/lib/newops/clientCommands.js +122 -213
  47. package/lib/newops/clientCommands.js.map +1 -1
  48. package/lib/newops/merkelizedPsbt.js +28 -75
  49. package/lib/newops/merkelizedPsbt.js.map +1 -1
  50. package/lib/newops/merkle.js +38 -67
  51. package/lib/newops/merkle.js.map +1 -1
  52. package/lib/newops/merkleMap.js +11 -12
  53. package/lib/newops/merkleMap.js.map +1 -1
  54. package/lib/newops/policy.d.ts +1 -1
  55. package/lib/newops/policy.d.ts.map +1 -1
  56. package/lib/newops/policy.js +17 -18
  57. package/lib/newops/policy.js.map +1 -1
  58. package/lib/newops/psbtExtractor.js +9 -9
  59. package/lib/newops/psbtExtractor.js.map +1 -1
  60. package/lib/newops/psbtFinalizer.js +22 -22
  61. package/lib/newops/psbtFinalizer.js.map +1 -1
  62. package/lib/newops/psbtv2.d.ts +1 -1
  63. package/lib/newops/psbtv2.d.ts.map +1 -1
  64. package/lib/newops/psbtv2.js +227 -286
  65. package/lib/newops/psbtv2.js.map +1 -1
  66. package/lib/serializeTransaction.js +13 -15
  67. package/lib/serializeTransaction.js.map +1 -1
  68. package/lib/shouldUseTrustedInputForSegwit.js +4 -5
  69. package/lib/shouldUseTrustedInputForSegwit.js.map +1 -1
  70. package/lib/signMessage.js +47 -99
  71. package/lib/signMessage.js.map +1 -1
  72. package/lib/signP2SHTransaction.d.ts +1 -1
  73. package/lib/signP2SHTransaction.d.ts.map +1 -1
  74. package/lib/signP2SHTransaction.js +91 -187
  75. package/lib/signP2SHTransaction.js.map +1 -1
  76. package/lib/signTransaction.js +8 -9
  77. package/lib/signTransaction.js.map +1 -1
  78. package/lib/splitTransaction.js +50 -54
  79. package/lib/splitTransaction.js.map +1 -1
  80. package/lib/startUntrustedHashTransactionInput.js +65 -167
  81. package/lib/startUntrustedHashTransactionInput.js.map +1 -1
  82. package/lib/types.js +1 -1
  83. package/lib/varint.js +10 -10
  84. package/lib/varint.js.map +1 -1
  85. package/lib-es/Btc.d.ts.map +1 -1
  86. package/lib-es/Btc.js +58 -84
  87. package/lib-es/Btc.js.map +1 -1
  88. package/lib-es/BtcNew.js +205 -302
  89. package/lib-es/BtcNew.js.map +1 -1
  90. package/lib-es/BtcOld.js +35 -96
  91. package/lib-es/BtcOld.js.map +1 -1
  92. package/lib-es/bip32.js +7 -7
  93. package/lib-es/bip32.js.map +1 -1
  94. package/lib-es/buffertools.js +62 -67
  95. package/lib-es/buffertools.js.map +1 -1
  96. package/lib-es/compressPublicKey.js +2 -2
  97. package/lib-es/compressPublicKey.js.map +1 -1
  98. package/lib-es/constants.js +12 -12
  99. package/lib-es/constants.js.map +1 -1
  100. package/lib-es/createTransaction.d.ts +1 -1
  101. package/lib-es/createTransaction.d.ts.map +1 -1
  102. package/lib-es/createTransaction.js +271 -384
  103. package/lib-es/createTransaction.js.map +1 -1
  104. package/lib-es/debug.js +10 -12
  105. package/lib-es/debug.js.map +1 -1
  106. package/lib-es/finalizeInput.js +20 -59
  107. package/lib-es/finalizeInput.js.map +1 -1
  108. package/lib-es/getAppAndVersion.d.ts +1 -1
  109. package/lib-es/getAppAndVersion.d.ts.map +1 -1
  110. package/lib-es/getAppAndVersion.js +27 -70
  111. package/lib-es/getAppAndVersion.js.map +1 -1
  112. package/lib-es/getTrustedInput.js +104 -247
  113. package/lib-es/getTrustedInput.js.map +1 -1
  114. package/lib-es/getTrustedInputBIP143.js +5 -6
  115. package/lib-es/getTrustedInputBIP143.js.map +1 -1
  116. package/lib-es/getWalletPublicKey.d.ts +1 -1
  117. package/lib-es/getWalletPublicKey.d.ts.map +1 -1
  118. package/lib-es/getWalletPublicKey.js +25 -71
  119. package/lib-es/getWalletPublicKey.js.map +1 -1
  120. package/lib-es/newops/accounttype.d.ts +2 -2
  121. package/lib-es/newops/accounttype.d.ts.map +1 -1
  122. package/lib-es/newops/accounttype.js +79 -123
  123. package/lib-es/newops/accounttype.js.map +1 -1
  124. package/lib-es/newops/appClient.js +92 -200
  125. package/lib-es/newops/appClient.js.map +1 -1
  126. package/lib-es/newops/clientCommands.js +117 -214
  127. package/lib-es/newops/clientCommands.js.map +1 -1
  128. package/lib-es/newops/merkelizedPsbt.js +25 -73
  129. package/lib-es/newops/merkelizedPsbt.js.map +1 -1
  130. package/lib-es/newops/merkle.js +36 -66
  131. package/lib-es/newops/merkle.js.map +1 -1
  132. package/lib-es/newops/merkleMap.js +8 -10
  133. package/lib-es/newops/merkleMap.js.map +1 -1
  134. package/lib-es/newops/policy.d.ts +1 -1
  135. package/lib-es/newops/policy.d.ts.map +1 -1
  136. package/lib-es/newops/policy.js +12 -14
  137. package/lib-es/newops/policy.js.map +1 -1
  138. package/lib-es/newops/psbtExtractor.js +7 -7
  139. package/lib-es/newops/psbtExtractor.js.map +1 -1
  140. package/lib-es/newops/psbtFinalizer.js +19 -19
  141. package/lib-es/newops/psbtFinalizer.js.map +1 -1
  142. package/lib-es/newops/psbtv2.d.ts +1 -1
  143. package/lib-es/newops/psbtv2.d.ts.map +1 -1
  144. package/lib-es/newops/psbtv2.js +225 -286
  145. package/lib-es/newops/psbtv2.js.map +1 -1
  146. package/lib-es/serializeTransaction.js +11 -13
  147. package/lib-es/serializeTransaction.js.map +1 -1
  148. package/lib-es/shouldUseTrustedInputForSegwit.js +1 -2
  149. package/lib-es/shouldUseTrustedInputForSegwit.js.map +1 -1
  150. package/lib-es/signMessage.js +44 -96
  151. package/lib-es/signMessage.js.map +1 -1
  152. package/lib-es/signP2SHTransaction.d.ts +1 -1
  153. package/lib-es/signP2SHTransaction.d.ts.map +1 -1
  154. package/lib-es/signP2SHTransaction.js +84 -180
  155. package/lib-es/signP2SHTransaction.js.map +1 -1
  156. package/lib-es/signTransaction.js +6 -7
  157. package/lib-es/signTransaction.js.map +1 -1
  158. package/lib-es/splitTransaction.js +46 -50
  159. package/lib-es/splitTransaction.js.map +1 -1
  160. package/lib-es/startUntrustedHashTransactionInput.js +62 -164
  161. package/lib-es/startUntrustedHashTransactionInput.js.map +1 -1
  162. package/lib-es/varint.js +9 -9
  163. package/lib-es/varint.js.map +1 -1
  164. package/package.json +5 -6
  165. package/src/Btc.ts +28 -5
package/lib-es/BtcNew.js CHANGED
@@ -7,33 +7,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (_) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
10
  import { crypto } from "bitcoinjs-lib";
38
11
  import { pointCompress } from "tiny-secp256k1";
39
12
  import { getXpubComponents, hardenedPathOf, pathArrayToString, pathStringToArray, pubkeyFromXpub, } from "./bip32";
@@ -57,8 +30,8 @@ import { serializeTransaction } from "./serializeTransaction";
57
30
  * be developed that exposes PSBT to the outer world, which would render
58
31
  * a much cleaner implementation.
59
32
  */
60
- var BtcNew = /** @class */ (function () {
61
- function BtcNew(client) {
33
+ export default class BtcNew {
34
+ constructor(client) {
62
35
  this.client = client;
63
36
  }
64
37
  /**
@@ -91,26 +64,17 @@ var BtcNew = /** @class */ (function () {
91
64
  *
92
65
  * We opted for adding a new function, which can greatly simplify client code.
93
66
  */
94
- BtcNew.prototype.getWalletXpub = function (_a) {
95
- var path = _a.path, xpubVersion = _a.xpubVersion;
96
- return __awaiter(this, void 0, void 0, function () {
97
- var pathElements, xpub, xpubComponents;
98
- return __generator(this, function (_b) {
99
- switch (_b.label) {
100
- case 0:
101
- pathElements = pathStringToArray(path);
102
- return [4 /*yield*/, this.client.getExtendedPubkey(false, pathElements)];
103
- case 1:
104
- xpub = _b.sent();
105
- xpubComponents = getXpubComponents(xpub);
106
- if (xpubComponents.version != xpubVersion) {
107
- throw new Error("Expected xpub version ".concat(xpubVersion, " doesn't match the xpub version from the device ").concat(xpubComponents.version));
108
- }
109
- return [2 /*return*/, xpub];
110
- }
111
- });
67
+ getWalletXpub({ path, xpubVersion, }) {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ const pathElements = pathStringToArray(path);
70
+ const xpub = yield this.client.getExtendedPubkey(false, pathElements);
71
+ const xpubComponents = getXpubComponents(xpub);
72
+ if (xpubComponents.version != xpubVersion) {
73
+ throw new Error(`Expected xpub version ${xpubVersion} doesn't match the xpub version from the device ${xpubComponents.version}`);
74
+ }
75
+ return xpub;
112
76
  });
113
- };
77
+ }
114
78
  /**
115
79
  * This method returns a public key, a bitcoin address, and and a chaincode
116
80
  * for a specific derivation path.
@@ -118,35 +82,25 @@ var BtcNew = /** @class */ (function () {
118
82
  * Limitation: If the path is not a leaf node of a standard path, the address
119
83
  * will be the empty string "", see this.getWalletAddress() for details.
120
84
  */
121
- BtcNew.prototype.getWalletPublicKey = function (path, opts) {
85
+ getWalletPublicKey(path, opts) {
122
86
  var _a, _b;
123
- return __awaiter(this, void 0, void 0, function () {
124
- var pathElements, xpub, display, address, components, uncompressedPubkey;
125
- return __generator(this, function (_c) {
126
- switch (_c.label) {
127
- case 0:
128
- if (!isPathNormal(path)) {
129
- throw Error("non-standard path: ".concat(path));
130
- }
131
- pathElements = pathStringToArray(path);
132
- return [4 /*yield*/, this.client.getExtendedPubkey(false, pathElements)];
133
- case 1:
134
- xpub = _c.sent();
135
- display = (_a = opts === null || opts === void 0 ? void 0 : opts.verify) !== null && _a !== void 0 ? _a : false;
136
- return [4 /*yield*/, this.getWalletAddress(pathElements, descrTemplFrom((_b = opts === null || opts === void 0 ? void 0 : opts.format) !== null && _b !== void 0 ? _b : "legacy"), display)];
137
- case 2:
138
- address = _c.sent();
139
- components = getXpubComponents(xpub);
140
- uncompressedPubkey = Buffer.from(pointCompress(components.pubkey, false));
141
- return [2 /*return*/, {
142
- publicKey: uncompressedPubkey.toString("hex"),
143
- bitcoinAddress: address,
144
- chainCode: components.chaincode.toString("hex")
145
- }];
146
- }
147
- });
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ if (!isPathNormal(path)) {
89
+ throw Error(`non-standard path: ${path}`);
90
+ }
91
+ const pathElements = pathStringToArray(path);
92
+ const xpub = yield this.client.getExtendedPubkey(false, pathElements);
93
+ const display = (_a = opts === null || opts === void 0 ? void 0 : opts.verify) !== null && _a !== void 0 ? _a : false;
94
+ const address = yield this.getWalletAddress(pathElements, descrTemplFrom((_b = opts === null || opts === void 0 ? void 0 : opts.format) !== null && _b !== void 0 ? _b : "legacy"), display);
95
+ const components = getXpubComponents(xpub);
96
+ const uncompressedPubkey = Buffer.from(pointCompress(components.pubkey, false));
97
+ return {
98
+ publicKey: uncompressedPubkey.toString("hex"),
99
+ bitcoinAddress: address,
100
+ chainCode: components.chaincode.toString("hex"),
101
+ };
148
102
  });
149
- };
103
+ }
150
104
  /**
151
105
  * Get an address for the specified path.
152
106
  *
@@ -162,29 +116,19 @@ var BtcNew = /** @class */ (function () {
162
116
  * way to get the address from the device. In this case we have to create it
163
117
  * ourselves, but we don't at this time, and instead return an empty ("") address.
164
118
  */
165
- BtcNew.prototype.getWalletAddress = function (pathElements, descrTempl, display) {
166
- return __awaiter(this, void 0, void 0, function () {
167
- var accountPath, accountXpub, masterFingerprint, policy, changeAndIndex;
168
- return __generator(this, function (_a) {
169
- switch (_a.label) {
170
- case 0:
171
- accountPath = hardenedPathOf(pathElements);
172
- if (accountPath.length + 2 != pathElements.length) {
173
- return [2 /*return*/, ""];
174
- }
175
- return [4 /*yield*/, this.client.getExtendedPubkey(false, accountPath)];
176
- case 1:
177
- accountXpub = _a.sent();
178
- return [4 /*yield*/, this.client.getMasterFingerprint()];
179
- case 2:
180
- masterFingerprint = _a.sent();
181
- policy = new WalletPolicy(descrTempl, createKey(masterFingerprint, accountPath, accountXpub));
182
- changeAndIndex = pathElements.slice(-2, pathElements.length);
183
- return [2 /*return*/, this.client.getWalletAddress(policy, Buffer.alloc(32, 0), changeAndIndex[0], changeAndIndex[1], display)];
184
- }
185
- });
119
+ getWalletAddress(pathElements, descrTempl, display) {
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ const accountPath = hardenedPathOf(pathElements);
122
+ if (accountPath.length + 2 != pathElements.length) {
123
+ return "";
124
+ }
125
+ const accountXpub = yield this.client.getExtendedPubkey(false, accountPath);
126
+ const masterFingerprint = yield this.client.getMasterFingerprint();
127
+ const policy = new WalletPolicy(descrTempl, createKey(masterFingerprint, accountPath, accountXpub));
128
+ const changeAndIndex = pathElements.slice(-2, pathElements.length);
129
+ return this.client.getWalletAddress(policy, Buffer.alloc(32, 0), changeAndIndex[0], changeAndIndex[1], display);
186
130
  });
187
- };
131
+ }
188
132
  /**
189
133
  * Build and sign a transaction. See Btc.createPaymentTransaction for
190
134
  * details on how to use this method.
@@ -193,111 +137,97 @@ var BtcNew = /** @class */ (function () {
193
137
  * a psbt which is finally signed and finalized, and the extracted fully signed
194
138
  * transaction is returned.
195
139
  */
196
- BtcNew.prototype.createPaymentTransaction = function (arg) {
197
- return __awaiter(this, void 0, void 0, function () {
198
- var inputCount, psbt, masterFp, accountType, notifyCount, progress, accountXpub, accountPath, i, pathElems, outputsConcat, outputsBufferReader, outputCount, changeData, changeFound, i, amount, outputScript, isChange, changePath, pubkey, key, p, firstSigned, progressCallback, serializedTx;
199
- return __generator(this, function (_a) {
200
- switch (_a.label) {
201
- case 0:
202
- inputCount = arg.inputs.length;
203
- if (inputCount == 0) {
204
- throw Error("No inputs");
205
- }
206
- psbt = new PsbtV2();
207
- return [4 /*yield*/, this.client.getMasterFingerprint()];
208
- case 1:
209
- masterFp = _a.sent();
210
- accountType = accountTypeFromArg(arg, psbt, masterFp);
211
- if (arg.lockTime != undefined) {
212
- // The signer will assume locktime 0 if unset
213
- psbt.setGlobalFallbackLocktime(arg.lockTime);
214
- }
215
- psbt.setGlobalInputCount(inputCount);
216
- psbt.setGlobalPsbtVersion(2);
217
- psbt.setGlobalTxVersion(2);
218
- notifyCount = 0;
219
- progress = function () {
220
- if (!arg.onDeviceStreaming)
221
- return;
222
- arg.onDeviceStreaming({
223
- total: 2 * inputCount,
224
- index: notifyCount,
225
- progress: ++notifyCount / (2 * inputCount)
226
- });
227
- };
228
- accountXpub = "";
229
- accountPath = [];
230
- i = 0;
231
- _a.label = 2;
232
- case 2:
233
- if (!(i < inputCount)) return [3 /*break*/, 7];
234
- progress();
235
- pathElems = pathStringToArray(arg.associatedKeysets[i]);
236
- if (!(accountXpub == "")) return [3 /*break*/, 4];
237
- // We assume all inputs belong to the same account so we set
238
- // the account xpub and path based on the first input.
239
- accountPath = pathElems.slice(0, -2);
240
- return [4 /*yield*/, this.client.getExtendedPubkey(false, accountPath)];
241
- case 3:
242
- accountXpub = _a.sent();
243
- _a.label = 4;
244
- case 4: return [4 /*yield*/, this.setInput(psbt, i, arg.inputs[i], pathElems, accountType, masterFp, arg.sigHashType)];
245
- case 5:
246
- _a.sent();
247
- _a.label = 6;
248
- case 6:
249
- i++;
250
- return [3 /*break*/, 2];
251
- case 7:
252
- outputsConcat = Buffer.from(arg.outputScriptHex, "hex");
253
- outputsBufferReader = new BufferReader(outputsConcat);
254
- outputCount = outputsBufferReader.readVarInt();
255
- psbt.setGlobalOutputCount(outputCount);
256
- return [4 /*yield*/, this.outputScriptAt(accountPath, accountType, arg.changePath)];
257
- case 8:
258
- changeData = _a.sent();
259
- changeFound = !changeData;
260
- for (i = 0; i < outputCount; i++) {
261
- amount = Number(outputsBufferReader.readUInt64());
262
- outputScript = outputsBufferReader.readVarSlice();
263
- psbt.setOutputAmount(i, amount);
264
- psbt.setOutputScript(i, outputScript);
265
- isChange = changeData && outputScript.equals(changeData === null || changeData === void 0 ? void 0 : changeData.cond.scriptPubKey);
266
- if (isChange) {
267
- changeFound = true;
268
- changePath = pathStringToArray(arg.changePath);
269
- pubkey = changeData.pubkey;
270
- accountType.setOwnOutput(i, changeData.cond, [pubkey], [changePath]);
271
- }
272
- }
273
- if (!changeFound) {
274
- throw new Error("Change script not found among outputs! " +
275
- (changeData === null || changeData === void 0 ? void 0 : changeData.cond.scriptPubKey.toString("hex")));
276
- }
277
- key = createKey(masterFp, accountPath, accountXpub);
278
- p = new WalletPolicy(accountType.getDescriptorTemplate(), key);
279
- // This is cheating, because it's not actually requested on the
280
- // device yet, but it will be, soonish.
281
- if (arg.onDeviceSignatureRequested)
282
- arg.onDeviceSignatureRequested();
283
- firstSigned = false;
284
- progressCallback = function () {
285
- if (!firstSigned) {
286
- firstSigned = true;
287
- arg.onDeviceSignatureGranted && arg.onDeviceSignatureGranted();
288
- }
289
- progress();
290
- };
291
- return [4 /*yield*/, this.signPsbt(psbt, p, progressCallback)];
292
- case 9:
293
- _a.sent();
294
- finalize(psbt);
295
- serializedTx = extract(psbt);
296
- return [2 /*return*/, serializedTx.toString("hex")];
140
+ createPaymentTransaction(arg) {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ const inputCount = arg.inputs.length;
143
+ if (inputCount == 0) {
144
+ throw Error("No inputs");
145
+ }
146
+ const psbt = new PsbtV2();
147
+ // The master fingerprint is needed when adding BIP32 derivation paths on
148
+ // the psbt.
149
+ const masterFp = yield this.client.getMasterFingerprint();
150
+ const accountType = accountTypeFromArg(arg, psbt, masterFp);
151
+ if (arg.lockTime != undefined) {
152
+ // The signer will assume locktime 0 if unset
153
+ psbt.setGlobalFallbackLocktime(arg.lockTime);
154
+ }
155
+ psbt.setGlobalInputCount(inputCount);
156
+ psbt.setGlobalPsbtVersion(2);
157
+ psbt.setGlobalTxVersion(2);
158
+ let notifyCount = 0;
159
+ const progress = () => {
160
+ if (!arg.onDeviceStreaming)
161
+ return;
162
+ arg.onDeviceStreaming({
163
+ total: 2 * inputCount,
164
+ index: notifyCount,
165
+ progress: ++notifyCount / (2 * inputCount),
166
+ });
167
+ };
168
+ let accountXpub = "";
169
+ let accountPath = [];
170
+ for (let i = 0; i < inputCount; i++) {
171
+ progress();
172
+ const pathElems = pathStringToArray(arg.associatedKeysets[i]);
173
+ if (accountXpub == "") {
174
+ // We assume all inputs belong to the same account so we set
175
+ // the account xpub and path based on the first input.
176
+ accountPath = pathElems.slice(0, -2);
177
+ accountXpub = yield this.client.getExtendedPubkey(false, accountPath);
297
178
  }
298
- });
179
+ yield this.setInput(psbt, i, arg.inputs[i], pathElems, accountType, masterFp, arg.sigHashType);
180
+ }
181
+ const outputsConcat = Buffer.from(arg.outputScriptHex, "hex");
182
+ const outputsBufferReader = new BufferReader(outputsConcat);
183
+ const outputCount = outputsBufferReader.readVarInt();
184
+ psbt.setGlobalOutputCount(outputCount);
185
+ const changeData = yield this.outputScriptAt(accountPath, accountType, arg.changePath);
186
+ // If the caller supplied a changePath, we must make sure there actually is
187
+ // a change output. If no change output found, we'll throw an error.
188
+ let changeFound = !changeData;
189
+ for (let i = 0; i < outputCount; i++) {
190
+ const amount = Number(outputsBufferReader.readUInt64());
191
+ const outputScript = outputsBufferReader.readVarSlice();
192
+ psbt.setOutputAmount(i, amount);
193
+ psbt.setOutputScript(i, outputScript);
194
+ // We won't know if we're paying to ourselves, because there's no
195
+ // information in arg to support multiple "change paths". One exception is
196
+ // if there are multiple outputs to the change address.
197
+ const isChange = changeData && outputScript.equals(changeData === null || changeData === void 0 ? void 0 : changeData.cond.scriptPubKey);
198
+ if (isChange) {
199
+ changeFound = true;
200
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
201
+ const changePath = pathStringToArray(arg.changePath);
202
+ const pubkey = changeData.pubkey;
203
+ accountType.setOwnOutput(i, changeData.cond, [pubkey], [changePath]);
204
+ }
205
+ }
206
+ if (!changeFound) {
207
+ throw new Error("Change script not found among outputs! " +
208
+ (changeData === null || changeData === void 0 ? void 0 : changeData.cond.scriptPubKey.toString("hex")));
209
+ }
210
+ const key = createKey(masterFp, accountPath, accountXpub);
211
+ const p = new WalletPolicy(accountType.getDescriptorTemplate(), key);
212
+ // This is cheating, because it's not actually requested on the
213
+ // device yet, but it will be, soonish.
214
+ if (arg.onDeviceSignatureRequested)
215
+ arg.onDeviceSignatureRequested();
216
+ let firstSigned = false;
217
+ // This callback will be called once for each signature yielded.
218
+ const progressCallback = () => {
219
+ if (!firstSigned) {
220
+ firstSigned = true;
221
+ arg.onDeviceSignatureGranted && arg.onDeviceSignatureGranted();
222
+ }
223
+ progress();
224
+ };
225
+ yield this.signPsbt(psbt, p, progressCallback);
226
+ finalize(psbt);
227
+ const serializedTx = extract(psbt);
228
+ return serializedTx.toString("hex");
299
229
  });
300
- };
230
+ }
301
231
  /**
302
232
  * Calculates an output script along with public key and possible redeemScript
303
233
  * from a path and accountType. The accountPath must be a prefix of path.
@@ -306,75 +236,60 @@ var BtcNew = /** @class */ (function () {
306
236
  * wrapped p2wpkh), and pubkey at provided path. The values of these three
307
237
  * properties depend on the accountType used.
308
238
  */
309
- BtcNew.prototype.outputScriptAt = function (accountPath, accountType, path) {
310
- return __awaiter(this, void 0, void 0, function () {
311
- var pathElems, i, xpub, pubkey, cond;
312
- return __generator(this, function (_a) {
313
- switch (_a.label) {
314
- case 0:
315
- if (!path)
316
- return [2 /*return*/, undefined];
317
- pathElems = pathStringToArray(path);
318
- // Make sure path is in our account, otherwise something fishy is probably
319
- // going on.
320
- for (i = 0; i < accountPath.length; i++) {
321
- if (accountPath[i] != pathElems[i]) {
322
- throw new Error("Path ".concat(path, " not in account ").concat(pathArrayToString(accountPath)));
323
- }
324
- }
325
- return [4 /*yield*/, this.client.getExtendedPubkey(false, pathElems)];
326
- case 1:
327
- xpub = _a.sent();
328
- pubkey = pubkeyFromXpub(xpub);
329
- cond = accountType.spendingCondition([pubkey]);
330
- return [2 /*return*/, { cond: cond, pubkey: pubkey }];
239
+ outputScriptAt(accountPath, accountType, path) {
240
+ return __awaiter(this, void 0, void 0, function* () {
241
+ if (!path)
242
+ return undefined;
243
+ const pathElems = pathStringToArray(path);
244
+ // Make sure path is in our account, otherwise something fishy is probably
245
+ // going on.
246
+ for (let i = 0; i < accountPath.length; i++) {
247
+ if (accountPath[i] != pathElems[i]) {
248
+ throw new Error(`Path ${path} not in account ${pathArrayToString(accountPath)}`);
331
249
  }
332
- });
250
+ }
251
+ const xpub = yield this.client.getExtendedPubkey(false, pathElems);
252
+ const pubkey = pubkeyFromXpub(xpub);
253
+ const cond = accountType.spendingCondition([pubkey]);
254
+ return { cond, pubkey };
333
255
  });
334
- };
256
+ }
335
257
  /**
336
258
  * Adds relevant data about an input to the psbt. This includes sequence,
337
259
  * previous txid, output index, spent UTXO, redeem script for wrapped p2wpkh,
338
260
  * public key and its derivation path.
339
261
  */
340
- BtcNew.prototype.setInput = function (psbt, i, input, pathElements, accountType, masterFP, sigHashType) {
341
- return __awaiter(this, void 0, void 0, function () {
342
- var inputTx, spentOutputIndex, redeemScript, sequence, inputTxBuffer, inputTxid, xpubBase58, pubkey, spentTxOutput, spendCondition, spentOutput;
343
- return __generator(this, function (_a) {
344
- switch (_a.label) {
345
- case 0:
346
- inputTx = input[0];
347
- spentOutputIndex = input[1];
348
- redeemScript = input[2] ? Buffer.from(input[2], "hex") : undefined;
349
- sequence = input[3];
350
- if (sequence != undefined) {
351
- psbt.setInputSequence(i, sequence);
352
- }
353
- if (sigHashType != undefined) {
354
- psbt.setInputSighashType(i, sigHashType);
355
- }
356
- inputTxBuffer = serializeTransaction(inputTx, true);
357
- inputTxid = crypto.hash256(inputTxBuffer);
358
- return [4 /*yield*/, this.client.getExtendedPubkey(false, pathElements)];
359
- case 1:
360
- xpubBase58 = _a.sent();
361
- pubkey = pubkeyFromXpub(xpubBase58);
362
- if (!inputTx.outputs)
363
- throw Error("Missing outputs array in transaction to sign");
364
- spentTxOutput = inputTx.outputs[spentOutputIndex];
365
- spendCondition = {
366
- scriptPubKey: spentTxOutput.script,
367
- redeemScript: redeemScript
368
- };
369
- spentOutput = { cond: spendCondition, amount: spentTxOutput.amount };
370
- accountType.setInput(i, inputTxBuffer, spentOutput, [pubkey], [pathElements]);
371
- psbt.setInputPreviousTxId(i, inputTxid);
372
- psbt.setInputOutputIndex(i, spentOutputIndex);
373
- return [2 /*return*/];
374
- }
375
- });
262
+ setInput(psbt, i, input, pathElements, accountType, masterFP, sigHashType) {
263
+ return __awaiter(this, void 0, void 0, function* () {
264
+ const inputTx = input[0];
265
+ const spentOutputIndex = input[1];
266
+ // redeemScript will be null for wrapped p2wpkh, we need to create it
267
+ // ourselves. But if set, it should be used.
268
+ const redeemScript = input[2] ? Buffer.from(input[2], "hex") : undefined;
269
+ const sequence = input[3];
270
+ if (sequence != undefined) {
271
+ psbt.setInputSequence(i, sequence);
272
+ }
273
+ if (sigHashType != undefined) {
274
+ psbt.setInputSighashType(i, sigHashType);
275
+ }
276
+ const inputTxBuffer = serializeTransaction(inputTx, true);
277
+ const inputTxid = crypto.hash256(inputTxBuffer);
278
+ const xpubBase58 = yield this.client.getExtendedPubkey(false, pathElements);
279
+ const pubkey = pubkeyFromXpub(xpubBase58);
280
+ if (!inputTx.outputs)
281
+ throw Error("Missing outputs array in transaction to sign");
282
+ const spentTxOutput = inputTx.outputs[spentOutputIndex];
283
+ const spendCondition = {
284
+ scriptPubKey: spentTxOutput.script,
285
+ redeemScript: redeemScript,
286
+ };
287
+ const spentOutput = { cond: spendCondition, amount: spentTxOutput.amount };
288
+ accountType.setInput(i, inputTxBuffer, spentOutput, [pubkey], [pathElements]);
289
+ psbt.setInputPreviousTxId(i, inputTxid);
290
+ psbt.setInputOutputIndex(i, spentOutputIndex);
376
291
  });
377
- };
292
+ }
378
293
  /**
379
294
  * This implements the "Signer" role of the BIP370 transaction signing
380
295
  * process.
@@ -384,40 +299,30 @@ var BtcNew = /** @class */ (function () {
384
299
  * comment in-line. The signatures returned from the hardware device is added
385
300
  * to the appropriate input fields of the PSBT.
386
301
  */
387
- BtcNew.prototype.signPsbt = function (psbt, walletPolicy, progressCallback) {
388
- return __awaiter(this, void 0, void 0, function () {
389
- var sigs;
390
- return __generator(this, function (_a) {
391
- switch (_a.label) {
392
- case 0: return [4 /*yield*/, this.client.signPsbt(psbt, walletPolicy, Buffer.alloc(32, 0), progressCallback)];
393
- case 1:
394
- sigs = _a.sent();
395
- sigs.forEach(function (v, k) {
396
- // Note: Looking at BIP32 derivation does not work in the generic case,
397
- // since some inputs might not have a BIP32-derived pubkey.
398
- var pubkeys = psbt.getInputKeyDatas(k, psbtIn.BIP32_DERIVATION);
399
- var pubkey;
400
- if (pubkeys.length != 1) {
401
- // No legacy BIP32_DERIVATION, assume we're using taproot.
402
- pubkey = psbt.getInputKeyDatas(k, psbtIn.TAP_BIP32_DERIVATION);
403
- if (pubkey.length == 0) {
404
- throw Error("Missing pubkey derivation for input ".concat(k));
405
- }
406
- psbt.setInputTapKeySig(k, v);
407
- }
408
- else {
409
- pubkey = pubkeys[0];
410
- psbt.setInputPartialSig(k, pubkey, v);
411
- }
412
- });
413
- return [2 /*return*/];
302
+ signPsbt(psbt, walletPolicy, progressCallback) {
303
+ return __awaiter(this, void 0, void 0, function* () {
304
+ const sigs = yield this.client.signPsbt(psbt, walletPolicy, Buffer.alloc(32, 0), progressCallback);
305
+ sigs.forEach((v, k) => {
306
+ // Note: Looking at BIP32 derivation does not work in the generic case,
307
+ // since some inputs might not have a BIP32-derived pubkey.
308
+ const pubkeys = psbt.getInputKeyDatas(k, psbtIn.BIP32_DERIVATION);
309
+ let pubkey;
310
+ if (pubkeys.length != 1) {
311
+ // No legacy BIP32_DERIVATION, assume we're using taproot.
312
+ pubkey = psbt.getInputKeyDatas(k, psbtIn.TAP_BIP32_DERIVATION);
313
+ if (pubkey.length == 0) {
314
+ throw Error(`Missing pubkey derivation for input ${k}`);
315
+ }
316
+ psbt.setInputTapKeySig(k, v);
317
+ }
318
+ else {
319
+ pubkey = pubkeys[0];
320
+ psbt.setInputPartialSig(k, pubkey, v);
414
321
  }
415
322
  });
416
323
  });
417
- };
418
- return BtcNew;
419
- }());
420
- export default BtcNew;
324
+ }
325
+ }
421
326
  function descrTemplFrom(addressFormat) {
422
327
  if (addressFormat == "legacy")
423
328
  return "pkh(@0)";
@@ -459,17 +364,15 @@ function accountTypeFromArg(arg, psbt, masterFp) {
459
364
  */
460
365
  function isPathNormal(path) {
461
366
  //path is not deepest hardened node of a standard path or deeper, use BtcOld
462
- var h = 0x80000000; //HARDENED from bip32
463
- var pathElems = pathStringToArray(path);
464
- var hard = function (n) { return n >= h; };
465
- var soft = function (n) { return n === undefined || n < h; };
466
- var change = function (n) {
467
- return n === undefined || n === 0 || n === 1;
468
- };
367
+ const h = 0x80000000; //HARDENED from bip32
368
+ const pathElems = pathStringToArray(path);
369
+ const hard = (n) => n >= h;
370
+ const soft = (n) => n === undefined || n < h;
371
+ const change = (n) => n === undefined || n === 0 || n === 1;
469
372
  if (pathElems.length >= 3 &&
470
373
  pathElems.length <= 5 &&
471
- [44 + h, 49 + h, 84 + h, 86 + h].some(function (v) { return v == pathElems[0]; }) &&
472
- [0 + h, 1 + h].some(function (v) { return v == pathElems[1]; }) &&
374
+ [44 + h, 49 + h, 84 + h, 86 + h].some((v) => v == pathElems[0]) &&
375
+ [0 + h, 1 + h].some((v) => v == pathElems[1]) &&
473
376
  hard(pathElems[2]) &&
474
377
  change(pathElems[3]) &&
475
378
  soft(pathElems[4])) {
@@ -478,7 +381,7 @@ function isPathNormal(path) {
478
381
  if (pathElems.length >= 4 &&
479
382
  pathElems.length <= 6 &&
480
383
  48 + h == pathElems[0] &&
481
- [0 + h, 1 + h].some(function (v) { return v == pathElems[1]; }) &&
384
+ [0 + h, 1 + h].some((v) => v == pathElems[1]) &&
482
385
  hard(pathElems[2]) &&
483
386
  hard(pathElems[3]) &&
484
387
  change(pathElems[4]) &&