@ledgerhq/hw-app-btc 6.2.0 → 6.9.1-6.9.1-taproot.0.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 (187) hide show
  1. package/lib/Btc.d.ts +7 -3
  2. package/lib/Btc.d.ts.map +1 -1
  3. package/lib/Btc.js +99 -30
  4. package/lib/Btc.js.map +1 -1
  5. package/lib/BtcNew.d.ts +70 -0
  6. package/lib/BtcNew.d.ts.map +1 -0
  7. package/lib/BtcNew.js +372 -0
  8. package/lib/BtcNew.js.map +1 -0
  9. package/lib/BtcOld.d.ts +114 -0
  10. package/lib/BtcOld.d.ts.map +1 -0
  11. package/lib/BtcOld.js +138 -0
  12. package/lib/BtcOld.js.map +1 -0
  13. package/lib/bip32.d.ts +8 -0
  14. package/lib/bip32.d.ts.map +1 -1
  15. package/lib/bip32.js +32 -3
  16. package/lib/bip32.js.map +1 -1
  17. package/lib/buffertools.d.ts +28 -0
  18. package/lib/buffertools.d.ts.map +1 -0
  19. package/lib/buffertools.js +100 -0
  20. package/lib/buffertools.js.map +1 -0
  21. package/lib/createTransaction.d.ts.map +1 -1
  22. package/lib/createTransaction.js +16 -16
  23. package/lib/createTransaction.js.map +1 -1
  24. package/lib/finalizeInput.js +1 -1
  25. package/lib/finalizeInput.js.map +1 -1
  26. package/lib/getAppAndVersion.js +1 -1
  27. package/lib/getAppAndVersion.js.map +1 -1
  28. package/lib/getTrustedInput.js +6 -6
  29. package/lib/getTrustedInput.js.map +1 -1
  30. package/lib/getTrustedInputBIP143.js +2 -2
  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 +1 -1
  35. package/lib/getWalletPublicKey.js.map +1 -1
  36. package/lib/hashPublicKey.d.ts +1 -1
  37. package/lib/hashPublicKey.d.ts.map +1 -1
  38. package/lib/hashPublicKey.js +1 -1
  39. package/lib/hashPublicKey.js.map +1 -1
  40. package/lib/index.d.ts +3 -0
  41. package/lib/index.d.ts.map +1 -0
  42. package/lib/index.js +8 -0
  43. package/lib/index.js.map +1 -0
  44. package/lib/newops/appClient.d.ts +14 -0
  45. package/lib/newops/appClient.d.ts.map +1 -0
  46. package/lib/newops/appClient.js +242 -0
  47. package/lib/newops/appClient.js.map +1 -0
  48. package/lib/newops/clientCommands.d.ts +61 -0
  49. package/lib/newops/clientCommands.d.ts.map +1 -0
  50. package/lib/newops/clientCommands.js +331 -0
  51. package/lib/newops/clientCommands.js.map +1 -0
  52. package/lib/newops/merkelizedPsbt.d.ts +15 -0
  53. package/lib/newops/merkelizedPsbt.d.ts.map +1 -0
  54. package/lib/newops/merkelizedPsbt.js +91 -0
  55. package/lib/newops/merkelizedPsbt.js.map +1 -0
  56. package/lib/newops/merkle.d.ts +29 -0
  57. package/lib/newops/merkle.d.ts.map +1 -0
  58. package/lib/newops/merkle.js +133 -0
  59. package/lib/newops/merkle.js.map +1 -0
  60. package/lib/newops/merkleMap.d.ts +15 -0
  61. package/lib/newops/merkleMap.d.ts.map +1 -0
  62. package/lib/newops/merkleMap.js +37 -0
  63. package/lib/newops/merkleMap.js.map +1 -0
  64. package/lib/newops/policy.d.ts +14 -0
  65. package/lib/newops/policy.d.ts.map +1 -0
  66. package/lib/newops/policy.js +40 -0
  67. package/lib/newops/policy.js.map +1 -0
  68. package/lib/newops/psbtExtractor.d.ts +4 -0
  69. package/lib/newops/psbtExtractor.d.ts.map +1 -0
  70. package/lib/newops/psbtExtractor.js +36 -0
  71. package/lib/newops/psbtExtractor.js.map +1 -0
  72. package/lib/newops/psbtFinalizer.d.ts +7 -0
  73. package/lib/newops/psbtFinalizer.d.ts.map +1 -0
  74. package/lib/newops/psbtFinalizer.js +111 -0
  75. package/lib/newops/psbtFinalizer.js.map +1 -0
  76. package/lib/newops/psbtv2.d.ts +129 -0
  77. package/lib/newops/psbtv2.d.ts.map +1 -0
  78. package/lib/newops/psbtv2.js +478 -0
  79. package/lib/newops/psbtv2.js.map +1 -0
  80. package/lib/serializeTransaction.js +4 -4
  81. package/lib/serializeTransaction.js.map +1 -1
  82. package/lib/signP2SHTransaction.js +5 -5
  83. package/lib/signP2SHTransaction.js.map +1 -1
  84. package/lib/signTransaction.js +1 -1
  85. package/lib/signTransaction.js.map +1 -1
  86. package/lib/splitTransaction.js +7 -7
  87. package/lib/splitTransaction.js.map +1 -1
  88. package/lib/startUntrustedHashTransactionInput.js +2 -2
  89. package/lib/startUntrustedHashTransactionInput.js.map +1 -1
  90. package/lib/varint.d.ts.map +1 -1
  91. package/lib/varint.js +1 -0
  92. package/lib/varint.js.map +1 -1
  93. package/lib-es/Btc.d.ts +7 -3
  94. package/lib-es/Btc.d.ts.map +1 -1
  95. package/lib-es/Btc.js +92 -26
  96. package/lib-es/Btc.js.map +1 -1
  97. package/lib-es/BtcNew.d.ts +70 -0
  98. package/lib-es/BtcNew.d.ts.map +1 -0
  99. package/lib-es/BtcNew.js +370 -0
  100. package/lib-es/BtcNew.js.map +1 -0
  101. package/lib-es/BtcOld.d.ts +114 -0
  102. package/lib-es/BtcOld.d.ts.map +1 -0
  103. package/lib-es/BtcOld.js +136 -0
  104. package/lib-es/BtcOld.js.map +1 -0
  105. package/lib-es/bip32.d.ts +8 -0
  106. package/lib-es/bip32.d.ts.map +1 -1
  107. package/lib-es/bip32.js +26 -2
  108. package/lib-es/bip32.js.map +1 -1
  109. package/lib-es/buffertools.d.ts +28 -0
  110. package/lib-es/buffertools.d.ts.map +1 -0
  111. package/lib-es/buffertools.js +94 -0
  112. package/lib-es/buffertools.js.map +1 -0
  113. package/lib-es/createTransaction.d.ts.map +1 -1
  114. package/lib-es/getWalletPublicKey.d.ts +1 -1
  115. package/lib-es/getWalletPublicKey.d.ts.map +1 -1
  116. package/lib-es/getWalletPublicKey.js.map +1 -1
  117. package/lib-es/hashPublicKey.d.ts +1 -1
  118. package/lib-es/hashPublicKey.d.ts.map +1 -1
  119. package/lib-es/index.d.ts +3 -0
  120. package/lib-es/index.d.ts.map +1 -0
  121. package/lib-es/index.js +3 -0
  122. package/lib-es/index.js.map +1 -0
  123. package/lib-es/newops/appClient.d.ts +14 -0
  124. package/lib-es/newops/appClient.d.ts.map +1 -0
  125. package/lib-es/newops/appClient.js +239 -0
  126. package/lib-es/newops/appClient.js.map +1 -0
  127. package/lib-es/newops/clientCommands.d.ts +61 -0
  128. package/lib-es/newops/clientCommands.d.ts.map +1 -0
  129. package/lib-es/newops/clientCommands.js +328 -0
  130. package/lib-es/newops/clientCommands.js.map +1 -0
  131. package/lib-es/newops/merkelizedPsbt.d.ts +15 -0
  132. package/lib-es/newops/merkelizedPsbt.d.ts.map +1 -0
  133. package/lib-es/newops/merkelizedPsbt.js +88 -0
  134. package/lib-es/newops/merkelizedPsbt.js.map +1 -0
  135. package/lib-es/newops/merkle.d.ts +29 -0
  136. package/lib-es/newops/merkle.d.ts.map +1 -0
  137. package/lib-es/newops/merkle.js +129 -0
  138. package/lib-es/newops/merkle.js.map +1 -0
  139. package/lib-es/newops/merkleMap.d.ts +15 -0
  140. package/lib-es/newops/merkleMap.d.ts.map +1 -0
  141. package/lib-es/newops/merkleMap.js +34 -0
  142. package/lib-es/newops/merkleMap.js.map +1 -0
  143. package/lib-es/newops/policy.d.ts +14 -0
  144. package/lib-es/newops/policy.d.ts.map +1 -0
  145. package/lib-es/newops/policy.js +36 -0
  146. package/lib-es/newops/policy.js.map +1 -0
  147. package/lib-es/newops/psbtExtractor.d.ts +4 -0
  148. package/lib-es/newops/psbtExtractor.d.ts.map +1 -0
  149. package/lib-es/newops/psbtExtractor.js +32 -0
  150. package/lib-es/newops/psbtExtractor.js.map +1 -0
  151. package/lib-es/newops/psbtFinalizer.d.ts +7 -0
  152. package/lib-es/newops/psbtFinalizer.d.ts.map +1 -0
  153. package/lib-es/newops/psbtFinalizer.js +107 -0
  154. package/lib-es/newops/psbtFinalizer.js.map +1 -0
  155. package/lib-es/newops/psbtv2.d.ts +129 -0
  156. package/lib-es/newops/psbtv2.d.ts.map +1 -0
  157. package/lib-es/newops/psbtv2.js +475 -0
  158. package/lib-es/newops/psbtv2.js.map +1 -0
  159. package/lib-es/varint.d.ts.map +1 -1
  160. package/lib-es/varint.js +1 -0
  161. package/lib-es/varint.js.map +1 -1
  162. package/package.json +7 -4
  163. package/src/Btc.ts +42 -25
  164. package/src/BtcNew.ts +326 -0
  165. package/src/BtcOld.ts +156 -0
  166. package/src/bip32.ts +34 -2
  167. package/src/buffertools.ts +102 -0
  168. package/src/createTransaction.ts +2 -2
  169. package/src/getWalletPublicKey.ts +6 -1
  170. package/src/hashPublicKey.ts +1 -1
  171. package/src/index.ts +2 -0
  172. package/src/newops/appClient.ts +178 -0
  173. package/src/newops/clientCommands.ts +312 -0
  174. package/src/newops/merkelizedPsbt.ts +55 -0
  175. package/src/newops/merkle.ts +123 -0
  176. package/src/newops/merkleMap.ts +39 -0
  177. package/src/newops/policy.ts +52 -0
  178. package/src/newops/psbtExtractor.ts +33 -0
  179. package/src/newops/psbtFinalizer.ts +110 -0
  180. package/src/newops/psbtv2.ts +548 -0
  181. package/src/varint.ts +2 -0
  182. package/tests/Btc.integration.test.ts +89 -0
  183. package/tests/Btc.test.ts +6 -0
  184. package/tests/newops/BtcNew.test.ts +646 -0
  185. package/tests/newops/common.ts +25 -0
  186. package/tests/newops/merkle.test.ts +97 -0
  187. package/tests/trustedInputs.test.ts +4 -0
@@ -0,0 +1,646 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+ /* eslint-disable prettier/prettier */
3
+ import {
4
+ openTransportReplayer,
5
+ RecordStore
6
+ } from "@ledgerhq/hw-transport-mocker";
7
+ import { TransportReplayer } from "@ledgerhq/hw-transport-mocker/lib/openTransportReplayer";
8
+ import bs58check from "bs58check";
9
+ import ecc from "tiny-secp256k1";
10
+ import { getXpubComponents, pathArrayToString } from "../../src/bip32";
11
+ import Btc from "../../src/Btc";
12
+ import BtcNew from "../../src/BtcNew";
13
+ import { BufferWriter } from "../../src/buffertools";
14
+ import { CreateTransactionArg } from "../../src/createTransaction";
15
+ import { AppClient } from "../../src/newops/appClient";
16
+ import { AddressFormat } from "../../src/getWalletPublicKey";
17
+ import {
18
+ DefaultDescriptorTemplate,
19
+ WalletPolicy
20
+ } from "../../src/newops/policy";
21
+ import { PsbtV2 } from "../../src/newops/psbtv2";
22
+ import { Transaction } from "../../src/types";
23
+
24
+ test("getWalletPublicKey p2pkh", async () => {
25
+ await testGetWalletPublicKey("m/44'/1'/0'", "pkh(@0)");
26
+ await testGetWalletPublicKey("m/44'/0'/17'", "pkh(@0)");
27
+ await testGetWalletPublicKey("m/46'/0'/17'", "pkh(@0)");
28
+ await testGetWalletPublicKey("m/109'/0'/17'", "pkh(@0)");
29
+ });
30
+ test("getWalletPublicKey p2wpkh", async () => {
31
+ await testGetWalletPublicKey("m/84'/1'/0'", "wpkh(@0)");
32
+ await testGetWalletPublicKey("m/84'/0'/17'", "wpkh(@0)");
33
+ await testGetWalletPublicKey("m/2'/0'/17'", "wpkh(@0)");
34
+ });
35
+ test("getWalletPublicKey wrapped p2wpkh", async () => {
36
+ await testGetWalletPublicKey("m/49'/1'/0'", "sh(wpkh(@0))");
37
+ await testGetWalletPublicKey("m/49'/0'/17'", "sh(wpkh(@0))");
38
+ await testGetWalletPublicKey("m/9'/0'/17'", "sh(wpkh(@0))");
39
+ });
40
+ test("getWalletPublicKey p2tr", async () => {
41
+ await testGetWalletPublicKey("m/86'/1'/0'", "tr(@0)");
42
+ await testGetWalletPublicKey("m/86'/0'/17'", "tr(@0)");
43
+ await testGetWalletPublicKey("m/17'", "tr(@0)");
44
+ });
45
+
46
+ test("Sign p2pkh", async () => {
47
+ await runSignTransactionTest(p2pkh);
48
+ });
49
+ test("Sign p2wpkh wrapped", async () => {
50
+ await runSignTransactionTest(wrappedP2wpkh);
51
+ // await runSignTransactionTest(wrappedP2wpkhTwoInputs);
52
+ });
53
+ test("Sign p2wpkh", async () => {
54
+ await runSignTransactionTest(p2wpkh);
55
+ // await runSignTransactionTest(p2wpkhTwoInputs);
56
+ });
57
+ test("Sign p2tr", async () => {
58
+ await runSignTransactionTest(p2tr);
59
+ });
60
+
61
+ async function runSignTransactionTest(testTx: CoreTx) {
62
+ const [client, transport] = await createClient();
63
+ const btcNew = new BtcNew(client);
64
+ // btc is needed to perform some functions like splitTransaction.
65
+ const btc = new Btc(transport);
66
+ const accountType = getAccountType(testTx.vin[0], btc);
67
+ const additionals: string[] = [];
68
+ if (accountType == AccountType.p2wpkh) {
69
+ additionals.push("bech32");
70
+ }
71
+ if (accountType == AccountType.p2tr) {
72
+ additionals.push("bech32m");
73
+ }
74
+ const associatedKeysets: string[] = [];
75
+ const accountXpub = "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
76
+ client.mockGetPubkeyResponse(`m/${accountType}/1'/0'`, accountXpub);
77
+ const yieldSigs = new Map<number, Buffer>();
78
+ const inputs = testTx.vin.map((input, index) => {
79
+ const path = `m/${accountType}/1'/0'/${index % 2}/${index}`;
80
+ associatedKeysets.push(path);
81
+ const inputData = createInput(input, btc);
82
+ const pubkey = getPubkey(index, accountType, testTx, inputData[0], inputData[1]);
83
+ const mockXpub = creatDummyXpub(pubkey);
84
+ client.mockGetPubkeyResponse(path, mockXpub);
85
+ yieldSigs.set(index, getSignature(input, accountType));
86
+ return inputData;
87
+ });
88
+ client.mockSignPsbt(yieldSigs);
89
+ const outputWriter = new BufferWriter();
90
+ outputWriter.writeVarInt(testTx.vout.length);
91
+ testTx.vout.forEach((output) => {
92
+ outputWriter.writeUInt64(BigInt(output.value*100000000));
93
+ outputWriter.writeVarSlice(Buffer.from(output.scriptPubKey.hex, "hex"));
94
+ });
95
+ const outputScriptHex = outputWriter.buffer().toString("hex");
96
+
97
+ const arg: CreateTransactionArg = {
98
+ inputs,
99
+ additionals,
100
+ associatedKeysets,
101
+ changePath: `m/${accountType}/1'/0'/1/100`,
102
+ outputScriptHex,
103
+ lockTime: testTx.locktime,
104
+ segwit: accountType != AccountType.p2pkh,
105
+ };
106
+ client.mockGetPubkeyResponse(arg.changePath!, creatDummyXpub(Buffer.alloc(32, 0)));
107
+ const tx = await btcNew.createPaymentTransactionNew(arg);
108
+ expect(tx).toEqual(testTx.hex);
109
+ };
110
+
111
+ function addressFormatFromDescriptorTemplate(descTemp: DefaultDescriptorTemplate): AddressFormat {
112
+ if (descTemp == "tr(@0)") return "bech32m";
113
+ if (descTemp == "pkh(@0)") return "legacy";
114
+ if (descTemp == "wpkh(@0)") return "bech32";
115
+ if (descTemp == "sh(wpkh(@0))") return "p2sh";
116
+ throw new Error();
117
+ }
118
+
119
+ enum AccountType {
120
+ p2tr = "86'",
121
+ p2wpkh = "84'",
122
+ p2wpkhInP2sh = "49'",
123
+ p2pkh = "44'"
124
+ }
125
+
126
+ function getPubkey(inputIndex: number, accountType: AccountType, testTx: CoreTx, spentTx: Transaction, spentOutputIndex: number): Buffer {
127
+ const scriptSig = Buffer.from(testTx.vin[inputIndex].scriptSig.hex, "hex");
128
+ if (accountType == AccountType.p2pkh) {
129
+ return scriptSig.slice(scriptSig.length-33);
130
+ }
131
+ if (accountType == AccountType.p2tr) {
132
+ return spentTx.outputs![spentOutputIndex].script.slice(2, 34); // 32 bytes x-only pubkey
133
+ }
134
+ if (accountType == AccountType.p2wpkh || accountType == AccountType.p2wpkhInP2sh) {
135
+ return Buffer.from(testTx.vin[inputIndex].txinwitness![1], "hex");
136
+ }
137
+ throw new Error();
138
+ }
139
+
140
+ function getSignature(testTxInput: CoreInput, accountType: AccountType): Buffer {
141
+ const scriptSig = Buffer.from(testTxInput.scriptSig.hex, "hex");
142
+ if (accountType == AccountType.p2pkh) {
143
+ return scriptSig.slice(1, scriptSig.length-34);
144
+ }
145
+ if (accountType == AccountType.p2tr) {
146
+ return Buffer.from(testTxInput.txinwitness![0], "hex");
147
+ }
148
+ if (accountType == AccountType.p2wpkh || accountType == AccountType.p2wpkhInP2sh) {
149
+ return Buffer.from(testTxInput.txinwitness![0], "hex");
150
+ }
151
+ throw new Error();
152
+ }
153
+
154
+ function getAccountType(coreInput: CoreInput, btc: Btc): AccountType {
155
+ const spentTx = spentTxs[coreInput.txid];
156
+ if (!spentTx) {
157
+ throw new Error("Spent tx " + coreInput.txid + " unavailable.");
158
+ }
159
+ const splitSpentTx = btc.splitTransaction(spentTx, !!coreInput.txinwitness);
160
+ const spentOutput = splitSpentTx.outputs![coreInput.vout];
161
+ const script = spentOutput.script;
162
+ if (script.length == 34 && script[0] == 0x51) {
163
+ return AccountType.p2tr;
164
+ }
165
+ if (script.length == 22 && script[0] == 0x00) {
166
+ return AccountType.p2wpkh;
167
+ }
168
+ if (script.length == 23) {
169
+ return AccountType.p2wpkhInP2sh;
170
+ }
171
+ return AccountType.p2pkh;
172
+ }
173
+
174
+ function creatDummyXpub(pubkey: Buffer): string {
175
+ const xpubDecoded = bs58check.decode("tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd");
176
+ const pubkey33 = pubkey.length == 33 ? pubkey : Buffer.concat([Buffer.of(2), pubkey]);
177
+ xpubDecoded.fill(pubkey33, xpubDecoded.length-33);
178
+ return bs58check.encode(xpubDecoded);
179
+ }
180
+
181
+ function createInput(coreInput: CoreInput, btc: Btc): [Transaction, number, string, number] {
182
+ const spentTx = spentTxs[coreInput.txid];
183
+ const splitSpentTx = btc.splitTransaction(spentTx, !!coreInput.txinwitness);
184
+ const scriptSig = coreInput.scriptSig;
185
+ let redeemScript;
186
+ if (scriptSig?.hex && scriptSig.hex.startsWith("160014")) {
187
+ redeemScript = scriptSig.hex.substring(2);
188
+ }
189
+ return [splitSpentTx, coreInput.vout, redeemScript, coreInput.sequence];
190
+ }
191
+
192
+ async function createClient(): Promise<[MockClient, TransportReplayer]> {
193
+ const transport = await openTransportReplayer(RecordStore.fromString(""));
194
+ return [new MockClient(transport), transport];
195
+ }
196
+ async function testGetWalletPublicKey(
197
+ accountPath: string,
198
+ expectedDescriptorTemplate: DefaultDescriptorTemplate
199
+ ) {
200
+ const [client] = await createClient();
201
+ const path = accountPath + "/0/0";
202
+ const accountXpub =
203
+ "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
204
+ const keyXpub =
205
+ "tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd";
206
+ client.mockGetPubkeyResponse(accountPath, accountXpub);
207
+ client.mockGetPubkeyResponse(path, keyXpub);
208
+ const key = `[${masterFingerprint.toString("hex")}${accountPath.substring(
209
+ 1
210
+ )}]${accountXpub}/**`;
211
+ client.mockGetWalletAddressResponse(
212
+ new WalletPolicy(expectedDescriptorTemplate, key),
213
+ 0,
214
+ 0,
215
+ "testaddress"
216
+ );
217
+
218
+ const btcNew = new BtcNew(client);
219
+ const addressFormat = addressFormatFromDescriptorTemplate(expectedDescriptorTemplate);
220
+ const result = await btcNew.getWalletPublicKey(path, {format: addressFormat});
221
+ verifyGetWalletPublicKeyResult(result, keyXpub, "testaddress");
222
+
223
+ const resultAccount = await btcNew.getWalletPublicKey(accountPath);
224
+ verifyGetWalletPublicKeyResult(resultAccount, accountXpub);
225
+ }
226
+
227
+ function verifyGetWalletPublicKeyResult(
228
+ result: { publicKey: string; bitcoinAddress: string; chainCode: string },
229
+ expectedXpub: string,
230
+ expectedAddress?: string
231
+ ) {
232
+ expect(result.bitcoinAddress).toEqual(expectedAddress ?? "");
233
+ const expectedComponents = getXpubComponents(expectedXpub);
234
+ const expectedPubKey = Buffer.from(
235
+ ecc.pointCompress(expectedComponents.pubkey, false)
236
+ );
237
+ expect(expectedPubKey.length).toEqual(65);
238
+ expect(result.chainCode).toEqual(
239
+ expectedComponents.chaincode.toString("hex")
240
+ );
241
+ expect(result.publicKey).toEqual(expectedPubKey.toString("hex"));
242
+ }
243
+
244
+ const masterFingerprint = Buffer.of(1, 2, 3, 4);
245
+ class MockClient extends AppClient {
246
+ getPubkeyResponses = new Map();
247
+ getWalletAddressResponses = new Map();
248
+ yieldSigs: Map<number, Buffer>[] = [];
249
+ mockGetPubkeyResponse(pathElements: string, response: string) {
250
+ this.getPubkeyResponses.set(pathElements, response);
251
+ }
252
+ mockGetWalletAddressResponse(
253
+ walletPolicy: WalletPolicy,
254
+ change: number,
255
+ addressIndex: number,
256
+ response: string
257
+ ) {
258
+ const key = this.getWalletAddressKey(walletPolicy, change, addressIndex);
259
+ this.getWalletAddressResponses.set(key, response);
260
+ }
261
+ mockSignPsbt(yieldSigs: Map<number, Buffer>) {
262
+ this.yieldSigs.push(yieldSigs);
263
+ }
264
+ async getPubkey(display: boolean, pathElements: number[]): Promise<string> {
265
+ const path = pathArrayToString(pathElements);
266
+ const response = this.getPubkeyResponses.get(path);
267
+ if (!response) {
268
+ throw new Error("No getPubkey response prepared for " + path);
269
+ }
270
+ return response;
271
+ }
272
+
273
+ async getWalletAddress(
274
+ walletPolicy: WalletPolicy,
275
+ walletHMAC: Buffer | null,
276
+ change: number,
277
+ addressIndex: number,
278
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
279
+ display: boolean
280
+ ): Promise<string> {
281
+ const key = this.getWalletAddressKey(walletPolicy, change, addressIndex);
282
+ const response = this.getWalletAddressResponses.get(key);
283
+ if (!response) {
284
+ throw new Error("No getWalletAddress response prepared for " + key);
285
+ }
286
+ return response;
287
+ }
288
+ async getMasterFingerprint(): Promise<Buffer> {
289
+ return masterFingerprint;
290
+ }
291
+ async signPsbt(
292
+ _psbt: PsbtV2,
293
+ _walletPolicy: WalletPolicy,
294
+ _walletHMAC: Buffer | null
295
+ ): Promise<Map<number, Buffer>> {
296
+ return this.yieldSigs.splice(0, 1)[0];
297
+ }
298
+ private getWalletAddressKey(
299
+ walletPolicy: WalletPolicy,
300
+ change: number,
301
+ addressIndex: number
302
+ ): string {
303
+ return walletPolicy.serialize().toString("hex") + change + addressIndex;
304
+ }
305
+ }
306
+
307
+ type CoreInput = {txid: string, vout: number, scriptSig: {hex: string, [x: string]: unknown}, txinwitness?: string[], sequence: number}
308
+ type CoreOutput = {value: number, scriptPubKey: {hex: string, [x: string]: unknown}, [x: string]: unknown}
309
+ type CoreTx = {txid: string, vin: CoreInput[], vout: CoreOutput[], hex: string, locktime: number, [x: string]: unknown}
310
+ const spentTxs = {
311
+ "5c02391a5b8f55ebb0db0e4e75900ace70f7e8e992115b3931379ab32b69da40": "020000000001016dac615a27b99c5e82af284cc01b410e789047709de08026c861bb6675fbf81800000000171600140fc5a02184f752c41e7f5da947f48646a213e32dfeffffff02ab5b990000000000160014080b627107f555d511730262f3c7167168e0db46a086010000000000220020de4cbf3bfa733a93fc7db03ef7aef2d3aae4e6c04c0ed3a9ebfe6aae259bb7e8024730440220740e00a9cde06677429018b6cadadbdbe7edd2bcd20f8255be2d83560de1490b02206be17eb882b02b25db2367d3afe8b67e6fb62fee2cd8244285403f16efc1886c012103ad62cd5bce8dab660f74c6bdcd4fc2695acdaa3687d8d6901c1cfb35b1211f3b87032000",
312
+ "80453b180c6616431d28d395a6a89cb331d7ecb21bf3ac1cbb68c90dba6e95ff": "02000000015e50f6bfe2d91dc2927ba425fd1617cc2b68d2d7d2b70a3c795c15a9c86f43f1010000006a47304402203c9bf4759c850c43d7c25936c4163a3e6b869cc8a4cce107475fb0447442814c02203630d862ad274ba227ddd8d7ca85580139398b53101d4c4eec9d54712bc4b0420121037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cfffffffff020000000000000000366a34696f6e3a322e516d66316f75486a46474b48674652716262794a4463454c617369414c595a344d5769797542715877674376695494eded07000000001976a9147628046f6ec479c031d03a47b6a003c4dedb1cad88ac00000000",
313
+ "0d41be343ced2023ff112b123a7bb5c8f345becddb8f1cc7070e1273a21d3710": "0200000000010112fad068799db7637882b643557fb48fd5a7d733276a0e8e96cb44c28e3633230100000000fdffffff01b23f010000000000225120aaeed4185487b0fa6939914cf851cfbe84f5ef098bdc79408e8201b98339a0d80400473044022037ac3cbec286964f3fda9fdd4a73e510d76e829b267aafab392ee23b72d888f602200cc2f93f9251efd6ff1d511384fd0f7d0eb62924444f3806c5ac5e82977e546f0147304402203d5f1ef5cf53bce95e10731375b625dbaf4f6a344cb858d203b422aa421e59e902206fab1e6ee80420a46b5bafbf5ceecd06fd0971080b4c3d0c69d24f953f30ce160169522102bec882e74ae50d719b95087050feb223d9af025d381700c02eb27e8efc5aa50d21038be5e2af3e885abb51d4bd2dbe7bde16d24e1bc3fbe74781ff09645786c7cc262103b135afbeb5dd40aab1fd5e0b19aa537713af8507f01cbfc123a21a750e0efd8753aeb1f61f00",
314
+ "5742c24f1485958d0e36d0ae758b1e33c01ba99107eb54baa539cc7db233a330": "02000000000101b7ff921fcf988d2f394b23f7a9e4648a11e64040d9cbe140d68e9f0fa63b52bd00000000171600142d62a39a40a30228c77de441c1f0993fe1707ddaffffffff02c38f934c0200000017a9145a102ac5376429003168cad88c80331daa3a747187102700000000000017a914c18c7cc194e62a004de3427199417f42d32cd81b870247304402205b615920b281070e99804ef9c5fe57e0595cb0c7968dd5d803cc505f7d28413102202b51ebf4ba70d7f987a98d101e1d60a6b40fba5bcb6ba9261eca9ed3777761cd012103efc6b990c1626d08bd176aab0e545a4f55c627c7ddee878d12bbbc46a126177a00000000",
315
+ };
316
+
317
+ // Taken from bitcoin-core testnet
318
+ const p2tr: CoreTx = {
319
+ "txid": "c77a7c5338ed59b934193209f16ea74ec6d846ef61e9fb9705d99e9896d79e25",
320
+ "hash": "d5b0513aeb462fb52cf977a8d367021fa3e66002194a8b8dd2fe97e6e52b81e4",
321
+ "version": 2,
322
+ "size": 150,
323
+ "vsize": 99,
324
+ "weight": 396,
325
+ "locktime": 2097065,
326
+ "vin": [
327
+ {
328
+ "txid": "0d41be343ced2023ff112b123a7bb5c8f345becddb8f1cc7070e1273a21d3710",
329
+ "vout": 0,
330
+ "scriptSig": {
331
+ "asm": "",
332
+ "hex": ""
333
+ },
334
+ "txinwitness": [
335
+ "8d370b53421e0ae033f736a73af72b35562b584143adca592fd918a0bb252ca904b379393446c8dddba08974a2122802844afcc03ef24bcb2312b81a5c5d65ac"
336
+ ],
337
+ "sequence": 4294967293
338
+ }
339
+ ],
340
+ "vout": [
341
+ {
342
+ "value": 0.00081742,
343
+ "n": 0,
344
+ "scriptPubKey": {
345
+ "asm": "0 f5d7911e8d7c560dfc3cf6e3079a4c7c0dce70e9",
346
+ "hex": "0014f5d7911e8d7c560dfc3cf6e3079a4c7c0dce70e9",
347
+ "reqSigs": 1,
348
+ "type": "witness_v0_keyhash",
349
+ "addresses": [
350
+ "tb1q7htez85d03tqmlpu7m3s0xjv0sxuuu8fg40ght"
351
+ ]
352
+ }
353
+ }
354
+ ],
355
+ "hex": "0200000000010110371da273120e07c71c8fdbcdbe45f3c8b57b3a122b11ff2320ed3c34be410d0000000000fdffffff014e3f010000000000160014f5d7911e8d7c560dfc3cf6e3079a4c7c0dce70e901408d370b53421e0ae033f736a73af72b35562b584143adca592fd918a0bb252ca904b379393446c8dddba08974a2122802844afcc03ef24bcb2312b81a5c5d65aca9ff1f00",
356
+ "blockhash": "0000000000000024a3605855f3b669e9e165ab242e53761ecbaae4b6167829d3",
357
+ "confirmations": 1017,
358
+ "time": 1633037023,
359
+ "blocktime": 1633037023
360
+ };
361
+
362
+ const p2wpkh = {
363
+ "txid": "062c623b6a9486aaa11b60e5c37bddcd6214aa642172d81f485faf3b2fc2996e",
364
+ "hash": "6fabbc622e0d8c9b099fce3a2ac92334a1902302f9f572525b563e3ad97aeab0",
365
+ "version": 2,
366
+ "size": 226,
367
+ "vsize": 145,
368
+ "weight": 577,
369
+ "locktime": 2098057,
370
+ "vin": [
371
+ {
372
+ "txid": "5c02391a5b8f55ebb0db0e4e75900ace70f7e8e992115b3931379ab32b69da40",
373
+ "vout": 0,
374
+ "scriptSig": {
375
+ "asm": "",
376
+ "hex": ""
377
+ },
378
+ "txinwitness": [
379
+ "30440220667c54bc57770a563ef74e68331ee6a27d3a1b073d22e867fda346273d768da50220506609d58f78ab6dfe78d1635cf1974a234347f080da86ed1ee9b0ec345b7c1901",
380
+ "02a236cce923cfb073fd4bfdaf0a8c5ae2f2144052a98549810cd3fe39dcf1e1d7"
381
+ ],
382
+ "sequence": 4294967294
383
+ }
384
+ ],
385
+ "vout": [
386
+ {
387
+ "value": 0.09950330,
388
+ "n": 0,
389
+ "scriptPubKey": {
390
+ "asm": "OP_HASH160 afe05670e110d5203e0544137d2ede18338ced8b OP_EQUAL",
391
+ "hex": "a914afe05670e110d5203e0544137d2ede18338ced8b87",
392
+ "reqSigs": 1,
393
+ "type": "scripthash",
394
+ "addresses": [
395
+ "2N9HAz7E4itqt78dDkN2ZNkAYaKp1pmvnxH"
396
+ ]
397
+ }
398
+ },
399
+ {
400
+ "value": 0.00100000,
401
+ "n": 1,
402
+ "scriptPubKey": {
403
+ "asm": "OP_DUP OP_HASH160 c025f47a88d88b09aa9b4cb7f92010b1d513e300 OP_EQUALVERIFY OP_CHECKSIG",
404
+ "hex": "76a914c025f47a88d88b09aa9b4cb7f92010b1d513e30088ac",
405
+ "reqSigs": 1,
406
+ "type": "pubkeyhash",
407
+ "addresses": [
408
+ "my2wW3Yic3huFYiHWSXy1sMX9DgeQRHmg9"
409
+ ]
410
+ }
411
+ }
412
+ ],
413
+ "hex": "0200000000010140da692bb39a3731395b1192e9e8f770ce0a90754e0edbb0eb558f5b1a39025c0000000000feffffff027ad497000000000017a914afe05670e110d5203e0544137d2ede18338ced8b87a0860100000000001976a914c025f47a88d88b09aa9b4cb7f92010b1d513e30088ac024730440220667c54bc57770a563ef74e68331ee6a27d3a1b073d22e867fda346273d768da50220506609d58f78ab6dfe78d1635cf1974a234347f080da86ed1ee9b0ec345b7c19012102a236cce923cfb073fd4bfdaf0a8c5ae2f2144052a98549810cd3fe39dcf1e1d789032000",
414
+ "blockhash": "0000000000000012201f4dd0b06cdbc3b8a037a5c2c0486c4523688555613a53",
415
+ "confirmations": 16,
416
+ "time": 1633594907,
417
+ "blocktime": 1633594907
418
+ };
419
+
420
+ const wrappedP2wpkh: CoreTx = {
421
+ "txid": "3f3b8e65eb666dc9950ddf1b4b9a7438e9baae710a6a7c06d2582bd2d750ed54",
422
+ "hash": "a3035b0af8eb2176e4e4f459233c7e669e4a8becbf32cee7d1639ba52b671c5b",
423
+ "version": 2,
424
+ "size": 248,
425
+ "vsize": 166,
426
+ "weight": 662,
427
+ "locktime": 0,
428
+ "vin": [
429
+ {
430
+ "txid": "5742c24f1485958d0e36d0ae758b1e33c01ba99107eb54baa539cc7db233a330",
431
+ "vout": 0,
432
+ "scriptSig": {
433
+ "asm": "00142d62a39a40a30228c77de441c1f0993fe1707dda",
434
+ "hex": "1600142d62a39a40a30228c77de441c1f0993fe1707dda"
435
+ },
436
+ "txinwitness": [
437
+ "3045022100d4a981592a3e314ee20c662b7a34339d26855c0ecff1588154f0f41856a17a990220444364570c93d5a7a82de8d863dc51868e69ff357901926eedd43c305e51818701",
438
+ "03efc6b990c1626d08bd176aab0e545a4f55c627c7ddee878d12bbbc46a126177a"
439
+ ],
440
+ "sequence": 4294967295
441
+ }
442
+ ],
443
+ "vout": [
444
+ {
445
+ "value": 98.74662473,
446
+ "n": 0,
447
+ "scriptPubKey": {
448
+ "asm": "OP_HASH160 5a102ac5376429003168cad88c80331daa3a7471 OP_EQUAL",
449
+ "hex": "a9145a102ac5376429003168cad88c80331daa3a747187",
450
+ "reqSigs": 1,
451
+ "type": "scripthash",
452
+ "addresses": [
453
+ "2N1TSArdd2pt9RoqE3LXY55ixpRE9e5aot8"
454
+ ]
455
+ }
456
+ },
457
+ {
458
+ "value": 0.00010000,
459
+ "n": 1,
460
+ "scriptPubKey": {
461
+ "asm": "OP_HASH160 e5776c571979173607c28d5c1882465014b777dc OP_EQUAL",
462
+ "hex": "a914e5776c571979173607c28d5c1882465014b777dc87",
463
+ "reqSigs": 1,
464
+ "type": "scripthash",
465
+ "addresses": [
466
+ "2NEAXntA12Zoa7NdsNyC9ncw7HLKH66jKNH"
467
+ ]
468
+ }
469
+ }
470
+ ],
471
+ "hex": "0200000000010130a333b27dcc39a5ba54eb0791a91bc0331e8b75aed0360e8d9585144fc2425700000000171600142d62a39a40a30228c77de441c1f0993fe1707ddaffffffff024964934c0200000017a9145a102ac5376429003168cad88c80331daa3a747187102700000000000017a914e5776c571979173607c28d5c1882465014b777dc8702483045022100d4a981592a3e314ee20c662b7a34339d26855c0ecff1588154f0f41856a17a990220444364570c93d5a7a82de8d863dc51868e69ff357901926eedd43c305e518187012103efc6b990c1626d08bd176aab0e545a4f55c627c7ddee878d12bbbc46a126177a00000000",
472
+ "blockhash": "00000000c117e8cb6cb65ef6afc22dda3ab906dc6a42669a154fea124ecec3ca",
473
+ "confirmations": 3,
474
+ "time": 1633609698,
475
+ "blocktime": 1633609698
476
+ };
477
+
478
+ const p2pkh: CoreTx = {
479
+ "txid": "03717ce615625148a3a3aad38a68fa2aa68e54633259cb98a7a16c16c33a71c3",
480
+ "hash": "03717ce615625148a3a3aad38a68fa2aa68e54633259cb98a7a16c16c33a71c3",
481
+ "version": 2,
482
+ "size": 254,
483
+ "vsize": 254,
484
+ "weight": 1016,
485
+ "locktime": 0,
486
+ "vin": [
487
+ {
488
+ "txid": "80453b180c6616431d28d395a6a89cb331d7ecb21bf3ac1cbb68c90dba6e95ff",
489
+ "vout": 1,
490
+ "scriptSig": {
491
+ "asm": "304402205c809d58dadb3dbe1b9cf129549036b00f7dfa876f7f6c1686d8df77b69cef2c02206512480ee394c3298c8b66340c0ccddddc3c245b4e870a31bf52c9eec9ad69b6[ALL] 037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cf",
492
+ "hex": "47304402205c809d58dadb3dbe1b9cf129549036b00f7dfa876f7f6c1686d8df77b69cef2c02206512480ee394c3298c8b66340c0ccddddc3c245b4e870a31bf52c9eec9ad69b60121037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cf"
493
+ },
494
+ "sequence": 4294967295
495
+ }
496
+ ],
497
+ "vout": [
498
+ {
499
+ "value": 0.00000000,
500
+ "n": 0,
501
+ "scriptPubKey": {
502
+ "asm": "OP_RETURN 696f6e3a322e516d59386b56553674567364344a65764d64656d5a744143635152647675776b546158344d455a4e336778677072",
503
+ "hex": "6a34696f6e3a322e516d59386b56553674567364344a65764d64656d5a744143635152647675776b546158344d455a4e336778677072",
504
+ "type": "nulldata"
505
+ }
506
+ },
507
+ {
508
+ "value": 1.33032112,
509
+ "n": 1,
510
+ "scriptPubKey": {
511
+ "asm": "OP_DUP OP_HASH160 7628046f6ec479c031d03a47b6a003c4dedb1cad OP_EQUALVERIFY OP_CHECKSIG",
512
+ "hex": "76a9147628046f6ec479c031d03a47b6a003c4dedb1cad88ac",
513
+ "reqSigs": 1,
514
+ "type": "pubkeyhash",
515
+ "addresses": [
516
+ "mrHhy9DgpBbDLoJsACv4QXXY7f2B5Fq5o1"
517
+ ]
518
+ }
519
+ }
520
+ ],
521
+ "hex": "0200000001ff956eba0dc968bb1cacf31bb2ecd731b39ca8a695d3281d4316660c183b4580010000006a47304402205c809d58dadb3dbe1b9cf129549036b00f7dfa876f7f6c1686d8df77b69cef2c02206512480ee394c3298c8b66340c0ccddddc3c245b4e870a31bf52c9eec9ad69b60121037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cfffffffff020000000000000000366a34696f6e3a322e516d59386b56553674567364344a65764d64656d5a744143635152647675776b546158344d455a4e336778677072b0e8ed07000000001976a9147628046f6ec479c031d03a47b6a003c4dedb1cad88ac00000000",
522
+ "blockhash": "0000000000000040f9117341ca31f40e4f440fc6f6552a3b3f15e96ed9edeb3e",
523
+ "confirmations": 1,
524
+ "time": 1633611385,
525
+ "blocktime": 1633611385
526
+ };
527
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
528
+ const p2wpkhTwoInputs = {
529
+ "txid": "1913b7b5ffdcb5f32b9aca1f5eec2a189e7c66650f82b560eae211265fc995b7",
530
+ "hash": "c3439dcd3489373c586c7aed48c32f2b5d9c71aad24acd765a61684d98690a3f",
531
+ "version": 2,
532
+ "size": 388,
533
+ "vsize": 226,
534
+ "weight": 904,
535
+ "locktime": 0,
536
+ "vin": [
537
+ {
538
+ "txid": "5512d5788d4c26117f093de91223ef384c3fb22799810a92e3304bb6f0819224",
539
+ "vout": 1,
540
+ "scriptSig": {
541
+ "asm": "0014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3",
542
+ "hex": "160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3"
543
+ },
544
+ "txinwitness": [
545
+ "30440220543617c5f4504dc29d34d2d06d0d7733dac4ec418b77c67feefb29f3f82ba3d80220690b784c52c3375f4ba9e64cc5c0aeb6a1b9fc6aadda0062905c06ce3bbba57501",
546
+ "02fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e441"
547
+ ],
548
+ "sequence": 4294967295
549
+ },
550
+ {
551
+ "txid": "28ad5054e029252d72da37f13fce66212d7f7763845b4a8c4aaf78e897b2bf9f",
552
+ "vout": 1,
553
+ "scriptSig": {
554
+ "asm": "0014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3",
555
+ "hex": "160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3"
556
+ },
557
+ "txinwitness": [
558
+ "3044022049e7f3015a33ccdb015fe3891667564fd37111272df57e58447645c7bad8fed0022074d1e93ba946453896d0f0bc500df3a1e0d5bb5ad10cd9906736d5fbaebadd5801",
559
+ "02fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e441"
560
+ ],
561
+ "sequence": 4294967295
562
+ }
563
+ ],
564
+ "vout": [
565
+ {
566
+ "value": 0.01800000,
567
+ "n": 0,
568
+ "scriptPubKey": {
569
+ "asm": "OP_DUP OP_HASH160 f73384bcc3951ab6a75541ff79a9a51f82056ed8 OP_EQUALVERIFY OP_CHECKSIG",
570
+ "hex": "76a914f73384bcc3951ab6a75541ff79a9a51f82056ed888ac",
571
+ "address": "n442v1DrXQNim9gjjctKjyGVoe717hNdtG",
572
+ "type": "pubkeyhash"
573
+ }
574
+ }
575
+ ],
576
+ "hex": "02000000000102249281f0b64b30e3920a819927b23f4c38ef2312e93d097f11264c8d78d512550100000017160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3ffffffff9fbfb297e878af4a8c4a5b8463777f2d2166ce3ff137da722d2529e05450ad280100000017160014c1ac0d63d0258ea1b6fe90ef72d0c35d8d773dd3ffffffff0140771b00000000001976a914f73384bcc3951ab6a75541ff79a9a51f82056ed888ac024730440220543617c5f4504dc29d34d2d06d0d7733dac4ec418b77c67feefb29f3f82ba3d80220690b784c52c3375f4ba9e64cc5c0aeb6a1b9fc6aadda0062905c06ce3bbba575012102fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e44102473044022049e7f3015a33ccdb015fe3891667564fd37111272df57e58447645c7bad8fed0022074d1e93ba946453896d0f0bc500df3a1e0d5bb5ad10cd9906736d5fbaebadd58012102fb255ed920db5c2f507289202eb60a160e5a067ee7e30199a4ed81b74c22e44100000000",
577
+ "blockhash": "00000000025a711e6cd4bce9138dc852232a4494afbf36d8bb80499a786da2a4",
578
+ "confirmations": 1,
579
+ "time": 1633944124,
580
+ "blocktime": 1633944124
581
+ };
582
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
583
+ const wrappedP2wpkhTwoInputs = {
584
+ "txid": "c03119b538c78f56c8ce2e6cc5fc6998d447eeef42e34c12692764a3f1a3da7c",
585
+ "hash": "6b3812304554a6964e43a6971ac533046f4be101e39609f72179856916e20268",
586
+ "version": 2,
587
+ "size": 420,
588
+ "vsize": 257,
589
+ "weight": 1026,
590
+ "locktime": 0,
591
+ "vin": [
592
+ {
593
+ "txid": "9075ef8fd97f92ff0db344322873f12c42b29661c3960801e05114ba8adcabd6",
594
+ "vout": 0,
595
+ "scriptSig": {
596
+ "asm": "0014e4a7ff7c7e16cb6f15914938e2b92e2801220250",
597
+ "hex": "160014e4a7ff7c7e16cb6f15914938e2b92e2801220250"
598
+ },
599
+ "txinwitness": [
600
+ "30450221008a777087167aaeda51cf3532da368a7541630cd7274068ae4353aa1e9e32d7850220628ad0f414ae4cfb7a6dcd590b0e21e003b2ff638c5fc9aaad9b411783b03e3301",
601
+ "02de057221383ed65635568e38d4305d9120a4e68e205734a5f95a8feea3dd5f53"
602
+ ],
603
+ "sequence": 4294967293
604
+ },
605
+ {
606
+ "txid": "d36d3ba59981dab0dad0e02dafa9fa97ad51f4e5a47ffad3ad8544bdb251b70f",
607
+ "vout": 0,
608
+ "scriptSig": {
609
+ "asm": "001442721355859d8f2a461a5badfb19e59a61935692",
610
+ "hex": "16001442721355859d8f2a461a5badfb19e59a61935692"
611
+ },
612
+ "txinwitness": [
613
+ "3045022100e49eac220605239d702261c5929e4544e2d3ea70f3372527cee7f6cb31dabd24022015b67591a07e15a7a35ac5cc775e2abbc7fdf41983ad14438961e76029aee52c01",
614
+ "02783edf31f3a8845c6350d17a254a73561c02f1d00c69a8972fd91472c1920105"
615
+ ],
616
+ "sequence": 4294967293
617
+ }
618
+ ],
619
+ "vout": [
620
+ {
621
+ "value": 0.03532507,
622
+ "n": 0,
623
+ "scriptPubKey": {
624
+ "asm": "OP_HASH160 deb26fa74cb3bb95cd00213172397ec91c5fc9ba OP_EQUAL",
625
+ "hex": "a914deb26fa74cb3bb95cd00213172397ec91c5fc9ba87",
626
+ "address": "2NDYjkqA8jUpMAqU2rBaSumb5bqa41Ri5BM",
627
+ "type": "scripthash"
628
+ }
629
+ },
630
+ {
631
+ "value": 0.00069944,
632
+ "n": 1,
633
+ "scriptPubKey": {
634
+ "asm": "OP_HASH160 c0a4669d0b6fd3ce7b22e158ac160f2e656f2592 OP_EQUAL",
635
+ "hex": "a914c0a4669d0b6fd3ce7b22e158ac160f2e656f259287",
636
+ "address": "2NAopftKM5sNgM7AueL7Cin9NsFv8ykBkUA",
637
+ "type": "scripthash"
638
+ }
639
+ }
640
+ ],
641
+ "hex": "02000000000102d6abdc8aba1451e0010896c36196b2422cf173283244b30dff927fd98fef75900000000017160014e4a7ff7c7e16cb6f15914938e2b92e2801220250fdffffff0fb751b2bd4485add3fa7fa4e5f451ad97faa9af2de0d0dab0da8199a53b6dd3000000001716001442721355859d8f2a461a5badfb19e59a61935692fdffffff02dbe635000000000017a914deb26fa74cb3bb95cd00213172397ec91c5fc9ba87381101000000000017a914c0a4669d0b6fd3ce7b22e158ac160f2e656f259287024830450221008a777087167aaeda51cf3532da368a7541630cd7274068ae4353aa1e9e32d7850220628ad0f414ae4cfb7a6dcd590b0e21e003b2ff638c5fc9aaad9b411783b03e33012102de057221383ed65635568e38d4305d9120a4e68e205734a5f95a8feea3dd5f5302483045022100e49eac220605239d702261c5929e4544e2d3ea70f3372527cee7f6cb31dabd24022015b67591a07e15a7a35ac5cc775e2abbc7fdf41983ad14438961e76029aee52c012102783edf31f3a8845c6350d17a254a73561c02f1d00c69a8972fd91472c192010500000000",
642
+ "blockhash": "00000000025a711e6cd4bce9138dc852232a4494afbf36d8bb80499a786da2a4",
643
+ "confirmations": 1,
644
+ "time": 1633944124,
645
+ "blocktime": 1633944124
646
+ };
@@ -0,0 +1,25 @@
1
+ export const cla = "e1";
2
+ export const p1p2 = "0000";
3
+ export const ok = "9000";
4
+ export const resp = "<= ";
5
+ export const comm = "=> ";
6
+
7
+ export function h(n: number, padding: number = 1): string {
8
+ const base = n.toString(16);
9
+ if (padding > 0) {
10
+ return base.padStart(padding * 2, "0");
11
+ }
12
+ return base;
13
+ }
14
+
15
+ export function ascii(s: string): string {
16
+ return Buffer.from(s, "ascii").toString("hex");
17
+ }
18
+
19
+ export function statusResponse(code: number): string {
20
+ return resp + h(code, 2);
21
+ }
22
+
23
+ export function asciiResponse(data: string): string {
24
+ return resp + ascii(data) + ok;
25
+ }