@ledgerhq/hw-app-btc 6.11.1 → 6.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -48
- package/lib/Btc.d.ts.map +1 -1
- package/lib/Btc.js +4 -2
- package/lib/Btc.js.map +1 -1
- package/lib/BtcNew.d.ts.map +1 -1
- package/lib/BtcNew.js +35 -164
- package/lib/BtcNew.js.map +1 -1
- package/lib/newops/accounttype.d.ts +110 -0
- package/lib/newops/accounttype.d.ts.map +1 -0
- package/lib/newops/accounttype.js +233 -0
- package/lib/newops/accounttype.js.map +1 -0
- package/lib/newops/clientCommands.d.ts.map +1 -1
- package/lib/newops/clientCommands.js +14 -9
- package/lib/newops/clientCommands.js.map +1 -1
- package/lib-es/Btc.d.ts.map +1 -1
- package/lib-es/Btc.js +4 -2
- package/lib-es/Btc.js.map +1 -1
- package/lib-es/BtcNew.d.ts.map +1 -1
- package/lib-es/BtcNew.js +38 -167
- package/lib-es/BtcNew.js.map +1 -1
- package/lib-es/newops/accounttype.d.ts +110 -0
- package/lib-es/newops/accounttype.d.ts.map +1 -0
- package/lib-es/newops/accounttype.js +230 -0
- package/lib-es/newops/accounttype.js.map +1 -0
- package/lib-es/newops/clientCommands.d.ts.map +1 -1
- package/lib-es/newops/clientCommands.js +14 -9
- package/lib-es/newops/clientCommands.js.map +1 -1
- package/package.json +3 -3
- package/src/Btc.ts +33 -2
- package/src/BtcNew.ts +61 -163
- package/src/newops/accounttype.ts +370 -0
- package/src/newops/clientCommands.ts +15 -9
- package/tests/Btc.test.ts +5 -0
- package/tests/newops/BtcNew.test.ts +10 -10
- package/tests/newops/integrationtools.ts +17 -17
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { crypto } from "bitcoinjs-lib";
|
|
2
|
+
import { BufferReader } from "../buffertools";
|
|
2
3
|
import { createVarint } from "../varint";
|
|
3
4
|
import { hashLeaf, Merkle } from "./merkle";
|
|
4
5
|
import { MerkleMap } from "./merkleMap";
|
|
@@ -106,19 +107,24 @@ export class GetMerkleLeafProofCommand extends ClientCommand {
|
|
|
106
107
|
execute(request: Buffer): Buffer {
|
|
107
108
|
const req = request.subarray(1);
|
|
108
109
|
|
|
109
|
-
if (req.length
|
|
110
|
-
throw new Error("Invalid request,
|
|
110
|
+
if (req.length < 32 + 1 + 1) {
|
|
111
|
+
throw new Error("Invalid request, expected at least 34 bytes");
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
const hash =
|
|
115
|
-
for (let i = 0; i < 32; i++) {
|
|
116
|
-
hash[i] = req.readUInt8(i);
|
|
117
|
-
}
|
|
114
|
+
const reqBuf = new BufferReader(req);
|
|
115
|
+
const hash = reqBuf.readSlice(32);
|
|
118
116
|
const hash_hex = hash.toString("hex");
|
|
119
117
|
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
let tree_size;
|
|
119
|
+
let leaf_index;
|
|
120
|
+
try {
|
|
121
|
+
tree_size = reqBuf.readVarInt();
|
|
122
|
+
leaf_index = reqBuf.readVarInt();
|
|
123
|
+
} catch (e: any) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
"Invalid request, couldn't parse tree_size or leaf_index"
|
|
126
|
+
);
|
|
127
|
+
}
|
|
122
128
|
|
|
123
129
|
const mt = this.known_trees.get(hash_hex);
|
|
124
130
|
if (!mt) {
|
package/tests/Btc.test.ts
CHANGED
|
@@ -469,6 +469,11 @@ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32m"} | ${false} | ${"
|
|
|
469
469
|
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'"} | ${"bech32"} | ${false} | ${"new"}
|
|
470
470
|
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${undefined} | ${"old"}
|
|
471
471
|
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${true} | ${"new"}
|
|
472
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/0/0"} | ${"bech32"} | ${false} | ${"new"}
|
|
473
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"bech32"} | ${false} | ${"new"}
|
|
474
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"legacy"} | ${false} | ${"new"}
|
|
475
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"p2sh"} | ${false} | ${"new"}
|
|
476
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/2/0"} | ${"bech32"} | ${false} | ${"old"}
|
|
472
477
|
`("dispatch $app $ver $path $format $display to $exp", async ({ app, ver, path, format, display, exp }) => {
|
|
473
478
|
const appName = Buffer.of(app.length)
|
|
474
479
|
.toString("hex")
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
WalletPolicy
|
|
10
10
|
} from "../../src/newops/policy";
|
|
11
11
|
import { PsbtV2 } from "../../src/newops/psbtv2";
|
|
12
|
-
import {
|
|
12
|
+
import { StandardPurpose, addressFormatFromDescriptorTemplate, creatDummyXpub, masterFingerprint, runSignTransaction, TestingClient } from "./integrationtools";
|
|
13
13
|
import { CoreInput, CoreTx, p2pkh, p2tr, p2wpkh, wrappedP2wpkh, wrappedP2wpkhTwoInputs } from "./testtx";
|
|
14
14
|
|
|
15
15
|
test("getWalletPublicKey p2pkh", async () => {
|
|
@@ -40,7 +40,7 @@ test("getWalletXpub normal path", async () => {
|
|
|
40
40
|
await testGetWalletXpub("m/44'/0'/0'");
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
function testPaths(type:
|
|
43
|
+
function testPaths(type: StandardPurpose): { ins: string[], out?: string } {
|
|
44
44
|
const basePath = `m/${type}/1'/0'/`;
|
|
45
45
|
const ins = [
|
|
46
46
|
basePath + "0/0",
|
|
@@ -55,21 +55,21 @@ function testPaths(type: AccountType): { ins: string[], out?: string } {
|
|
|
55
55
|
|
|
56
56
|
test("Sign p2pkh", async () => {
|
|
57
57
|
const changePubkey = "037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cf";
|
|
58
|
-
await runSignTransactionTest(p2pkh,
|
|
58
|
+
await runSignTransactionTest(p2pkh, StandardPurpose.p2pkh, changePubkey);
|
|
59
59
|
});
|
|
60
60
|
test("Sign p2wpkh wrapped", async () => {
|
|
61
61
|
let changePubkey = "03efc6b990c1626d08bd176aab0e545a4f55c627c7ddee878d12bbbc46a126177a";
|
|
62
|
-
await runSignTransactionTest(wrappedP2wpkh,
|
|
62
|
+
await runSignTransactionTest(wrappedP2wpkh, StandardPurpose.p2wpkhInP2sh, changePubkey);
|
|
63
63
|
changePubkey = "031175a985c56e310ce3496a819229b427a2172920fd20b5972dda62758c6def09";
|
|
64
|
-
await runSignTransactionTest(wrappedP2wpkhTwoInputs,
|
|
64
|
+
await runSignTransactionTest(wrappedP2wpkhTwoInputs, StandardPurpose.p2wpkhInP2sh, changePubkey);
|
|
65
65
|
});
|
|
66
66
|
test("Sign p2wpkh", async () => {
|
|
67
|
-
await runSignTransactionTest(p2wpkh,
|
|
67
|
+
await runSignTransactionTest(p2wpkh, StandardPurpose.p2wpkh);
|
|
68
68
|
});
|
|
69
69
|
test("Sign p2tr", async () => {
|
|
70
70
|
// This tx uses locktime, so this test verifies that locktime is propagated to/from
|
|
71
71
|
// the psbt correctly.
|
|
72
|
-
await runSignTransactionTest(p2tr,
|
|
72
|
+
await runSignTransactionTest(p2tr, StandardPurpose.p2tr);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
test("Sign p2tr with sigHashType", async () => {
|
|
@@ -79,16 +79,16 @@ test("Sign p2tr with sigHashType", async () => {
|
|
|
79
79
|
const sig = input.txinwitness![0] + "83";
|
|
80
80
|
input.txinwitness = [sig];
|
|
81
81
|
})
|
|
82
|
-
const tx = await runSignTransactionNoVerification(testTx,
|
|
82
|
+
const tx = await runSignTransactionNoVerification(testTx, StandardPurpose.p2tr);
|
|
83
83
|
// The verification of the sighashtype is done in MockClient.signPsbt
|
|
84
84
|
})
|
|
85
85
|
|
|
86
|
-
async function runSignTransactionTest(testTx: CoreTx, accountType:
|
|
86
|
+
async function runSignTransactionTest(testTx: CoreTx, accountType: StandardPurpose, changePubkey?: string) {
|
|
87
87
|
const tx = await runSignTransactionNoVerification(testTx, accountType, changePubkey);
|
|
88
88
|
expect(tx).toEqual(testTx.hex);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
async function runSignTransactionNoVerification(testTx: CoreTx, accountType:
|
|
91
|
+
async function runSignTransactionNoVerification(testTx: CoreTx, accountType: StandardPurpose, changePubkey?: string): Promise<string> {
|
|
92
92
|
const [client, transport] = await createClient();
|
|
93
93
|
const accountXpub = "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
|
|
94
94
|
client.mockGetPubkeyResponse(`m/${accountType}/1'/0'`, accountXpub);
|
|
@@ -25,10 +25,10 @@ export async function runSignTransaction(
|
|
|
25
25
|
const btc = new Btc(transport);
|
|
26
26
|
const accountType = getAccountType(testTx.vin[0], btc);
|
|
27
27
|
const additionals: string[] = [];
|
|
28
|
-
if (accountType ==
|
|
28
|
+
if (accountType == StandardPurpose.p2wpkh) {
|
|
29
29
|
additionals.push("bech32");
|
|
30
30
|
}
|
|
31
|
-
if (accountType ==
|
|
31
|
+
if (accountType == StandardPurpose.p2tr) {
|
|
32
32
|
additionals.push("bech32m");
|
|
33
33
|
}
|
|
34
34
|
const associatedKeysets: string[] = [];
|
|
@@ -68,7 +68,7 @@ export async function runSignTransaction(
|
|
|
68
68
|
outputScriptHex,
|
|
69
69
|
lockTime: testTx.locktime,
|
|
70
70
|
sigHashType,
|
|
71
|
-
segwit: accountType !=
|
|
71
|
+
segwit: accountType != StandardPurpose.p2pkh,
|
|
72
72
|
onDeviceSignatureGranted: () => logCallback("CALLBACK: signature granted"),
|
|
73
73
|
onDeviceSignatureRequested: () => logCallback("CALLBACK: signature requested"),
|
|
74
74
|
onDeviceStreaming: (arg) => logCallback("CALLBACK: " + JSON.stringify(arg))
|
|
@@ -90,42 +90,42 @@ export function addressFormatFromDescriptorTemplate(descTemp: DefaultDescriptorT
|
|
|
90
90
|
throw new Error();
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
export enum
|
|
93
|
+
export enum StandardPurpose {
|
|
94
94
|
p2tr = "86'",
|
|
95
95
|
p2wpkh = "84'",
|
|
96
96
|
p2wpkhInP2sh = "49'",
|
|
97
97
|
p2pkh = "44'"
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function getPubkey(inputIndex: number, accountType:
|
|
100
|
+
function getPubkey(inputIndex: number, accountType: StandardPurpose, testTx: CoreTx, spentTx: Transaction, spentOutputIndex: number): Buffer {
|
|
101
101
|
const scriptSig = Buffer.from(testTx.vin[inputIndex].scriptSig.hex, "hex");
|
|
102
|
-
if (accountType ==
|
|
102
|
+
if (accountType == StandardPurpose.p2pkh) {
|
|
103
103
|
return scriptSig.slice(scriptSig.length - 33);
|
|
104
104
|
}
|
|
105
|
-
if (accountType ==
|
|
105
|
+
if (accountType == StandardPurpose.p2tr) {
|
|
106
106
|
return spentTx.outputs![spentOutputIndex].script.slice(2, 34); // 32 bytes x-only pubkey
|
|
107
107
|
}
|
|
108
|
-
if (accountType ==
|
|
108
|
+
if (accountType == StandardPurpose.p2wpkh || accountType == StandardPurpose.p2wpkhInP2sh) {
|
|
109
109
|
return Buffer.from(testTx.vin[inputIndex].txinwitness![1], "hex");
|
|
110
110
|
}
|
|
111
111
|
throw new Error();
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
function getSignature(testTxInput: CoreInput, accountType:
|
|
114
|
+
function getSignature(testTxInput: CoreInput, accountType: StandardPurpose): Buffer {
|
|
115
115
|
const scriptSig = Buffer.from(testTxInput.scriptSig.hex, "hex");
|
|
116
|
-
if (accountType ==
|
|
116
|
+
if (accountType == StandardPurpose.p2pkh) {
|
|
117
117
|
return scriptSig.slice(1, scriptSig.length - 34);
|
|
118
118
|
}
|
|
119
|
-
if (accountType ==
|
|
119
|
+
if (accountType == StandardPurpose.p2tr) {
|
|
120
120
|
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
121
121
|
}
|
|
122
|
-
if (accountType ==
|
|
122
|
+
if (accountType == StandardPurpose.p2wpkh || accountType == StandardPurpose.p2wpkhInP2sh) {
|
|
123
123
|
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
124
124
|
}
|
|
125
125
|
throw new Error();
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
function getAccountType(coreInput: CoreInput, btc: Btc):
|
|
128
|
+
function getAccountType(coreInput: CoreInput, btc: Btc): StandardPurpose {
|
|
129
129
|
const spentTx = spentTxs[coreInput.txid];
|
|
130
130
|
if (!spentTx) {
|
|
131
131
|
throw new Error("Spent tx " + coreInput.txid + " unavailable.");
|
|
@@ -134,15 +134,15 @@ function getAccountType(coreInput: CoreInput, btc: Btc): AccountType {
|
|
|
134
134
|
const spentOutput = splitSpentTx.outputs![coreInput.vout];
|
|
135
135
|
const script = spentOutput.script;
|
|
136
136
|
if (script.length == 34 && script[0] == 0x51) {
|
|
137
|
-
return
|
|
137
|
+
return StandardPurpose.p2tr;
|
|
138
138
|
}
|
|
139
139
|
if (script.length == 22 && script[0] == 0x00) {
|
|
140
|
-
return
|
|
140
|
+
return StandardPurpose.p2wpkh;
|
|
141
141
|
}
|
|
142
142
|
if (script.length == 23) {
|
|
143
|
-
return
|
|
143
|
+
return StandardPurpose.p2wpkhInP2sh;
|
|
144
144
|
}
|
|
145
|
-
return
|
|
145
|
+
return StandardPurpose.p2pkh;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export function creatDummyXpub(pubkey: Buffer): string {
|