@ledgerhq/hw-app-btc 10.2.4 → 10.3.0-nightly.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/lib/Btc.js.map +1 -1
- package/lib/BtcNew.js +10 -10
- package/lib/BtcNew.js.map +1 -1
- package/lib/BtcOld.js +4 -4
- package/lib/BtcOld.js.map +1 -1
- package/lib/bip32.js.map +1 -1
- package/lib/buffertools.js.map +1 -1
- package/lib/createTransaction.js +2 -2
- package/lib/createTransaction.js.map +1 -1
- package/lib/debug.js.map +1 -1
- package/lib/finalizeInput.js +2 -2
- package/lib/finalizeInput.js.map +1 -1
- package/lib/getAppAndVersion.js.map +1 -1
- package/lib/getTrustedInput.js +3 -3
- package/lib/getTrustedInput.js.map +1 -1
- package/lib/getTrustedInputBIP143.js.map +1 -1
- package/lib/getWalletPublicKey.js.map +1 -1
- package/lib/newops/accounttype.js.map +1 -1
- package/lib/newops/appClient.js.map +1 -1
- package/lib/newops/clientCommands.js.map +1 -1
- package/lib/newops/merkelizedPsbt.js.map +1 -1
- package/lib/newops/merkle.js.map +1 -1
- package/lib/newops/merkleMap.js.map +1 -1
- package/lib/newops/psbtExtractor.js.map +1 -1
- package/lib/newops/psbtFinalizer.js.map +1 -1
- package/lib/newops/psbtv2.js.map +1 -1
- package/lib/serializeTransaction.js +2 -2
- package/lib/serializeTransaction.js.map +1 -1
- package/lib/signMessage.js +2 -2
- package/lib/signMessage.js.map +1 -1
- package/lib/signP2SHTransaction.js.map +1 -1
- package/lib/signTransaction.js.map +1 -1
- package/lib/splitTransaction.js.map +1 -1
- package/lib/startUntrustedHashTransactionInput.js +2 -2
- package/lib/startUntrustedHashTransactionInput.js.map +1 -1
- package/lib/varint.js.map +1 -1
- package/lib-es/Btc.js.map +1 -1
- package/lib-es/BtcNew.js +10 -10
- package/lib-es/BtcNew.js.map +1 -1
- package/lib-es/BtcOld.js +4 -4
- package/lib-es/BtcOld.js.map +1 -1
- package/lib-es/bip32.js.map +1 -1
- package/lib-es/buffertools.js.map +1 -1
- package/lib-es/createTransaction.js +2 -2
- package/lib-es/createTransaction.js.map +1 -1
- package/lib-es/debug.js.map +1 -1
- package/lib-es/finalizeInput.js +2 -2
- package/lib-es/finalizeInput.js.map +1 -1
- package/lib-es/getAppAndVersion.js.map +1 -1
- package/lib-es/getTrustedInput.js +3 -3
- package/lib-es/getTrustedInput.js.map +1 -1
- package/lib-es/getTrustedInputBIP143.js.map +1 -1
- package/lib-es/getWalletPublicKey.js.map +1 -1
- package/lib-es/newops/accounttype.js.map +1 -1
- package/lib-es/newops/appClient.js.map +1 -1
- package/lib-es/newops/clientCommands.js.map +1 -1
- package/lib-es/newops/merkelizedPsbt.js.map +1 -1
- package/lib-es/newops/merkle.js.map +1 -1
- package/lib-es/newops/merkleMap.js.map +1 -1
- package/lib-es/newops/psbtExtractor.js.map +1 -1
- package/lib-es/newops/psbtFinalizer.js.map +1 -1
- package/lib-es/newops/psbtv2.js.map +1 -1
- package/lib-es/serializeTransaction.js +2 -2
- package/lib-es/serializeTransaction.js.map +1 -1
- package/lib-es/signMessage.js +2 -2
- package/lib-es/signMessage.js.map +1 -1
- package/lib-es/signP2SHTransaction.js.map +1 -1
- package/lib-es/signTransaction.js.map +1 -1
- package/lib-es/splitTransaction.js.map +1 -1
- package/lib-es/startUntrustedHashTransactionInput.js +2 -2
- package/lib-es/startUntrustedHashTransactionInput.js.map +1 -1
- package/lib-es/varint.js.map +1 -1
- package/package.json +4 -4
- package/src/createTransaction.ts +10 -10
- package/src/getTrustedInput.ts +2 -2
- package/src/startUntrustedHashTransactionInput.ts +6 -6
- package/tests/buffertools.test.ts +7 -7
- package/tests/newops/BtcNew.test.ts +52 -37
- package/tests/newops/common.ts +1 -1
- package/tests/newops/integrationtools.ts +17 -41
- package/tests/newops/merkle.test.ts +10 -38
- package/tests/newops/psbtv2.test.ts +1 -1
- package/tests/parseTx.test.ts +3 -6
- package/tests/speculosclient.ts +43 -32
package/src/createTransaction.ts
CHANGED
|
@@ -129,8 +129,8 @@ export async function createTransaction(
|
|
|
129
129
|
!!expiryHeight && !isDecred
|
|
130
130
|
? defaultVersion.writeUInt32LE(isZcash ? 0x80000005 : sapling ? 0x80000004 : 0x80000003, 0) // v5 format for zcash refer to https://zips.z.cash/zip-0225
|
|
131
131
|
: isXST
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
? defaultVersion.writeUInt32LE(2, 0)
|
|
133
|
+
: defaultVersion.writeUInt32LE(1, 0);
|
|
134
134
|
// Default version to 2 for XST not to have timestamp
|
|
135
135
|
const trustedInputs: Array<any> = [];
|
|
136
136
|
const regularOutputs: Array<TransactionOutput> = [];
|
|
@@ -178,8 +178,8 @@ export async function createTransaction(
|
|
|
178
178
|
isZcash
|
|
179
179
|
? [0x0a, 0x27, 0xa7, 0x26]
|
|
180
180
|
: sapling
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
? [0x85, 0x20, 0x2f, 0x89]
|
|
182
|
+
: [0x70, 0x82, 0xc4, 0x03],
|
|
183
183
|
);
|
|
184
184
|
targetTransaction.nExpiryHeight = expiryHeight;
|
|
185
185
|
// For sapling : valueBalance (8), nShieldedSpend (1), nShieldedOutput (1), nJoinSplit (1)
|
|
@@ -267,12 +267,12 @@ export async function createTransaction(
|
|
|
267
267
|
inputs[i].length >= 3 && typeof input[2] === "string"
|
|
268
268
|
? Buffer.from(input[2], "hex")
|
|
269
269
|
: !segwit
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
? regularOutputs[i].script
|
|
271
|
+
: Buffer.concat([
|
|
272
|
+
Buffer.from([OP_DUP, OP_HASH160, HASH_SIZE]),
|
|
273
|
+
hashPublicKey(publicKeys[i]),
|
|
274
|
+
Buffer.from([OP_EQUALVERIFY, OP_CHECKSIG]),
|
|
275
|
+
]);
|
|
276
276
|
const pseudoTX = Object.assign({}, targetTransaction);
|
|
277
277
|
const pseudoTrustedInputs = useBip143 ? [trustedInputs[i]] : trustedInputs;
|
|
278
278
|
|
package/src/getTrustedInput.ts
CHANGED
|
@@ -101,8 +101,8 @@ export async function getTrustedInput(
|
|
|
101
101
|
await (isDecred
|
|
102
102
|
? processWholeScriptBlock(Buffer.concat([input.script, input.sequence]))
|
|
103
103
|
: isXSTV2
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
? processWholeScriptBlock(input.sequence)
|
|
105
|
+
: processScriptBlocks(input.script, input.sequence));
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
await getTrustedInputRaw(transport, createVarint(outputs.length));
|
|
@@ -14,12 +14,12 @@ export function startUntrustedHashTransactionInputRaw(
|
|
|
14
14
|
const p2 = additionals.includes("cashaddr")
|
|
15
15
|
? 0x03
|
|
16
16
|
: bip143
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
? additionals.includes("sapling")
|
|
18
|
+
? 0x05
|
|
19
|
+
: overwinter
|
|
20
|
+
? 0x04
|
|
21
|
+
: 0x02
|
|
22
|
+
: 0x00;
|
|
23
23
|
return transport.send(
|
|
24
24
|
0xe0,
|
|
25
25
|
0x44,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { BufferReader, BufferWriter } from "../src/buffertools"
|
|
1
|
+
import { BufferReader, BufferWriter } from "../src/buffertools";
|
|
2
2
|
|
|
3
3
|
function run(n: number, expectedHex: string) {
|
|
4
4
|
const w = new BufferWriter();
|
|
5
|
-
w.writeUInt64(n)
|
|
5
|
+
w.writeUInt64(n);
|
|
6
6
|
expect(w.buffer()).toEqual(Buffer.from(expectedHex, "hex"));
|
|
7
7
|
const r = new BufferReader(w.buffer());
|
|
8
8
|
expect(r.readUInt64()).toEqual(n);
|
|
@@ -11,15 +11,15 @@ function run(n: number, expectedHex: string) {
|
|
|
11
11
|
test("Test 64 bit numbers", () => {
|
|
12
12
|
run(0, "0000000000000000");
|
|
13
13
|
run(1, "0100000000000000");
|
|
14
|
-
run(0xffffffff,
|
|
14
|
+
run(0xffffffff, "ffffffff00000000");
|
|
15
15
|
run(0x0100000000, "0000000001000000");
|
|
16
16
|
run(0x010203040506, "0605040302010000");
|
|
17
17
|
run(Number.MAX_SAFE_INTEGER, "FFFFFFFFFFFF1F00");
|
|
18
|
-
})
|
|
18
|
+
});
|
|
19
19
|
|
|
20
20
|
test("Too big 64 bit number", () => {
|
|
21
21
|
const w = new BufferWriter();
|
|
22
|
-
expect(() => w.writeUInt64(Number.MAX_SAFE_INTEGER+1)).toThrow();
|
|
23
|
-
const r = new BufferReader(Buffer.from("FFFFFFFFFFFF2000", "hex"))
|
|
22
|
+
expect(() => w.writeUInt64(Number.MAX_SAFE_INTEGER + 1)).toThrow();
|
|
23
|
+
const r = new BufferReader(Buffer.from("FFFFFFFFFFFF2000", "hex"));
|
|
24
24
|
expect(() => r.readUInt64()).toThrow();
|
|
25
|
-
})
|
|
25
|
+
});
|
|
@@ -4,14 +4,26 @@ import { TransportReplayer } from "@ledgerhq/hw-transport-mocker/lib/openTranspo
|
|
|
4
4
|
import ecc from "tiny-secp256k1";
|
|
5
5
|
import { getXpubComponents, pathArrayToString } from "../../src/bip32";
|
|
6
6
|
import BtcNew from "../../src/BtcNew";
|
|
7
|
-
import {
|
|
8
|
-
DefaultDescriptorTemplate,
|
|
9
|
-
WalletPolicy
|
|
10
|
-
} from "../../src/newops/policy";
|
|
7
|
+
import { DefaultDescriptorTemplate, WalletPolicy } from "../../src/newops/policy";
|
|
11
8
|
import { PsbtV2 } from "../../src/newops/psbtv2";
|
|
12
9
|
import { splitTransaction } from "../../src/splitTransaction";
|
|
13
|
-
import {
|
|
14
|
-
|
|
10
|
+
import {
|
|
11
|
+
StandardPurpose,
|
|
12
|
+
addressFormatFromDescriptorTemplate,
|
|
13
|
+
creatDummyXpub,
|
|
14
|
+
masterFingerprint,
|
|
15
|
+
runSignTransaction,
|
|
16
|
+
TestingClient,
|
|
17
|
+
} from "./integrationtools";
|
|
18
|
+
import {
|
|
19
|
+
CoreInput,
|
|
20
|
+
CoreTx,
|
|
21
|
+
p2pkh,
|
|
22
|
+
p2tr,
|
|
23
|
+
p2wpkh,
|
|
24
|
+
wrappedP2wpkh,
|
|
25
|
+
wrappedP2wpkhTwoInputs,
|
|
26
|
+
} from "./testtx";
|
|
15
27
|
|
|
16
28
|
test("getWalletPublicKey p2pkh", async () => {
|
|
17
29
|
await testGetWalletPublicKey("m/44'/1'/0'", "pkh(@0)");
|
|
@@ -36,7 +48,7 @@ test("getWalletXpub normal path", async () => {
|
|
|
36
48
|
await testGetWalletXpub("m/44'/0'/0'");
|
|
37
49
|
});
|
|
38
50
|
|
|
39
|
-
function testPaths(type: StandardPurpose): { ins: string[]
|
|
51
|
+
function testPaths(type: StandardPurpose): { ins: string[]; out?: string } {
|
|
40
52
|
const basePath = `m/${type}/1'/0'/`;
|
|
41
53
|
const ins = [
|
|
42
54
|
basePath + "0/0",
|
|
@@ -70,35 +82,44 @@ test("Sign p2tr", async () => {
|
|
|
70
82
|
|
|
71
83
|
test("Sign p2tr with sigHashType", async () => {
|
|
72
84
|
const testTx = JSON.parse(JSON.stringify(p2tr));
|
|
73
|
-
testTx.vin.forEach((input: CoreInput
|
|
85
|
+
testTx.vin.forEach((input: CoreInput) => {
|
|
74
86
|
// Test SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, 0x83
|
|
75
87
|
const sig = input.txinwitness![0] + "83";
|
|
76
88
|
input.txinwitness = [sig];
|
|
77
|
-
})
|
|
78
|
-
|
|
89
|
+
});
|
|
90
|
+
await runSignTransactionNoVerification(testTx, StandardPurpose.p2tr);
|
|
79
91
|
// The verification of the sighashtype is done in MockClient.signPsbt
|
|
80
|
-
})
|
|
92
|
+
});
|
|
81
93
|
|
|
82
|
-
test("Sign p2tr sequence 0", async() => {
|
|
94
|
+
test("Sign p2tr sequence 0", async () => {
|
|
83
95
|
const testTx = JSON.parse(JSON.stringify(p2tr));
|
|
84
|
-
testTx.vin.forEach((input: CoreInput
|
|
96
|
+
testTx.vin.forEach((input: CoreInput) => {
|
|
85
97
|
input.sequence = 0;
|
|
86
|
-
})
|
|
98
|
+
});
|
|
87
99
|
const tx = await runSignTransactionNoVerification(testTx, StandardPurpose.p2tr);
|
|
88
100
|
const txObj = splitTransaction(tx, true);
|
|
89
|
-
txObj.inputs.forEach(
|
|
101
|
+
txObj.inputs.forEach(input => {
|
|
90
102
|
expect(input.sequence.toString("hex")).toEqual("00000000");
|
|
91
|
-
})
|
|
92
|
-
})
|
|
103
|
+
});
|
|
104
|
+
});
|
|
93
105
|
|
|
94
|
-
async function runSignTransactionTest(
|
|
106
|
+
async function runSignTransactionTest(
|
|
107
|
+
testTx: CoreTx,
|
|
108
|
+
accountType: StandardPurpose,
|
|
109
|
+
changePubkey?: string,
|
|
110
|
+
) {
|
|
95
111
|
const tx = await runSignTransactionNoVerification(testTx, accountType, changePubkey);
|
|
96
112
|
expect(tx).toEqual(testTx.hex);
|
|
97
113
|
}
|
|
98
114
|
|
|
99
|
-
async function runSignTransactionNoVerification(
|
|
115
|
+
async function runSignTransactionNoVerification(
|
|
116
|
+
testTx: CoreTx,
|
|
117
|
+
accountType: StandardPurpose,
|
|
118
|
+
changePubkey?: string,
|
|
119
|
+
): Promise<string> {
|
|
100
120
|
const [client, transport] = await createClient();
|
|
101
|
-
const accountXpub =
|
|
121
|
+
const accountXpub =
|
|
122
|
+
"tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
|
|
102
123
|
client.mockGetPubkeyResponse(`m/${accountType}/1'/0'`, accountXpub);
|
|
103
124
|
const paths = testPaths(accountType);
|
|
104
125
|
if (changePubkey) {
|
|
@@ -112,7 +133,8 @@ async function runSignTransactionNoVerification(testTx: CoreTx, accountType: Sta
|
|
|
112
133
|
|
|
113
134
|
async function testGetWalletXpub(path: string, version = 0x043587cf) {
|
|
114
135
|
const [client] = await createClient();
|
|
115
|
-
const expectedXpub =
|
|
136
|
+
const expectedXpub =
|
|
137
|
+
"tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
|
|
116
138
|
client.mockGetPubkeyResponse(path, expectedXpub);
|
|
117
139
|
const btc = new BtcNew(client);
|
|
118
140
|
const result = await btc.getWalletXpub({ path: path, xpubVersion: version });
|
|
@@ -120,7 +142,7 @@ async function testGetWalletXpub(path: string, version = 0x043587cf) {
|
|
|
120
142
|
}
|
|
121
143
|
async function testGetWalletPublicKey(
|
|
122
144
|
accountPath: string,
|
|
123
|
-
expectedDescriptorTemplate: DefaultDescriptorTemplate
|
|
145
|
+
expectedDescriptorTemplate: DefaultDescriptorTemplate,
|
|
124
146
|
) {
|
|
125
147
|
const [client] = await createClient();
|
|
126
148
|
const path = accountPath + "/0/0";
|
|
@@ -130,14 +152,12 @@ async function testGetWalletPublicKey(
|
|
|
130
152
|
"tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd";
|
|
131
153
|
client.mockGetPubkeyResponse(accountPath, accountXpub);
|
|
132
154
|
client.mockGetPubkeyResponse(path, keyXpub);
|
|
133
|
-
const key = `[${masterFingerprint.toString("hex")}${accountPath.substring(
|
|
134
|
-
1
|
|
135
|
-
)}]${accountXpub}/**`;
|
|
155
|
+
const key = `[${masterFingerprint.toString("hex")}${accountPath.substring(1)}]${accountXpub}/**`;
|
|
136
156
|
client.mockGetWalletAddressResponse(
|
|
137
157
|
new WalletPolicy(expectedDescriptorTemplate, key),
|
|
138
158
|
0,
|
|
139
159
|
0,
|
|
140
|
-
"testaddress"
|
|
160
|
+
"testaddress",
|
|
141
161
|
);
|
|
142
162
|
|
|
143
163
|
const btcNew = new BtcNew(client);
|
|
@@ -152,17 +172,13 @@ async function testGetWalletPublicKey(
|
|
|
152
172
|
function verifyGetWalletPublicKeyResult(
|
|
153
173
|
result: { publicKey: string; bitcoinAddress: string; chainCode: string },
|
|
154
174
|
expectedXpub: string,
|
|
155
|
-
expectedAddress?: string
|
|
175
|
+
expectedAddress?: string,
|
|
156
176
|
) {
|
|
157
177
|
expect(result.bitcoinAddress).toEqual(expectedAddress ?? "");
|
|
158
178
|
const expectedComponents = getXpubComponents(expectedXpub);
|
|
159
|
-
const expectedPubKey = Buffer.from(
|
|
160
|
-
ecc.pointCompress(expectedComponents.pubkey, false)
|
|
161
|
-
);
|
|
179
|
+
const expectedPubKey = Buffer.from(ecc.pointCompress(expectedComponents.pubkey, false));
|
|
162
180
|
expect(expectedPubKey.length).toEqual(65);
|
|
163
|
-
expect(result.chainCode).toEqual(
|
|
164
|
-
expectedComponents.chaincode.toString("hex")
|
|
165
|
-
);
|
|
181
|
+
expect(result.chainCode).toEqual(expectedComponents.chaincode.toString("hex"));
|
|
166
182
|
expect(result.publicKey).toEqual(expectedPubKey.toString("hex"));
|
|
167
183
|
}
|
|
168
184
|
|
|
@@ -182,7 +198,7 @@ class MockClient extends TestingClient {
|
|
|
182
198
|
walletPolicy: WalletPolicy,
|
|
183
199
|
change: number,
|
|
184
200
|
addressIndex: number,
|
|
185
|
-
response: string
|
|
201
|
+
response: string,
|
|
186
202
|
) {
|
|
187
203
|
const key = this.getWalletAddressKey(walletPolicy, change, addressIndex);
|
|
188
204
|
this.getWalletAddressResponses.set(key, response);
|
|
@@ -205,7 +221,7 @@ class MockClient extends TestingClient {
|
|
|
205
221
|
change: number,
|
|
206
222
|
addressIndex: number,
|
|
207
223
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
208
|
-
display: boolean
|
|
224
|
+
display: boolean,
|
|
209
225
|
): Promise<string> {
|
|
210
226
|
const key = this.getWalletAddressKey(walletPolicy, change, addressIndex);
|
|
211
227
|
const response = this.getWalletAddressResponses.get(key);
|
|
@@ -239,9 +255,8 @@ class MockClient extends TestingClient {
|
|
|
239
255
|
private getWalletAddressKey(
|
|
240
256
|
walletPolicy: WalletPolicy,
|
|
241
257
|
change: number,
|
|
242
|
-
addressIndex: number
|
|
258
|
+
addressIndex: number,
|
|
243
259
|
): string {
|
|
244
260
|
return walletPolicy.serialize().toString("hex") + change + addressIndex;
|
|
245
261
|
}
|
|
246
262
|
}
|
|
247
|
-
|
package/tests/newops/common.ts
CHANGED
|
@@ -7,10 +7,7 @@ import { BufferWriter } from "../../src/buffertools";
|
|
|
7
7
|
import { CreateTransactionArg } from "../../src/createTransaction";
|
|
8
8
|
import { AddressFormat } from "../../src/getWalletPublicKey";
|
|
9
9
|
import { AppClient } from "../../src/newops/appClient";
|
|
10
|
-
import {
|
|
11
|
-
DefaultDescriptorTemplate,
|
|
12
|
-
WalletPolicy,
|
|
13
|
-
} from "../../src/newops/policy";
|
|
10
|
+
import { DefaultDescriptorTemplate, WalletPolicy } from "../../src/newops/policy";
|
|
14
11
|
import { Transaction } from "../../src/types";
|
|
15
12
|
import { CoreInput, CoreTx, spentTxs } from "./testtx";
|
|
16
13
|
|
|
@@ -18,7 +15,7 @@ export async function runSignTransaction(
|
|
|
18
15
|
testTx: CoreTx,
|
|
19
16
|
testPaths: { ins: string[]; out?: string },
|
|
20
17
|
client: TestingClient,
|
|
21
|
-
transport: Transport
|
|
18
|
+
transport: Transport,
|
|
22
19
|
): Promise<string> {
|
|
23
20
|
const btcNew = new BtcNew(client);
|
|
24
21
|
// btc is needed to perform some functions like splitTransaction.
|
|
@@ -37,13 +34,7 @@ export async function runSignTransaction(
|
|
|
37
34
|
const path = testPaths.ins[index];
|
|
38
35
|
associatedKeysets.push(path);
|
|
39
36
|
const inputData = createInput(input, btc);
|
|
40
|
-
const pubkey = getPubkey(
|
|
41
|
-
index,
|
|
42
|
-
accountType,
|
|
43
|
-
testTx,
|
|
44
|
-
inputData[0],
|
|
45
|
-
inputData[1]
|
|
46
|
-
);
|
|
37
|
+
const pubkey = getPubkey(index, accountType, testTx, inputData[0], inputData[1]);
|
|
47
38
|
const mockXpub = creatDummyXpub(pubkey);
|
|
48
39
|
client.mockGetPubkeyResponse(path, mockXpub);
|
|
49
40
|
yieldSigs.set(index, getSignature(input, accountType));
|
|
@@ -57,13 +48,12 @@ export async function runSignTransaction(
|
|
|
57
48
|
client.mockSignPsbt(yieldSigs);
|
|
58
49
|
const outputWriter = new BufferWriter();
|
|
59
50
|
outputWriter.writeVarInt(testTx.vout.length);
|
|
60
|
-
testTx.vout.forEach(
|
|
61
|
-
outputWriter.writeUInt64(
|
|
62
|
-
Number.parseFloat((output.value * 100000000).toFixed(8))
|
|
63
|
-
);
|
|
51
|
+
testTx.vout.forEach(output => {
|
|
52
|
+
outputWriter.writeUInt64(Number.parseFloat((output.value * 100000000).toFixed(8)));
|
|
64
53
|
outputWriter.writeVarSlice(Buffer.from(output.scriptPubKey.hex, "hex"));
|
|
65
54
|
});
|
|
66
55
|
const outputScriptHex = outputWriter.buffer().toString("hex");
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
67
57
|
let callbacks = "";
|
|
68
58
|
function logCallback(message: string) {
|
|
69
59
|
callbacks += new Date().toISOString() + " " + message + "\n";
|
|
@@ -78,9 +68,8 @@ export async function runSignTransaction(
|
|
|
78
68
|
sigHashType,
|
|
79
69
|
segwit: accountType != StandardPurpose.p2pkh,
|
|
80
70
|
onDeviceSignatureGranted: () => logCallback("CALLBACK: signature granted"),
|
|
81
|
-
onDeviceSignatureRequested: () =>
|
|
82
|
-
|
|
83
|
-
onDeviceStreaming: (arg) => logCallback("CALLBACK: " + JSON.stringify(arg)),
|
|
71
|
+
onDeviceSignatureRequested: () => logCallback("CALLBACK: signature requested"),
|
|
72
|
+
onDeviceStreaming: arg => logCallback("CALLBACK: " + JSON.stringify(arg)),
|
|
84
73
|
};
|
|
85
74
|
logCallback("Start createPaymentTransaction");
|
|
86
75
|
const tx = await btcNew.createPaymentTransaction(arg);
|
|
@@ -90,7 +79,7 @@ export async function runSignTransaction(
|
|
|
90
79
|
}
|
|
91
80
|
|
|
92
81
|
export function addressFormatFromDescriptorTemplate(
|
|
93
|
-
descTemp: DefaultDescriptorTemplate
|
|
82
|
+
descTemp: DefaultDescriptorTemplate,
|
|
94
83
|
): AddressFormat {
|
|
95
84
|
if (descTemp == "tr(@0)") return "bech32m";
|
|
96
85
|
if (descTemp == "pkh(@0)") return "legacy";
|
|
@@ -111,7 +100,7 @@ function getPubkey(
|
|
|
111
100
|
accountType: StandardPurpose,
|
|
112
101
|
testTx: CoreTx,
|
|
113
102
|
spentTx: Transaction,
|
|
114
|
-
spentOutputIndex: number
|
|
103
|
+
spentOutputIndex: number,
|
|
115
104
|
): Buffer {
|
|
116
105
|
const scriptSig = Buffer.from(testTx.vin[inputIndex].scriptSig.hex, "hex");
|
|
117
106
|
if (accountType == StandardPurpose.p2pkh) {
|
|
@@ -120,19 +109,13 @@ function getPubkey(
|
|
|
120
109
|
if (accountType == StandardPurpose.p2tr) {
|
|
121
110
|
return spentTx.outputs![spentOutputIndex].script.slice(2, 34); // 32 bytes x-only pubkey
|
|
122
111
|
}
|
|
123
|
-
if (
|
|
124
|
-
accountType == StandardPurpose.p2wpkh ||
|
|
125
|
-
accountType == StandardPurpose.p2wpkhInP2sh
|
|
126
|
-
) {
|
|
112
|
+
if (accountType == StandardPurpose.p2wpkh || accountType == StandardPurpose.p2wpkhInP2sh) {
|
|
127
113
|
return Buffer.from(testTx.vin[inputIndex].txinwitness![1], "hex");
|
|
128
114
|
}
|
|
129
115
|
throw new Error();
|
|
130
116
|
}
|
|
131
117
|
|
|
132
|
-
function getSignature(
|
|
133
|
-
testTxInput: CoreInput,
|
|
134
|
-
accountType: StandardPurpose
|
|
135
|
-
): Buffer {
|
|
118
|
+
function getSignature(testTxInput: CoreInput, accountType: StandardPurpose): Buffer {
|
|
136
119
|
const scriptSig = Buffer.from(testTxInput.scriptSig.hex, "hex");
|
|
137
120
|
if (accountType == StandardPurpose.p2pkh) {
|
|
138
121
|
return scriptSig.slice(1, scriptSig.length - 34);
|
|
@@ -140,10 +123,7 @@ function getSignature(
|
|
|
140
123
|
if (accountType == StandardPurpose.p2tr) {
|
|
141
124
|
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
142
125
|
}
|
|
143
|
-
if (
|
|
144
|
-
accountType == StandardPurpose.p2wpkh ||
|
|
145
|
-
accountType == StandardPurpose.p2wpkhInP2sh
|
|
146
|
-
) {
|
|
126
|
+
if (accountType == StandardPurpose.p2wpkh || accountType == StandardPurpose.p2wpkhInP2sh) {
|
|
147
127
|
return Buffer.from(testTxInput.txinwitness![0], "hex");
|
|
148
128
|
}
|
|
149
129
|
throw new Error();
|
|
@@ -171,18 +151,14 @@ function getAccountType(coreInput: CoreInput, btc: Btc): StandardPurpose {
|
|
|
171
151
|
|
|
172
152
|
export function creatDummyXpub(pubkey: Buffer): string {
|
|
173
153
|
const xpubDecoded = bs58check.decode(
|
|
174
|
-
"tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd"
|
|
154
|
+
"tpubDHcN44A4UHqdHJZwBxgTbu8Cy87ZrZkN8tQnmJGhcijHqe4rztuvGcD4wo36XSviLmiqL5fUbDnekYaQ7LzAnaqauBb9RsyahsTTFHdeJGd",
|
|
175
155
|
);
|
|
176
|
-
const pubkey33 =
|
|
177
|
-
pubkey.length == 33 ? pubkey : Buffer.concat([Buffer.from([2]), pubkey]);
|
|
156
|
+
const pubkey33 = pubkey.length == 33 ? pubkey : Buffer.concat([Buffer.from([2]), pubkey]);
|
|
178
157
|
xpubDecoded.fill(pubkey33, xpubDecoded.length - 33);
|
|
179
158
|
return bs58check.encode(xpubDecoded);
|
|
180
159
|
}
|
|
181
160
|
|
|
182
|
-
function createInput(
|
|
183
|
-
coreInput: CoreInput,
|
|
184
|
-
btc: Btc
|
|
185
|
-
): [Transaction, number, string | null, number] {
|
|
161
|
+
function createInput(coreInput: CoreInput, btc: Btc): [Transaction, number, string | null, number] {
|
|
186
162
|
const spentTx = spentTxs[coreInput.txid];
|
|
187
163
|
if (!spentTx) {
|
|
188
164
|
throw new Error("Spent tx " + coreInput.txid + " unavailable.");
|
|
@@ -198,7 +174,7 @@ export class TestingClient extends AppClient {
|
|
|
198
174
|
_walletPolicy: WalletPolicy,
|
|
199
175
|
_change: number,
|
|
200
176
|
_addressIndex: number,
|
|
201
|
-
_response: string
|
|
177
|
+
_response: string,
|
|
202
178
|
): void {}
|
|
203
179
|
mockSignPsbt(_yieldSigs: Map<number, Buffer>): void {}
|
|
204
180
|
}
|
|
@@ -14,8 +14,8 @@ function merkleOf(count: number): Merkle {
|
|
|
14
14
|
}
|
|
15
15
|
function rootOfLeaves(...leaves: number[]): Buffer {
|
|
16
16
|
return new Merkle(
|
|
17
|
-
leaves.map(
|
|
18
|
-
testHasher
|
|
17
|
+
leaves.map(v => leaf(v)),
|
|
18
|
+
testHasher,
|
|
19
19
|
).getRoot();
|
|
20
20
|
}
|
|
21
21
|
function rootOf(count: number): Buffer {
|
|
@@ -55,43 +55,15 @@ test("Merkle proof of three", () => {
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
test("Merkle proof of four", () => {
|
|
58
|
-
expect(merkleOf(4).getProof(0)).toEqual([
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
]);
|
|
62
|
-
expect(merkleOf(4).getProof(1)).toEqual([
|
|
63
|
-
rootOfLeaves(0),
|
|
64
|
-
rootOfLeaves(2, 3),
|
|
65
|
-
]);
|
|
66
|
-
expect(merkleOf(4).getProof(2)).toEqual([
|
|
67
|
-
rootOfLeaves(3),
|
|
68
|
-
rootOfLeaves(0, 1),
|
|
69
|
-
]);
|
|
70
|
-
expect(merkleOf(4).getProof(3)).toEqual([
|
|
71
|
-
rootOfLeaves(2),
|
|
72
|
-
rootOfLeaves(0, 1),
|
|
73
|
-
]);
|
|
58
|
+
expect(merkleOf(4).getProof(0)).toEqual([rootOfLeaves(1), rootOfLeaves(2, 3)]);
|
|
59
|
+
expect(merkleOf(4).getProof(1)).toEqual([rootOfLeaves(0), rootOfLeaves(2, 3)]);
|
|
60
|
+
expect(merkleOf(4).getProof(2)).toEqual([rootOfLeaves(3), rootOfLeaves(0, 1)]);
|
|
61
|
+
expect(merkleOf(4).getProof(3)).toEqual([rootOfLeaves(2), rootOfLeaves(0, 1)]);
|
|
74
62
|
});
|
|
75
63
|
test("Merkle proof of five", () => {
|
|
76
|
-
expect(merkleOf(5).getProof(0)).toEqual([
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]);
|
|
81
|
-
expect(merkleOf(5).getProof(1)).toEqual([
|
|
82
|
-
rootOfLeaves(0),
|
|
83
|
-
rootOfLeaves(2, 3),
|
|
84
|
-
rootOfLeaves(4),
|
|
85
|
-
]);
|
|
86
|
-
expect(merkleOf(5).getProof(2)).toEqual([
|
|
87
|
-
rootOfLeaves(3),
|
|
88
|
-
rootOfLeaves(0, 1),
|
|
89
|
-
rootOfLeaves(4),
|
|
90
|
-
]);
|
|
91
|
-
expect(merkleOf(5).getProof(3)).toEqual([
|
|
92
|
-
rootOfLeaves(2),
|
|
93
|
-
rootOfLeaves(0, 1),
|
|
94
|
-
rootOfLeaves(4),
|
|
95
|
-
]);
|
|
64
|
+
expect(merkleOf(5).getProof(0)).toEqual([rootOfLeaves(1), rootOfLeaves(2, 3), rootOfLeaves(4)]);
|
|
65
|
+
expect(merkleOf(5).getProof(1)).toEqual([rootOfLeaves(0), rootOfLeaves(2, 3), rootOfLeaves(4)]);
|
|
66
|
+
expect(merkleOf(5).getProof(2)).toEqual([rootOfLeaves(3), rootOfLeaves(0, 1), rootOfLeaves(4)]);
|
|
67
|
+
expect(merkleOf(5).getProof(3)).toEqual([rootOfLeaves(2), rootOfLeaves(0, 1), rootOfLeaves(4)]);
|
|
96
68
|
expect(merkleOf(5).getProof(4)).toEqual([rootOfLeaves(0, 1, 2, 3)]);
|
|
97
69
|
});
|
|
@@ -4,7 +4,7 @@ describe("PsbtV2", () => {
|
|
|
4
4
|
it("deserializes a psbt and reserializes it unchanged", async () => {
|
|
5
5
|
const psbtBuf = Buffer.from(
|
|
6
6
|
"cHNidP8BAAoBAAAAAAAAAAAAAQIEAgAAAAEDBAAAAAABBAECAQUBAgH7BAIAAAAAAQBxAgAAAAGTarLgEHL3k8/kyXdU3hth/gPn22U2yLLyHdC1dCxIRQEAAAAA/v///wLe4ccAAAAAABYAFOt418QL8QY7Dj/OKcNWW2ichVmrECcAAAAAAAAWABQjGNZvhP71xIdfkzsDjcY4MfjaE/mXHgABAR8QJwAAAAAAABYAFCMY1m+E/vXEh1+TOwONxjgx+NoTIgYDRV7nztyXsLpDW4AGb8ksljo0xgAxeYHRNTMMTuQ6x6MY9azC/VQAAIABAACAAAAAgAAAAAABAAAAAQ4gniz+J/Cth7eKI31ddAXUowZmyjYdWFpGew3+QiYrTbQBDwQBAAAAARAE/f///wESBAAAAAAAAQBxAQAAAAEORx706Sway1HvyGYPjT9pk26pybK/9y/5vIHFHvz0ZAEAAAAAAAAAAAJgrgoAAAAAABYAFDXG4N1tPISxa6iF3Kc6yGPQtZPsrwYyAAAAAAAWABTcKG4M0ua9N86+nsNJ+18IkFZy/AAAAAABAR9grgoAAAAAABYAFDXG4N1tPISxa6iF3Kc6yGPQtZPsIgYCcbW3ea2HCDhYd5e89vDHrsWr52pwnXJPSNLibPh08KAY9azC/VQAAIABAACAAAAAgAEAAAAAAAAAAQ4gr7+uBlkPdB/xr1m2rEYRJjNqTEqC21U99v76tzesM/MBDwQAAAAAARAE/f///wESBAAAAAAAIgICKexHcnEx7SWIogxG7amrt9qm9J/VC6/nC5xappYcTswY9azC/VQAAIABAACAAAAAgAEAAAAKAAAAAQMIqDoGAAAAAAABBBYAFOs4+puBKPgfJule2wxf+uqDaQ/kAAEDCOCTBAAAAAAAAQQiACA/qWbJ3c3C/ZbkpeG8dlufr2zos+tPEQSq1r33cyTlvgA=",
|
|
7
|
-
"base64"
|
|
7
|
+
"base64",
|
|
8
8
|
);
|
|
9
9
|
|
|
10
10
|
const psbt = new PsbtV2();
|
package/tests/parseTx.test.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
openTransportReplayer,
|
|
3
|
-
RecordStore,
|
|
4
|
-
} from "@ledgerhq/hw-transport-mocker";
|
|
1
|
+
import { openTransportReplayer, RecordStore } from "@ledgerhq/hw-transport-mocker";
|
|
5
2
|
import Btc from "../src/Btc";
|
|
6
3
|
|
|
7
4
|
test("transaction on btc – nano s 1.3.1 – native segwit", async () => {
|
|
@@ -33,7 +30,7 @@ test("transaction on btc – nano s 1.3.1 – native segwit", async () => {
|
|
|
33
30
|
<= 9000
|
|
34
31
|
=> e04800001b05800000548000000080000000000000010000001b000000000001
|
|
35
32
|
<= 3045022100e4acf0eb3803a62399f53825d86aa30743fe999eefb01522d5f7ecd9eeec663d022063b90c512e207c2ac47d8759e1c73c6abeff58daec31c48905193470bc87f2d3019000
|
|
36
|
-
`)
|
|
33
|
+
`),
|
|
37
34
|
);
|
|
38
35
|
const btc = new Btc({ transport, currency: "zcash" });
|
|
39
36
|
const tx1 = btc.splitTransaction(
|
|
@@ -41,7 +38,7 @@ test("transaction on btc – nano s 1.3.1 – native segwit", async () => {
|
|
|
41
38
|
true,
|
|
42
39
|
false,
|
|
43
40
|
false,
|
|
44
|
-
["zencash"]
|
|
41
|
+
["zencash"],
|
|
45
42
|
);
|
|
46
43
|
expect(tx1.outputs?.length).toEqual(40); // 40 outputs in the above transaction. refer to https://explorer.zen-solutions.io/tx/1af7f8e4c77b35f558ee11defe7590c30e85723c0d846787729ecd4fbd45a533
|
|
47
44
|
});
|
package/tests/speculosclient.ts
CHANGED
|
@@ -3,45 +3,56 @@ import axios from "axios";
|
|
|
3
3
|
const SPECULOS_REST_API_ENDPOINT = "http://127.0.0.1:5000";
|
|
4
4
|
|
|
5
5
|
export async function approveTransaction(): Promise<void> {
|
|
6
|
-
await axios.post(
|
|
7
|
-
`${SPECULOS_REST_API_ENDPOINT}/automation`,
|
|
8
|
-
approveTransactionScript
|
|
9
|
-
);
|
|
6
|
+
await axios.post(`${SPECULOS_REST_API_ENDPOINT}/automation`, approveTransactionScript);
|
|
10
7
|
}
|
|
11
8
|
|
|
12
9
|
/* eslint-disable */
|
|
13
10
|
const approveTransactionScript = {
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
version: 1,
|
|
12
|
+
rules: [
|
|
16
13
|
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
["button", 2, true],
|
|
20
|
-
["button", 2,
|
|
21
|
-
["button", 2, true],
|
|
22
|
-
["button", 2,
|
|
23
|
-
["button", 2, true],
|
|
24
|
-
["button", 2,
|
|
25
|
-
["button", 2, true],
|
|
26
|
-
["button",
|
|
27
|
-
["button",
|
|
28
|
-
["button",
|
|
29
|
-
|
|
14
|
+
text: "output #1",
|
|
15
|
+
actions: [
|
|
16
|
+
["button", 2, true],
|
|
17
|
+
["button", 2, false],
|
|
18
|
+
["button", 2, true],
|
|
19
|
+
["button", 2, false],
|
|
20
|
+
["button", 2, true],
|
|
21
|
+
["button", 2, false],
|
|
22
|
+
["button", 2, true],
|
|
23
|
+
["button", 2, false],
|
|
24
|
+
["button", 2, true],
|
|
25
|
+
["button", 2, false],
|
|
26
|
+
["button", 2, true],
|
|
27
|
+
["button", 2, false],
|
|
28
|
+
["button", 2, true],
|
|
29
|
+
["button", 2, false],
|
|
30
|
+
["button", 1, true],
|
|
31
|
+
["button", 1, false],
|
|
32
|
+
["button", 1, true],
|
|
33
|
+
["button", 2, true],
|
|
34
|
+
["button", 1, false],
|
|
35
|
+
["button", 2, false],
|
|
36
|
+
],
|
|
30
37
|
},
|
|
31
38
|
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
["button", 2, true],
|
|
35
|
-
["button", 2,
|
|
36
|
-
|
|
39
|
+
text: "transaction",
|
|
40
|
+
actions: [
|
|
41
|
+
["button", 2, true],
|
|
42
|
+
["button", 2, false],
|
|
43
|
+
["button", 2, true],
|
|
44
|
+
["button", 2, false],
|
|
45
|
+
],
|
|
37
46
|
},
|
|
38
47
|
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
["button", 1, true],
|
|
42
|
-
["button",
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
48
|
+
text: "and send",
|
|
49
|
+
actions: [
|
|
50
|
+
["button", 1, true],
|
|
51
|
+
["button", 2, true],
|
|
52
|
+
["button", 1, false],
|
|
53
|
+
["button", 2, false],
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
47
58
|
/* eslint-enable */
|