@ledgerhq/hw-app-btc 6.9.1-taproot.0 → 6.11.1
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/README.md +602 -107
- package/lib/Btc.d.ts +11 -7
- package/lib/Btc.d.ts.map +1 -1
- package/lib/Btc.js +113 -31
- package/lib/Btc.js.map +1 -1
- package/lib/BtcNew.d.ts +81 -32
- package/lib/BtcNew.d.ts.map +1 -1
- package/lib/BtcNew.js +296 -99
- package/lib/BtcNew.js.map +1 -1
- package/lib/BtcOld.d.ts +3 -1
- package/lib/BtcOld.d.ts.map +1 -1
- package/lib/BtcOld.js +22 -6
- package/lib/BtcOld.js.map +1 -1
- package/lib/constants.d.ts +1 -0
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +2 -1
- package/lib/constants.js.map +1 -1
- package/lib/getAppAndVersion.d.ts +3 -2
- package/lib/getAppAndVersion.d.ts.map +1 -1
- package/lib/getAppAndVersion.js.map +1 -1
- package/lib/newops/appClient.d.ts +6 -2
- package/lib/newops/appClient.d.ts.map +1 -1
- package/lib/newops/appClient.js +9 -5
- package/lib/newops/appClient.js.map +1 -1
- package/lib/newops/clientCommands.d.ts +18 -2
- package/lib/newops/clientCommands.d.ts.map +1 -1
- package/lib/newops/clientCommands.js +20 -3
- package/lib/newops/clientCommands.js.map +1 -1
- package/lib/newops/merkelizedPsbt.d.ts +11 -0
- package/lib/newops/merkelizedPsbt.d.ts.map +1 -1
- package/lib/newops/merkelizedPsbt.js +11 -0
- package/lib/newops/merkelizedPsbt.js.map +1 -1
- package/lib/newops/merkle.d.ts +5 -0
- package/lib/newops/merkle.d.ts.map +1 -1
- package/lib/newops/merkle.js +5 -0
- package/lib/newops/merkle.js.map +1 -1
- package/lib/newops/merkleMap.d.ts +10 -0
- package/lib/newops/merkleMap.d.ts.map +1 -1
- package/lib/newops/merkleMap.js +10 -0
- package/lib/newops/merkleMap.js.map +1 -1
- package/lib/newops/policy.d.ts +8 -0
- package/lib/newops/policy.d.ts.map +1 -1
- package/lib/newops/policy.js +9 -1
- package/lib/newops/policy.js.map +1 -1
- package/lib/newops/psbtExtractor.d.ts +6 -0
- package/lib/newops/psbtExtractor.d.ts.map +1 -1
- package/lib/newops/psbtExtractor.js +6 -0
- package/lib/newops/psbtExtractor.js.map +1 -1
- package/lib/newops/psbtFinalizer.d.ts +11 -1
- package/lib/newops/psbtFinalizer.d.ts.map +1 -1
- package/lib/newops/psbtFinalizer.js +28 -4
- package/lib/newops/psbtFinalizer.js.map +1 -1
- package/lib/newops/psbtv2.d.ts +22 -2
- package/lib/newops/psbtv2.d.ts.map +1 -1
- package/lib/newops/psbtv2.js +37 -8
- package/lib/newops/psbtv2.js.map +1 -1
- package/lib-es/Btc.d.ts +11 -7
- package/lib-es/Btc.d.ts.map +1 -1
- package/lib-es/Btc.js +94 -31
- package/lib-es/Btc.js.map +1 -1
- package/lib-es/BtcNew.d.ts +81 -32
- package/lib-es/BtcNew.d.ts.map +1 -1
- package/lib-es/BtcNew.js +293 -101
- package/lib-es/BtcNew.js.map +1 -1
- package/lib-es/BtcOld.d.ts +3 -1
- package/lib-es/BtcOld.d.ts.map +1 -1
- package/lib-es/BtcOld.js +22 -6
- package/lib-es/BtcOld.js.map +1 -1
- package/lib-es/constants.d.ts +1 -0
- package/lib-es/constants.d.ts.map +1 -1
- package/lib-es/constants.js +1 -0
- package/lib-es/constants.js.map +1 -1
- package/lib-es/getAppAndVersion.d.ts +3 -2
- package/lib-es/getAppAndVersion.d.ts.map +1 -1
- package/lib-es/getAppAndVersion.js.map +1 -1
- package/lib-es/newops/appClient.d.ts +6 -2
- package/lib-es/newops/appClient.d.ts.map +1 -1
- package/lib-es/newops/appClient.js +9 -5
- package/lib-es/newops/appClient.js.map +1 -1
- package/lib-es/newops/clientCommands.d.ts +18 -2
- package/lib-es/newops/clientCommands.d.ts.map +1 -1
- package/lib-es/newops/clientCommands.js +20 -3
- package/lib-es/newops/clientCommands.js.map +1 -1
- package/lib-es/newops/merkelizedPsbt.d.ts +11 -0
- package/lib-es/newops/merkelizedPsbt.d.ts.map +1 -1
- package/lib-es/newops/merkelizedPsbt.js +11 -0
- package/lib-es/newops/merkelizedPsbt.js.map +1 -1
- package/lib-es/newops/merkle.d.ts +5 -0
- package/lib-es/newops/merkle.d.ts.map +1 -1
- package/lib-es/newops/merkle.js +5 -0
- package/lib-es/newops/merkle.js.map +1 -1
- package/lib-es/newops/merkleMap.d.ts +10 -0
- package/lib-es/newops/merkleMap.d.ts.map +1 -1
- package/lib-es/newops/merkleMap.js +10 -0
- package/lib-es/newops/merkleMap.js.map +1 -1
- package/lib-es/newops/policy.d.ts +8 -0
- package/lib-es/newops/policy.d.ts.map +1 -1
- package/lib-es/newops/policy.js +10 -2
- package/lib-es/newops/policy.js.map +1 -1
- package/lib-es/newops/psbtExtractor.d.ts +6 -0
- package/lib-es/newops/psbtExtractor.d.ts.map +1 -1
- package/lib-es/newops/psbtExtractor.js +6 -0
- package/lib-es/newops/psbtExtractor.js.map +1 -1
- package/lib-es/newops/psbtFinalizer.d.ts +11 -1
- package/lib-es/newops/psbtFinalizer.d.ts.map +1 -1
- package/lib-es/newops/psbtFinalizer.js +28 -4
- package/lib-es/newops/psbtFinalizer.js.map +1 -1
- package/lib-es/newops/psbtv2.d.ts +22 -2
- package/lib-es/newops/psbtv2.d.ts.map +1 -1
- package/lib-es/newops/psbtv2.js +37 -8
- package/lib-es/newops/psbtv2.js.map +1 -1
- package/package.json +4 -4
- package/src/Btc.ts +92 -21
- package/src/BtcNew.ts +295 -77
- package/src/BtcOld.ts +13 -9
- package/src/bip32.ts +1 -1
- package/src/constants.ts +1 -0
- package/src/getAppAndVersion.ts +7 -4
- package/src/newops/appClient.ts +13 -5
- package/src/newops/clientCommands.ts +19 -3
- package/src/newops/merkelizedPsbt.ts +11 -0
- package/src/newops/merkle.ts +5 -0
- package/src/newops/merkleMap.ts +10 -0
- package/src/newops/policy.ts +10 -2
- package/src/newops/psbtExtractor.ts +6 -0
- package/src/newops/psbtFinalizer.ts +28 -4
- package/src/newops/psbtv2.ts +38 -14
- package/tests/Btc.integration.test.ts +125 -15
- package/tests/Btc.test.ts +83 -0
- package/tests/newops/BtcNew.test.ts +75 -508
- package/tests/newops/integrationtools.ts +174 -0
- package/tests/newops/testtx.ts +676 -0
- package/tests/speculosclient.ts +47 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
import bs58check from "bs58check";
|
|
4
|
+
import Btc from "../../src/Btc";
|
|
5
|
+
import BtcNew from "../../src/BtcNew";
|
|
6
|
+
import { BufferWriter } from "../../src/buffertools";
|
|
7
|
+
import { CreateTransactionArg } from "../../src/createTransaction";
|
|
8
|
+
import { AddressFormat } from "../../src/getWalletPublicKey";
|
|
9
|
+
import { AppClient } from "../../src/newops/appClient";
|
|
10
|
+
import {
|
|
11
|
+
DefaultDescriptorTemplate,
|
|
12
|
+
WalletPolicy
|
|
13
|
+
} from "../../src/newops/policy";
|
|
14
|
+
import { Transaction } from "../../src/types";
|
|
15
|
+
import { CoreInput, CoreTx, spentTxs } from "./testtx";
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export async function runSignTransaction(
|
|
19
|
+
testTx: CoreTx,
|
|
20
|
+
testPaths: { ins: string[], out?: string },
|
|
21
|
+
client: TestingClient,
|
|
22
|
+
transport: Transport): Promise<string> {
|
|
23
|
+
const btcNew = new BtcNew(client);
|
|
24
|
+
// btc is needed to perform some functions like splitTransaction.
|
|
25
|
+
const btc = new Btc(transport);
|
|
26
|
+
const accountType = getAccountType(testTx.vin[0], btc);
|
|
27
|
+
const additionals: string[] = [];
|
|
28
|
+
if (accountType == AccountType.p2wpkh) {
|
|
29
|
+
additionals.push("bech32");
|
|
30
|
+
}
|
|
31
|
+
if (accountType == AccountType.p2tr) {
|
|
32
|
+
additionals.push("bech32m");
|
|
33
|
+
}
|
|
34
|
+
const associatedKeysets: string[] = [];
|
|
35
|
+
const yieldSigs = new Map<number, Buffer>();
|
|
36
|
+
const inputs = testTx.vin.map((input, index) => {
|
|
37
|
+
const path = testPaths.ins[index];
|
|
38
|
+
associatedKeysets.push(path);
|
|
39
|
+
const inputData = createInput(input, btc);
|
|
40
|
+
const pubkey = getPubkey(index, accountType, testTx, inputData[0], inputData[1]);
|
|
41
|
+
const mockXpub = creatDummyXpub(pubkey);
|
|
42
|
+
client.mockGetPubkeyResponse(path, mockXpub);
|
|
43
|
+
yieldSigs.set(index, getSignature(input, accountType));
|
|
44
|
+
return inputData;
|
|
45
|
+
});
|
|
46
|
+
const sig0 = yieldSigs.get(0)!;
|
|
47
|
+
let sigHashType: number | undefined = sig0.readUInt8(sig0.length - 1)
|
|
48
|
+
if (sigHashType == 0x01) {
|
|
49
|
+
sigHashType = undefined;
|
|
50
|
+
}
|
|
51
|
+
client.mockSignPsbt(yieldSigs);
|
|
52
|
+
const outputWriter = new BufferWriter();
|
|
53
|
+
outputWriter.writeVarInt(testTx.vout.length);
|
|
54
|
+
testTx.vout.forEach(output => {
|
|
55
|
+
outputWriter.writeUInt64(BigInt(Number.parseFloat((output.value * 100000000).toFixed(8))));
|
|
56
|
+
outputWriter.writeVarSlice(Buffer.from(output.scriptPubKey.hex, "hex"));
|
|
57
|
+
});
|
|
58
|
+
const outputScriptHex = outputWriter.buffer().toString("hex");
|
|
59
|
+
let callbacks = "";
|
|
60
|
+
function logCallback(message: string) {
|
|
61
|
+
callbacks += new Date().toISOString() + " " + message + "\n";
|
|
62
|
+
}
|
|
63
|
+
const arg: CreateTransactionArg = {
|
|
64
|
+
inputs,
|
|
65
|
+
additionals,
|
|
66
|
+
associatedKeysets,
|
|
67
|
+
changePath: testPaths.out,
|
|
68
|
+
outputScriptHex,
|
|
69
|
+
lockTime: testTx.locktime,
|
|
70
|
+
sigHashType,
|
|
71
|
+
segwit: accountType != AccountType.p2pkh,
|
|
72
|
+
onDeviceSignatureGranted: () => logCallback("CALLBACK: signature granted"),
|
|
73
|
+
onDeviceSignatureRequested: () => logCallback("CALLBACK: signature requested"),
|
|
74
|
+
onDeviceStreaming: (arg) => logCallback("CALLBACK: " + JSON.stringify(arg))
|
|
75
|
+
};
|
|
76
|
+
logCallback("Start createPaymentTransactionNew");
|
|
77
|
+
const tx = await btcNew.createPaymentTransactionNew(arg);
|
|
78
|
+
logCallback("Done createPaymentTransactionNew");
|
|
79
|
+
// console.log(callbacks);
|
|
80
|
+
return tx;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
export function addressFormatFromDescriptorTemplate(descTemp: DefaultDescriptorTemplate): AddressFormat {
|
|
86
|
+
if (descTemp == "tr(@0)") return "bech32m";
|
|
87
|
+
if (descTemp == "pkh(@0)") return "legacy";
|
|
88
|
+
if (descTemp == "wpkh(@0)") return "bech32";
|
|
89
|
+
if (descTemp == "sh(wpkh(@0))") return "p2sh";
|
|
90
|
+
throw new Error();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export enum AccountType {
|
|
94
|
+
p2tr = "86'",
|
|
95
|
+
p2wpkh = "84'",
|
|
96
|
+
p2wpkhInP2sh = "49'",
|
|
97
|
+
p2pkh = "44'"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getPubkey(inputIndex: number, accountType: AccountType, testTx: CoreTx, spentTx: Transaction, spentOutputIndex: number): Buffer {
|
|
101
|
+
const scriptSig = Buffer.from(testTx.vin[inputIndex].scriptSig.hex, "hex");
|
|
102
|
+
if (accountType == AccountType.p2pkh) {
|
|
103
|
+
return scriptSig.slice(scriptSig.length - 33);
|
|
104
|
+
}
|
|
105
|
+
if (accountType == AccountType.p2tr) {
|
|
106
|
+
return spentTx.outputs![spentOutputIndex].script.slice(2, 34); // 32 bytes x-only pubkey
|
|
107
|
+
}
|
|
108
|
+
if (accountType == AccountType.p2wpkh || accountType == AccountType.p2wpkhInP2sh) {
|
|
109
|
+
return Buffer.from(testTx.vin[inputIndex].txinwitness![1], "hex");
|
|
110
|
+
}
|
|
111
|
+
throw new Error();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getSignature(testTxInput: CoreInput, accountType: AccountType): Buffer {
|
|
115
|
+
const scriptSig = Buffer.from(testTxInput.scriptSig.hex, "hex");
|
|
116
|
+
if (accountType == AccountType.p2pkh) {
|
|
117
|
+
return scriptSig.slice(1, scriptSig.length - 34);
|
|
118
|
+
}
|
|
119
|
+
if (accountType == AccountType.p2tr) {
|
|
120
|
+
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
121
|
+
}
|
|
122
|
+
if (accountType == AccountType.p2wpkh || accountType == AccountType.p2wpkhInP2sh) {
|
|
123
|
+
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
124
|
+
}
|
|
125
|
+
throw new Error();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getAccountType(coreInput: CoreInput, btc: Btc): AccountType {
|
|
129
|
+
const spentTx = spentTxs[coreInput.txid];
|
|
130
|
+
if (!spentTx) {
|
|
131
|
+
throw new Error("Spent tx " + coreInput.txid + " unavailable.");
|
|
132
|
+
}
|
|
133
|
+
const splitSpentTx = btc.splitTransaction(spentTx, true);
|
|
134
|
+
const spentOutput = splitSpentTx.outputs![coreInput.vout];
|
|
135
|
+
const script = spentOutput.script;
|
|
136
|
+
if (script.length == 34 && script[0] == 0x51) {
|
|
137
|
+
return AccountType.p2tr;
|
|
138
|
+
}
|
|
139
|
+
if (script.length == 22 && script[0] == 0x00) {
|
|
140
|
+
return AccountType.p2wpkh;
|
|
141
|
+
}
|
|
142
|
+
if (script.length == 23) {
|
|
143
|
+
return AccountType.p2wpkhInP2sh;
|
|
144
|
+
}
|
|
145
|
+
return AccountType.p2pkh;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function creatDummyXpub(pubkey: Buffer): string {
|
|
149
|
+
const xpubDecoded = bs58check.decode("tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd");
|
|
150
|
+
const pubkey33 = pubkey.length == 33 ? pubkey : Buffer.concat([Buffer.of(2), pubkey]);
|
|
151
|
+
xpubDecoded.fill(pubkey33, xpubDecoded.length - 33);
|
|
152
|
+
return bs58check.encode(xpubDecoded);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function createInput(coreInput: CoreInput, btc: Btc): [Transaction, number, string | null, number] {
|
|
156
|
+
const spentTx = spentTxs[coreInput.txid];
|
|
157
|
+
if (!spentTx) {
|
|
158
|
+
throw new Error("Spent tx " + coreInput.txid + " unavailable.");
|
|
159
|
+
}
|
|
160
|
+
const splitSpentTx = btc.splitTransaction(spentTx, true);
|
|
161
|
+
return [splitSpentTx, coreInput.vout, null, coreInput.sequence];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const masterFingerprint = Buffer.of(1, 2, 3, 4);
|
|
165
|
+
export class TestingClient extends AppClient {
|
|
166
|
+
mockGetPubkeyResponse(_pathElements: string, _response: string): void { };
|
|
167
|
+
mockGetWalletAddressResponse(
|
|
168
|
+
_walletPolicy: WalletPolicy,
|
|
169
|
+
_change: number,
|
|
170
|
+
_addressIndex: number,
|
|
171
|
+
_response: string
|
|
172
|
+
): void { };
|
|
173
|
+
mockSignPsbt(_yieldSigs: Map<number, Buffer>): void { };
|
|
174
|
+
}
|