@ledgerhq/hw-app-btc 6.11.0 → 6.12.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 +110 -47
- package/lib/Btc.d.ts.map +1 -1
- package/lib/Btc.js +5 -3
- package/lib/Btc.js.map +1 -1
- package/lib/BtcNew.d.ts +1 -1
- package/lib/BtcNew.d.ts.map +1 -1
- package/lib/BtcNew.js +71 -174
- 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 +236 -0
- package/lib/newops/accounttype.js.map +1 -0
- package/lib/newops/appClient.d.ts +1 -1
- package/lib/newops/appClient.d.ts.map +1 -1
- package/lib/newops/appClient.js +7 -7
- package/lib/newops/appClient.js.map +1 -1
- package/lib/newops/clientCommands.d.ts +3 -2
- package/lib/newops/clientCommands.d.ts.map +1 -1
- package/lib/newops/clientCommands.js +19 -12
- package/lib/newops/clientCommands.js.map +1 -1
- package/lib/newops/merkle.js +2 -2
- package/lib/newops/merkle.js.map +1 -1
- package/lib/newops/psbtExtractor.js +2 -2
- package/lib/newops/psbtExtractor.js.map +1 -1
- package/lib/newops/psbtv2.d.ts +3 -0
- package/lib/newops/psbtv2.d.ts.map +1 -1
- package/lib/newops/psbtv2.js +14 -4
- package/lib/newops/psbtv2.js.map +1 -1
- package/lib-es/Btc.d.ts.map +1 -1
- package/lib-es/Btc.js +5 -3
- package/lib-es/Btc.js.map +1 -1
- package/lib-es/BtcNew.d.ts +1 -1
- package/lib-es/BtcNew.d.ts.map +1 -1
- package/lib-es/BtcNew.js +73 -176
- 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 +233 -0
- package/lib-es/newops/accounttype.js.map +1 -0
- package/lib-es/newops/appClient.d.ts +1 -1
- package/lib-es/newops/appClient.d.ts.map +1 -1
- package/lib-es/newops/appClient.js +7 -7
- package/lib-es/newops/appClient.js.map +1 -1
- package/lib-es/newops/clientCommands.d.ts +3 -2
- package/lib-es/newops/clientCommands.d.ts.map +1 -1
- package/lib-es/newops/clientCommands.js +19 -12
- package/lib-es/newops/clientCommands.js.map +1 -1
- package/lib-es/newops/merkle.js +2 -2
- package/lib-es/newops/merkle.js.map +1 -1
- package/lib-es/newops/psbtExtractor.js +2 -2
- package/lib-es/newops/psbtExtractor.js.map +1 -1
- package/lib-es/newops/psbtv2.d.ts +3 -0
- package/lib-es/newops/psbtv2.d.ts.map +1 -1
- package/lib-es/newops/psbtv2.js +14 -4
- package/lib-es/newops/psbtv2.js.map +1 -1
- package/package.json +3 -3
- package/src/Btc.ts +34 -3
- package/src/BtcNew.ts +105 -174
- package/src/newops/accounttype.ts +373 -0
- package/src/newops/appClient.ts +8 -7
- package/src/newops/clientCommands.ts +19 -12
- package/src/newops/merkle.ts +2 -2
- package/src/newops/psbtExtractor.ts +2 -2
- package/src/newops/psbtv2.ts +13 -4
- package/tests/Btc.test.ts +68 -39
- package/tests/newops/BtcNew.test.ts +47 -20
- package/tests/newops/integrationtools.ts +91 -50
- package/tests/newops/merkle.test.ts +1 -1
- package/tests/newops/testtx.ts +0 -55
package/tests/Btc.test.ts
CHANGED
|
@@ -106,14 +106,24 @@ ascii(1NjiCsVBuKDT62LmaUd7WZZZBK2gPAkisb)
|
|
|
106
106
|
8bd937d416de7020952cc8e2c99ce9ac7e01265e31ceb8e47bf9c37f46f8abbd
|
|
107
107
|
*/
|
|
108
108
|
/*eslint-disable */
|
|
109
|
-
const pubkeyParent =
|
|
110
|
-
|
|
111
|
-
const
|
|
109
|
+
const pubkeyParent =
|
|
110
|
+
"045d4a72237572a91e13818fa38cedabe6174569cc9a319012f75150d5c0a0639d54eafd13a68d079b7a67764800c6a981825ef52384f08c3925109188ab21bc09";
|
|
111
|
+
const addrParent = Buffer.from(
|
|
112
|
+
"1NjiCsVBuKDT62LmaUd7WZZZBK2gPAkisb",
|
|
113
|
+
"ascii"
|
|
114
|
+
).toString("hex");
|
|
115
|
+
const ccParent =
|
|
116
|
+
"8bd937d416de7020952cc8e2c99ce9ac7e01265e31ceb8e47bf9c37f46f8abbd";
|
|
112
117
|
const responseParent = `41${pubkeyParent}22${addrParent}${ccParent}`;
|
|
113
118
|
|
|
114
|
-
const pubkeyAcc =
|
|
115
|
-
|
|
116
|
-
const
|
|
119
|
+
const pubkeyAcc =
|
|
120
|
+
"04250dfdfb84c1efd160ed0e10ebac845d0e4b04277174630ba56de96bbd3afb21fc6c04ce0d5a0cbd784fdabc99d16269c27cf3842fe8440f1f21b8af900f0eaa";
|
|
121
|
+
const addrAcc = Buffer.from(
|
|
122
|
+
"16Y97ByhyboePhTYMMmFj1tq5Cy1bDq8jT",
|
|
123
|
+
"ascii"
|
|
124
|
+
).toString("hex");
|
|
125
|
+
const ccAcc =
|
|
126
|
+
"c071c6f2d05cbc9ea9a04951b238086ce1608cf00020c3cab85b36aac5fdd591";
|
|
117
127
|
/*eslint-enable */
|
|
118
128
|
const responseAcc = `41${pubkeyAcc}22${addrAcc}${ccAcc}`;
|
|
119
129
|
const transport = await openTransportReplayer(
|
|
@@ -123,7 +133,7 @@ ascii(1NjiCsVBuKDT62LmaUd7WZZZBK2gPAkisb)
|
|
|
123
133
|
=> e040000009028000002c80000000
|
|
124
134
|
<= ${responseParent}9000
|
|
125
135
|
=> e04000000d038000002c8000000080000011
|
|
126
|
-
<= ${responseAcc}9000
|
|
136
|
+
<= ${responseAcc}9000
|
|
127
137
|
`)
|
|
128
138
|
);
|
|
129
139
|
const btc = new Btc(transport);
|
|
@@ -430,7 +440,7 @@ test("signMessage", async () => {
|
|
|
430
440
|
function testBackend(s: string): any {
|
|
431
441
|
return async () => {
|
|
432
442
|
return { publicKey: s, bitcoinAddress: "", chainCode: "" };
|
|
433
|
-
}
|
|
443
|
+
};
|
|
434
444
|
}
|
|
435
445
|
|
|
436
446
|
class TestBtc extends Btc {
|
|
@@ -461,37 +471,51 @@ class TestBtc extends Btc {
|
|
|
461
471
|
// });
|
|
462
472
|
|
|
463
473
|
test.each`
|
|
464
|
-
app | ver
|
|
465
|
-
${"Bitcoin"} | ${"1.99.99"}
|
|
466
|
-
${"Bitcoin"} | ${"1.99.99"}
|
|
467
|
-
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'"}
|
|
468
|
-
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"}
|
|
469
|
-
${"Bitcoin"} | ${"2.0.0-
|
|
470
|
-
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"}
|
|
471
|
-
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
474
|
+
app | ver | path | format | display | exp
|
|
475
|
+
${"Bitcoin"} | ${"1.99.99"} | ${"m/44'/0'/1'"} | ${"bech32m"} | ${false} | ${""}
|
|
476
|
+
${"Bitcoin"} | ${"1.99.99"} | ${"m/44'/0'"} | ${"bech32m"} | ${false} | ${""}
|
|
477
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'"} | ${"bech32m"} | ${false} | ${"new"}
|
|
478
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32m"} | ${false} | ${"new"}
|
|
479
|
+
${"Bitcoin"} | ${"2.0.0-beta"} | ${"m/84'/1'/0'"} | ${"bech32"} | ${false} | ${"new"}
|
|
480
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'"} | ${"bech32"} | ${false} | ${"new"}
|
|
481
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${undefined} | ${"old"}
|
|
482
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${true} | ${"new"}
|
|
483
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/0/0"} | ${"bech32"} | ${false} | ${"new"}
|
|
484
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"bech32"} | ${false} | ${"new"}
|
|
485
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"legacy"} | ${false} | ${"new"}
|
|
486
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"p2sh"} | ${false} | ${"new"}
|
|
487
|
+
${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/2/0"} | ${"bech32"} | ${false} | ${"old"}
|
|
488
|
+
`(
|
|
489
|
+
"dispatch $app $ver $path $format $display to $exp",
|
|
490
|
+
async ({ app, ver, path, format, display, exp }) => {
|
|
491
|
+
const appName = Buffer.from([app.length])
|
|
492
|
+
.toString("hex")
|
|
493
|
+
.concat(Buffer.from(app, "ascii").toString("hex"));
|
|
494
|
+
const appVersion = Buffer.from([ver.length])
|
|
495
|
+
.toString("hex")
|
|
496
|
+
.concat(Buffer.from(ver, "ascii").toString("hex"));
|
|
497
|
+
const resp = `01${appName}${appVersion}01029000`;
|
|
498
|
+
const tr = await openTransportReplayer(
|
|
499
|
+
RecordStore.fromString(`=> b001000000\n <= ${resp}`)
|
|
500
|
+
);
|
|
501
|
+
const btc = new TestBtc(tr);
|
|
502
|
+
try {
|
|
503
|
+
const key = await btc.getWalletPublicKey(path, {
|
|
504
|
+
format: format,
|
|
505
|
+
verify: display,
|
|
506
|
+
});
|
|
507
|
+
if (exp === "") {
|
|
508
|
+
expect(1).toEqual(0); // Allways fail. Don't know how to do that properly
|
|
509
|
+
}
|
|
510
|
+
expect(key.publicKey).toEqual(exp);
|
|
511
|
+
} catch (e: any) {
|
|
512
|
+
if (exp != "") {
|
|
513
|
+
throw e;
|
|
514
|
+
}
|
|
515
|
+
expect(exp).toEqual("");
|
|
491
516
|
}
|
|
492
|
-
expect(exp).toEqual("");
|
|
493
517
|
}
|
|
494
|
-
|
|
518
|
+
);
|
|
495
519
|
|
|
496
520
|
// test("getWalletPublicKey compatibility for internal hardened keys", async () => {
|
|
497
521
|
// await testDispatch("Bitcoin", "1.99.99", "m/44'/0'/1'", "bech32m", "");
|
|
@@ -502,5 +526,10 @@ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${true} | ${"ne
|
|
|
502
526
|
// await testDispatch("Bitcoin", "2.0.0-alpha1", "m/44'/0'", "bech32", "old");
|
|
503
527
|
// });
|
|
504
528
|
|
|
505
|
-
async function testDispatch(
|
|
506
|
-
|
|
529
|
+
async function testDispatch(
|
|
530
|
+
name: string,
|
|
531
|
+
version: string,
|
|
532
|
+
path: string,
|
|
533
|
+
addressFormat: AddressFormat | undefined,
|
|
534
|
+
exp: string
|
|
535
|
+
): Promise<void> {}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
-
/* eslint-disable prettier/prettier */
|
|
3
2
|
import { openTransportReplayer, RecordStore } from "@ledgerhq/hw-transport-mocker";
|
|
4
3
|
import { TransportReplayer } from "@ledgerhq/hw-transport-mocker/lib/openTransportReplayer";
|
|
5
4
|
import ecc from "tiny-secp256k1";
|
|
@@ -10,8 +9,8 @@ import {
|
|
|
10
9
|
WalletPolicy
|
|
11
10
|
} from "../../src/newops/policy";
|
|
12
11
|
import { PsbtV2 } from "../../src/newops/psbtv2";
|
|
13
|
-
import {
|
|
14
|
-
import { CoreTx, p2pkh, p2tr, p2wpkh,
|
|
12
|
+
import { StandardPurpose, addressFormatFromDescriptorTemplate, creatDummyXpub, masterFingerprint, runSignTransaction, TestingClient } from "./integrationtools";
|
|
13
|
+
import { CoreInput, CoreTx, p2pkh, p2tr, p2wpkh, wrappedP2wpkh, wrappedP2wpkhTwoInputs } from "./testtx";
|
|
15
14
|
|
|
16
15
|
test("getWalletPublicKey p2pkh", async () => {
|
|
17
16
|
await testGetWalletPublicKey("m/44'/1'/0'", "pkh(@0)");
|
|
@@ -41,7 +40,7 @@ test("getWalletXpub normal path", async () => {
|
|
|
41
40
|
await testGetWalletXpub("m/44'/0'/0'");
|
|
42
41
|
});
|
|
43
42
|
|
|
44
|
-
function testPaths(type:
|
|
43
|
+
function testPaths(type: StandardPurpose): { ins: string[], out?: string } {
|
|
45
44
|
const basePath = `m/${type}/1'/0'/`;
|
|
46
45
|
const ins = [
|
|
47
46
|
basePath + "0/0",
|
|
@@ -51,48 +50,64 @@ function testPaths(type: AccountType): {ins: string[], out?: string} {
|
|
|
51
50
|
basePath + "0/2",
|
|
52
51
|
basePath + "1/2",
|
|
53
52
|
];
|
|
54
|
-
return {ins};
|
|
53
|
+
return { ins };
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
test("Sign p2pkh", async () => {
|
|
58
57
|
const changePubkey = "037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cf";
|
|
59
|
-
await runSignTransactionTest(p2pkh,
|
|
58
|
+
await runSignTransactionTest(p2pkh, StandardPurpose.p2pkh, changePubkey);
|
|
60
59
|
});
|
|
61
60
|
test("Sign p2wpkh wrapped", async () => {
|
|
62
61
|
let changePubkey = "03efc6b990c1626d08bd176aab0e545a4f55c627c7ddee878d12bbbc46a126177a";
|
|
63
|
-
await runSignTransactionTest(wrappedP2wpkh,
|
|
62
|
+
await runSignTransactionTest(wrappedP2wpkh, StandardPurpose.p2wpkhInP2sh, changePubkey);
|
|
64
63
|
changePubkey = "031175a985c56e310ce3496a819229b427a2172920fd20b5972dda62758c6def09";
|
|
65
|
-
await runSignTransactionTest(wrappedP2wpkhTwoInputs,
|
|
64
|
+
await runSignTransactionTest(wrappedP2wpkhTwoInputs, StandardPurpose.p2wpkhInP2sh, changePubkey);
|
|
66
65
|
});
|
|
67
66
|
test("Sign p2wpkh", async () => {
|
|
68
|
-
await runSignTransactionTest(p2wpkh,
|
|
69
|
-
await runSignTransactionTest(p2wpkhTwoInputs, AccountType.p2wpkh);
|
|
67
|
+
await runSignTransactionTest(p2wpkh, StandardPurpose.p2wpkh);
|
|
70
68
|
});
|
|
71
69
|
test("Sign p2tr", async () => {
|
|
72
|
-
|
|
70
|
+
// This tx uses locktime, so this test verifies that locktime is propagated to/from
|
|
71
|
+
// the psbt correctly.
|
|
72
|
+
await runSignTransactionTest(p2tr, StandardPurpose.p2tr);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
test("Sign p2tr with sigHashType", async () => {
|
|
76
|
+
const testTx = JSON.parse(JSON.stringify(p2tr));
|
|
77
|
+
testTx.vin.forEach((input: CoreInput, index: number) => {
|
|
78
|
+
// Test SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, 0x83
|
|
79
|
+
const sig = input.txinwitness![0] + "83";
|
|
80
|
+
input.txinwitness = [sig];
|
|
81
|
+
})
|
|
82
|
+
const tx = await runSignTransactionNoVerification(testTx, StandardPurpose.p2tr);
|
|
83
|
+
// The verification of the sighashtype is done in MockClient.signPsbt
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
async function runSignTransactionTest(testTx: CoreTx, accountType: StandardPurpose, changePubkey?: string) {
|
|
87
|
+
const tx = await runSignTransactionNoVerification(testTx, accountType, changePubkey);
|
|
88
|
+
expect(tx).toEqual(testTx.hex);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function runSignTransactionNoVerification(testTx: CoreTx, accountType: StandardPurpose, changePubkey?: string): Promise<string> {
|
|
76
92
|
const [client, transport] = await createClient();
|
|
77
93
|
const accountXpub = "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
|
|
78
94
|
client.mockGetPubkeyResponse(`m/${accountType}/1'/0'`, accountXpub);
|
|
79
95
|
const paths = testPaths(accountType);
|
|
80
96
|
if (changePubkey) {
|
|
81
|
-
paths.out =
|
|
97
|
+
paths.out = `m/${accountType}/1'/0'` + "/1/3";
|
|
82
98
|
client.mockGetPubkeyResponse(paths.out, creatDummyXpub(Buffer.from(changePubkey, "hex")));
|
|
83
99
|
}
|
|
84
100
|
const tx = await runSignTransaction(testTx, paths, client, transport);
|
|
85
|
-
expect(tx).toEqual(testTx.hex);
|
|
86
101
|
await transport.close();
|
|
102
|
+
return tx;
|
|
87
103
|
}
|
|
88
104
|
|
|
89
|
-
|
|
90
105
|
async function testGetWalletXpub(path: string, version = 0x043587cf) {
|
|
91
106
|
const [client] = await createClient();
|
|
92
107
|
const expectedXpub = "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
|
|
93
108
|
client.mockGetPubkeyResponse(path, expectedXpub);
|
|
94
109
|
const btc = new BtcNew(client);
|
|
95
|
-
const result = await btc.getWalletXpub({path: path, xpubVersion: version});
|
|
110
|
+
const result = await btc.getWalletXpub({ path: path, xpubVersion: version });
|
|
96
111
|
expect(result).toEqual(expectedXpub);
|
|
97
112
|
}
|
|
98
113
|
async function testGetWalletPublicKey(
|
|
@@ -119,7 +134,7 @@ async function testGetWalletPublicKey(
|
|
|
119
134
|
|
|
120
135
|
const btcNew = new BtcNew(client);
|
|
121
136
|
const addressFormat = addressFormatFromDescriptorTemplate(expectedDescriptorTemplate);
|
|
122
|
-
const result = await btcNew.getWalletPublicKey(path, {format: addressFormat});
|
|
137
|
+
const result = await btcNew.getWalletPublicKey(path, { format: addressFormat });
|
|
123
138
|
verifyGetWalletPublicKeyResult(result, keyXpub, "testaddress");
|
|
124
139
|
|
|
125
140
|
const resultAccount = await btcNew.getWalletPublicKey(accountPath);
|
|
@@ -195,11 +210,23 @@ class MockClient extends TestingClient {
|
|
|
195
210
|
return masterFingerprint;
|
|
196
211
|
}
|
|
197
212
|
async signPsbt(
|
|
198
|
-
|
|
213
|
+
psbt: PsbtV2,
|
|
199
214
|
_walletPolicy: WalletPolicy,
|
|
200
|
-
_walletHMAC: Buffer | null
|
|
215
|
+
_walletHMAC: Buffer | null,
|
|
201
216
|
): Promise<Map<number, Buffer>> {
|
|
202
|
-
|
|
217
|
+
const sigs = this.yieldSigs.splice(0, 1)[0];
|
|
218
|
+
const sig0 = sigs.get(0)!;
|
|
219
|
+
if (sig0.length == 64) {
|
|
220
|
+
// Taproot may leave out sighash type, which defaults to 0x01 SIGHASH_ALL
|
|
221
|
+
return sigs;
|
|
222
|
+
}
|
|
223
|
+
const sigHashType = sig0.readUInt8(sig0.length - 1);
|
|
224
|
+
if (sigHashType != 0x01) {
|
|
225
|
+
for (let i = 0; i < psbt.getGlobalInputCount(); i++) {
|
|
226
|
+
expect(psbt.getInputSighashType(i)).toEqual(sigHashType);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return sigs;
|
|
203
230
|
}
|
|
204
231
|
private getWalletAddressKey(
|
|
205
232
|
walletPolicy: WalletPolicy,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
-
/* eslint-disable prettier/prettier */
|
|
3
2
|
import Transport from "@ledgerhq/hw-transport";
|
|
4
3
|
import bs58check from "bs58check";
|
|
5
4
|
import Btc from "../../src/Btc";
|
|
@@ -10,26 +9,26 @@ import { AddressFormat } from "../../src/getWalletPublicKey";
|
|
|
10
9
|
import { AppClient } from "../../src/newops/appClient";
|
|
11
10
|
import {
|
|
12
11
|
DefaultDescriptorTemplate,
|
|
13
|
-
WalletPolicy
|
|
12
|
+
WalletPolicy,
|
|
14
13
|
} from "../../src/newops/policy";
|
|
15
14
|
import { Transaction } from "../../src/types";
|
|
16
15
|
import { CoreInput, CoreTx, spentTxs } from "./testtx";
|
|
17
16
|
|
|
18
|
-
|
|
19
17
|
export async function runSignTransaction(
|
|
20
|
-
testTx: CoreTx,
|
|
21
|
-
testPaths: {ins: string[]
|
|
22
|
-
client: TestingClient,
|
|
23
|
-
transport: Transport
|
|
18
|
+
testTx: CoreTx,
|
|
19
|
+
testPaths: { ins: string[]; out?: string },
|
|
20
|
+
client: TestingClient,
|
|
21
|
+
transport: Transport
|
|
22
|
+
): Promise<string> {
|
|
24
23
|
const btcNew = new BtcNew(client);
|
|
25
24
|
// btc is needed to perform some functions like splitTransaction.
|
|
26
25
|
const btc = new Btc(transport);
|
|
27
26
|
const accountType = getAccountType(testTx.vin[0], btc);
|
|
28
27
|
const additionals: string[] = [];
|
|
29
|
-
if (accountType ==
|
|
28
|
+
if (accountType == StandardPurpose.p2wpkh) {
|
|
30
29
|
additionals.push("bech32");
|
|
31
30
|
}
|
|
32
|
-
if (accountType ==
|
|
31
|
+
if (accountType == StandardPurpose.p2tr) {
|
|
33
32
|
additionals.push("bech32m");
|
|
34
33
|
}
|
|
35
34
|
const associatedKeysets: string[] = [];
|
|
@@ -38,35 +37,61 @@ export async function runSignTransaction(
|
|
|
38
37
|
const path = testPaths.ins[index];
|
|
39
38
|
associatedKeysets.push(path);
|
|
40
39
|
const inputData = createInput(input, btc);
|
|
41
|
-
const pubkey = getPubkey(
|
|
40
|
+
const pubkey = getPubkey(
|
|
41
|
+
index,
|
|
42
|
+
accountType,
|
|
43
|
+
testTx,
|
|
44
|
+
inputData[0],
|
|
45
|
+
inputData[1]
|
|
46
|
+
);
|
|
42
47
|
const mockXpub = creatDummyXpub(pubkey);
|
|
43
48
|
client.mockGetPubkeyResponse(path, mockXpub);
|
|
44
49
|
yieldSigs.set(index, getSignature(input, accountType));
|
|
45
50
|
return inputData;
|
|
46
51
|
});
|
|
52
|
+
const sig0 = yieldSigs.get(0)!;
|
|
53
|
+
let sigHashType: number | undefined = sig0.readUInt8(sig0.length - 1);
|
|
54
|
+
if (sigHashType == 0x01) {
|
|
55
|
+
sigHashType = undefined;
|
|
56
|
+
}
|
|
47
57
|
client.mockSignPsbt(yieldSigs);
|
|
48
58
|
const outputWriter = new BufferWriter();
|
|
49
59
|
outputWriter.writeVarInt(testTx.vout.length);
|
|
50
|
-
testTx.vout.forEach(output => {
|
|
51
|
-
outputWriter.writeUInt64(
|
|
52
|
-
|
|
60
|
+
testTx.vout.forEach((output) => {
|
|
61
|
+
outputWriter.writeUInt64(
|
|
62
|
+
BigInt(Number.parseFloat((output.value * 100000000).toFixed(8)))
|
|
63
|
+
);
|
|
64
|
+
outputWriter.writeVarSlice(Buffer.from(output.scriptPubKey.hex, "hex"));
|
|
53
65
|
});
|
|
54
|
-
const outputScriptHex = outputWriter.buffer().toString("hex");
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
const outputScriptHex = outputWriter.buffer().toString("hex");
|
|
67
|
+
let callbacks = "";
|
|
68
|
+
function logCallback(message: string) {
|
|
69
|
+
callbacks += new Date().toISOString() + " " + message + "\n";
|
|
70
|
+
}
|
|
71
|
+
const arg: CreateTransactionArg = {
|
|
57
72
|
inputs,
|
|
58
73
|
additionals,
|
|
59
74
|
associatedKeysets,
|
|
60
75
|
changePath: testPaths.out,
|
|
61
76
|
outputScriptHex,
|
|
62
77
|
lockTime: testTx.locktime,
|
|
63
|
-
|
|
78
|
+
sigHashType,
|
|
79
|
+
segwit: accountType != StandardPurpose.p2pkh,
|
|
80
|
+
onDeviceSignatureGranted: () => logCallback("CALLBACK: signature granted"),
|
|
81
|
+
onDeviceSignatureRequested: () =>
|
|
82
|
+
logCallback("CALLBACK: signature requested"),
|
|
83
|
+
onDeviceStreaming: (arg) => logCallback("CALLBACK: " + JSON.stringify(arg)),
|
|
64
84
|
};
|
|
85
|
+
logCallback("Start createPaymentTransactionNew");
|
|
65
86
|
const tx = await btcNew.createPaymentTransactionNew(arg);
|
|
87
|
+
logCallback("Done createPaymentTransactionNew");
|
|
88
|
+
// console.log(callbacks);
|
|
66
89
|
return tx;
|
|
67
|
-
}
|
|
90
|
+
}
|
|
68
91
|
|
|
69
|
-
export function addressFormatFromDescriptorTemplate(
|
|
92
|
+
export function addressFormatFromDescriptorTemplate(
|
|
93
|
+
descTemp: DefaultDescriptorTemplate
|
|
94
|
+
): AddressFormat {
|
|
70
95
|
if (descTemp == "tr(@0)") return "bech32m";
|
|
71
96
|
if (descTemp == "pkh(@0)") return "legacy";
|
|
72
97
|
if (descTemp == "wpkh(@0)") return "bech32";
|
|
@@ -74,42 +99,57 @@ export function addressFormatFromDescriptorTemplate(descTemp: DefaultDescriptorT
|
|
|
74
99
|
throw new Error();
|
|
75
100
|
}
|
|
76
101
|
|
|
77
|
-
export enum
|
|
102
|
+
export enum StandardPurpose {
|
|
78
103
|
p2tr = "86'",
|
|
79
104
|
p2wpkh = "84'",
|
|
80
105
|
p2wpkhInP2sh = "49'",
|
|
81
|
-
p2pkh = "44'"
|
|
106
|
+
p2pkh = "44'",
|
|
82
107
|
}
|
|
83
108
|
|
|
84
|
-
function getPubkey(
|
|
109
|
+
function getPubkey(
|
|
110
|
+
inputIndex: number,
|
|
111
|
+
accountType: StandardPurpose,
|
|
112
|
+
testTx: CoreTx,
|
|
113
|
+
spentTx: Transaction,
|
|
114
|
+
spentOutputIndex: number
|
|
115
|
+
): Buffer {
|
|
85
116
|
const scriptSig = Buffer.from(testTx.vin[inputIndex].scriptSig.hex, "hex");
|
|
86
|
-
if (accountType ==
|
|
87
|
-
return scriptSig.slice(scriptSig.length-33);
|
|
117
|
+
if (accountType == StandardPurpose.p2pkh) {
|
|
118
|
+
return scriptSig.slice(scriptSig.length - 33);
|
|
88
119
|
}
|
|
89
|
-
if (accountType ==
|
|
120
|
+
if (accountType == StandardPurpose.p2tr) {
|
|
90
121
|
return spentTx.outputs![spentOutputIndex].script.slice(2, 34); // 32 bytes x-only pubkey
|
|
91
122
|
}
|
|
92
|
-
if (
|
|
123
|
+
if (
|
|
124
|
+
accountType == StandardPurpose.p2wpkh ||
|
|
125
|
+
accountType == StandardPurpose.p2wpkhInP2sh
|
|
126
|
+
) {
|
|
93
127
|
return Buffer.from(testTx.vin[inputIndex].txinwitness![1], "hex");
|
|
94
128
|
}
|
|
95
129
|
throw new Error();
|
|
96
130
|
}
|
|
97
131
|
|
|
98
|
-
function getSignature(
|
|
132
|
+
function getSignature(
|
|
133
|
+
testTxInput: CoreInput,
|
|
134
|
+
accountType: StandardPurpose
|
|
135
|
+
): Buffer {
|
|
99
136
|
const scriptSig = Buffer.from(testTxInput.scriptSig.hex, "hex");
|
|
100
|
-
if (accountType ==
|
|
101
|
-
return scriptSig.slice(1, scriptSig.length-34);
|
|
137
|
+
if (accountType == StandardPurpose.p2pkh) {
|
|
138
|
+
return scriptSig.slice(1, scriptSig.length - 34);
|
|
102
139
|
}
|
|
103
|
-
if (accountType ==
|
|
140
|
+
if (accountType == StandardPurpose.p2tr) {
|
|
104
141
|
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
105
142
|
}
|
|
106
|
-
if (
|
|
143
|
+
if (
|
|
144
|
+
accountType == StandardPurpose.p2wpkh ||
|
|
145
|
+
accountType == StandardPurpose.p2wpkhInP2sh
|
|
146
|
+
) {
|
|
107
147
|
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
108
148
|
}
|
|
109
149
|
throw new Error();
|
|
110
150
|
}
|
|
111
151
|
|
|
112
|
-
function getAccountType(coreInput: CoreInput, btc: Btc):
|
|
152
|
+
function getAccountType(coreInput: CoreInput, btc: Btc): StandardPurpose {
|
|
113
153
|
const spentTx = spentTxs[coreInput.txid];
|
|
114
154
|
if (!spentTx) {
|
|
115
155
|
throw new Error("Spent tx " + coreInput.txid + " unavailable.");
|
|
@@ -118,46 +158,47 @@ function getAccountType(coreInput: CoreInput, btc: Btc): AccountType {
|
|
|
118
158
|
const spentOutput = splitSpentTx.outputs![coreInput.vout];
|
|
119
159
|
const script = spentOutput.script;
|
|
120
160
|
if (script.length == 34 && script[0] == 0x51) {
|
|
121
|
-
return
|
|
161
|
+
return StandardPurpose.p2tr;
|
|
122
162
|
}
|
|
123
163
|
if (script.length == 22 && script[0] == 0x00) {
|
|
124
|
-
return
|
|
164
|
+
return StandardPurpose.p2wpkh;
|
|
125
165
|
}
|
|
126
166
|
if (script.length == 23) {
|
|
127
|
-
return
|
|
167
|
+
return StandardPurpose.p2wpkhInP2sh;
|
|
128
168
|
}
|
|
129
|
-
return
|
|
169
|
+
return StandardPurpose.p2pkh;
|
|
130
170
|
}
|
|
131
171
|
|
|
132
172
|
export function creatDummyXpub(pubkey: Buffer): string {
|
|
133
|
-
const xpubDecoded = bs58check.decode(
|
|
134
|
-
|
|
135
|
-
|
|
173
|
+
const xpubDecoded = bs58check.decode(
|
|
174
|
+
"tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd"
|
|
175
|
+
);
|
|
176
|
+
const pubkey33 =
|
|
177
|
+
pubkey.length == 33 ? pubkey : Buffer.concat([Buffer.from([2]), pubkey]);
|
|
178
|
+
xpubDecoded.fill(pubkey33, xpubDecoded.length - 33);
|
|
136
179
|
return bs58check.encode(xpubDecoded);
|
|
137
180
|
}
|
|
138
181
|
|
|
139
|
-
function createInput(
|
|
182
|
+
function createInput(
|
|
183
|
+
coreInput: CoreInput,
|
|
184
|
+
btc: Btc
|
|
185
|
+
): [Transaction, number, string | null, number] {
|
|
140
186
|
const spentTx = spentTxs[coreInput.txid];
|
|
141
187
|
if (!spentTx) {
|
|
142
188
|
throw new Error("Spent tx " + coreInput.txid + " unavailable.");
|
|
143
189
|
}
|
|
144
190
|
const splitSpentTx = btc.splitTransaction(spentTx, true);
|
|
145
|
-
|
|
146
|
-
let redeemScript;
|
|
147
|
-
if (scriptSig?.hex && scriptSig.hex.startsWith("160014")) {
|
|
148
|
-
redeemScript = scriptSig.hex.substring(2);
|
|
149
|
-
}
|
|
150
|
-
return [splitSpentTx, coreInput.vout, redeemScript, coreInput.sequence];
|
|
191
|
+
return [splitSpentTx, coreInput.vout, null, coreInput.sequence];
|
|
151
192
|
}
|
|
152
193
|
|
|
153
|
-
export const masterFingerprint = Buffer.
|
|
194
|
+
export const masterFingerprint = Buffer.from([1, 2, 3, 4]);
|
|
154
195
|
export class TestingClient extends AppClient {
|
|
155
|
-
mockGetPubkeyResponse(_pathElements: string, _response: string): void {}
|
|
196
|
+
mockGetPubkeyResponse(_pathElements: string, _response: string): void {}
|
|
156
197
|
mockGetWalletAddressResponse(
|
|
157
198
|
_walletPolicy: WalletPolicy,
|
|
158
199
|
_change: number,
|
|
159
200
|
_addressIndex: number,
|
|
160
201
|
_response: string
|
|
161
|
-
): void {}
|
|
162
|
-
mockSignPsbt(_yieldSigs: Map<number, Buffer>): void {}
|
|
202
|
+
): void {}
|
|
203
|
+
mockSignPsbt(_yieldSigs: Map<number, Buffer>): void {}
|
|
163
204
|
}
|
package/tests/newops/testtx.ts
CHANGED
|
@@ -237,61 +237,6 @@ export const p2pkh: CoreTx = {
|
|
|
237
237
|
"blocktime": 1633611385
|
|
238
238
|
};
|
|
239
239
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
240
|
-
export const p2wpkhTwoInputs = {
|
|
241
|
-
"txid": "1913b7b5ffdcb5f32b9aca1f5eec2a189e7c66650f82b560eae211265fc995b7",
|
|
242
|
-
"hash": "c3439dcd3489373c586c7aed48c32f2b5d9c71aad24acd765a61684d98690a3f",
|
|
243
|
-
"version": 2,
|
|
244
|
-
"size": 388,
|
|
245
|
-
"vsize": 226,
|
|
246
|
-
"weight": 904,
|
|
247
|
-
"locktime": 0,
|
|
248
|
-
"vin": [
|
|
249
|
-
{
|
|
250
|
-
"txid": "5512d5788d4c26117f093de91223ef384c3fb22799810a92e3304bb6f0819224",
|
|
251
|
-
"vout": 1,
|
|
252
|
-
"scriptSig": {
|
|
253
|
-
"asm": "0014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3",
|
|
254
|
-
"hex": "160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3"
|
|
255
|
-
},
|
|
256
|
-
"txinwitness": [
|
|
257
|
-
"30440220543617c5f4504dc29d34d2d06d0d7733dac4ec418b77c67feefb29f3f82ba3d80220690b784c52c3375f4ba9e64cc5c0aeb6a1b9fc6aadda0062905c06ce3bbba57501",
|
|
258
|
-
"02fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e441"
|
|
259
|
-
],
|
|
260
|
-
"sequence": 4294967295
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
"txid": "28ad5054e029252d72da37f13fce66212d7f7763845b4a8c4aaf78e897b2bf9f",
|
|
264
|
-
"vout": 1,
|
|
265
|
-
"scriptSig": {
|
|
266
|
-
"asm": "0014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3",
|
|
267
|
-
"hex": "160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3"
|
|
268
|
-
},
|
|
269
|
-
"txinwitness": [
|
|
270
|
-
"3044022049e7f3015a33ccdb015fe3891667564fd37111272df57e58447645c7bad8fed0022074d1e93ba946453896d0f0bc500df3a1e0d5bb5ad10cd9906736d5fbaebadd5801",
|
|
271
|
-
"02fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e441"
|
|
272
|
-
],
|
|
273
|
-
"sequence": 4294967295
|
|
274
|
-
}
|
|
275
|
-
],
|
|
276
|
-
"vout": [
|
|
277
|
-
{
|
|
278
|
-
"value": 0.01800000,
|
|
279
|
-
"n": 0,
|
|
280
|
-
"scriptPubKey": {
|
|
281
|
-
"asm": "OP_DUP OP_HASH160 f73384bcc3951ab6a75541ff79a9a51f82056ed8 OP_EQUALVERIFY OP_CHECKSIG",
|
|
282
|
-
"hex": "76a914f73384bcc3951ab6a75541ff79a9a51f82056ed888ac",
|
|
283
|
-
"address": "n442v1DrXQNim9gjjctKjyGVoe717hNdtG",
|
|
284
|
-
"type": "pubkeyhash"
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
],
|
|
288
|
-
"hex": "02000000000102249281f0b64b30e3920a819927b23f4c38ef2312e93d097f11264c8d78d512550100000017160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3ffffffff9fbfb297e878af4a8c4a5b8463777f2d2166ce3ff137da722d2529e05450ad280100000017160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3ffffffff0140771b00000000001976a914f73384bcc3951ab6a75541ff79a9a51f82056ed888ac024730440220543617c5f4504dc29d34d2d06d0d7733dac4ec418b77c67feefb29f3f82ba3d80220690b784c52c3375f4ba9e64cc5c0aeb6a1b9fc6aadda0062905c06ce3bbba575012102fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e44102473044022049e7f3015a33ccdb015fe3891667564fd37111272df57e58447645c7bad8fed0022074d1e93ba946453896d0f0bc500df3a1e0d5bb5ad10cd9906736d5fbaebadd58012102fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e44100000000",
|
|
289
|
-
"blockhash": "00000000025a711e6cd4bce9138dc852232a4494afbf36d8bb80499a786da2a4",
|
|
290
|
-
"confirmations": 1,
|
|
291
|
-
"time": 1633944124,
|
|
292
|
-
"blocktime": 1633944124
|
|
293
|
-
};
|
|
294
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
295
240
|
export const wrappedP2wpkhTwoInputs = {
|
|
296
241
|
"txid": "c03119b538c78f56c8ce2e6cc5fc6998d447eeef42e34c12692764a3f1a3da7c",
|
|
297
242
|
"hash": "6b3812304554a6964e43a6971ac533046f4be101e39609f72179856916e20268",
|