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