@ledgerhq/hw-app-kaspa 1.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/.prettierrc +4 -0
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE.txt +21 -0
- package/README.md +105 -0
- package/jest.config.ts +10 -0
- package/lib/Kaspa.d.ts +59 -0
- package/lib/Kaspa.d.ts.map +1 -0
- package/lib/Kaspa.js +185 -0
- package/lib/Kaspa.js.map +1 -0
- package/lib/base32.d.ts +11 -0
- package/lib/base32.d.ts.map +1 -0
- package/lib/base32.js +36 -0
- package/lib/base32.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -0
- package/lib/kaspa-util.d.ts +3 -0
- package/lib/kaspa-util.d.ts.map +1 -0
- package/lib/kaspa-util.js +102 -0
- package/lib/kaspa-util.js.map +1 -0
- package/lib/kaspaHwTransaction.d.ts +89 -0
- package/lib/kaspaHwTransaction.d.ts.map +1 -0
- package/lib/kaspaHwTransaction.js +157 -0
- package/lib/kaspaHwTransaction.js.map +1 -0
- package/lib-es/Kaspa.d.ts +59 -0
- package/lib-es/Kaspa.d.ts.map +1 -0
- package/lib-es/Kaspa.js +179 -0
- package/lib-es/Kaspa.js.map +1 -0
- package/lib-es/base32.d.ts +11 -0
- package/lib-es/base32.d.ts.map +1 -0
- package/lib-es/base32.js +33 -0
- package/lib-es/base32.js.map +1 -0
- package/lib-es/index.d.ts +4 -0
- package/lib-es/index.d.ts.map +1 -0
- package/lib-es/index.js +4 -0
- package/lib-es/index.js.map +1 -0
- package/lib-es/kaspa-util.d.ts +3 -0
- package/lib-es/kaspa-util.d.ts.map +1 -0
- package/lib-es/kaspa-util.js +95 -0
- package/lib-es/kaspa-util.js.map +1 -0
- package/lib-es/kaspaHwTransaction.d.ts +89 -0
- package/lib-es/kaspaHwTransaction.d.ts.map +1 -0
- package/lib-es/kaspaHwTransaction.js +150 -0
- package/lib-es/kaspaHwTransaction.js.map +1 -0
- package/package.json +43 -0
- package/src/Kaspa.ts +261 -0
- package/src/base32.ts +36 -0
- package/src/index.ts +9 -0
- package/src/kaspa-util.ts +107 -0
- package/src/kaspaHwTransaction.ts +244 -0
- package/tests/kaspa.test.ts +724 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openTransportReplayer,
|
|
3
|
+
RecordStore,
|
|
4
|
+
} from "@ledgerhq/hw-transport-mocker";
|
|
5
|
+
import Kaspa from "../src/Kaspa";
|
|
6
|
+
import {
|
|
7
|
+
KaspaHwTransaction,
|
|
8
|
+
TransactionInput,
|
|
9
|
+
TransactionOutput,
|
|
10
|
+
} from "../lib/kaspaHwTransaction";
|
|
11
|
+
|
|
12
|
+
describe("kaspa", () => {
|
|
13
|
+
it("getVersion", async () => {
|
|
14
|
+
const transport = await openTransportReplayer(
|
|
15
|
+
RecordStore.fromString(`
|
|
16
|
+
=> e004000000
|
|
17
|
+
<= 0105069000
|
|
18
|
+
`),
|
|
19
|
+
);
|
|
20
|
+
const kaspa = new Kaspa(transport);
|
|
21
|
+
const result = await kaspa.getVersion();
|
|
22
|
+
expect(result).toEqual({
|
|
23
|
+
version: "1.5.6",
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("getPublicKey without display (implicit)", async () => {
|
|
28
|
+
const transport = await openTransportReplayer(
|
|
29
|
+
RecordStore.fromString(`
|
|
30
|
+
=> e005000015058000002c8001b207800000000000000000000000
|
|
31
|
+
<= deadbeef9000
|
|
32
|
+
`),
|
|
33
|
+
);
|
|
34
|
+
const kaspa = new Kaspa(transport);
|
|
35
|
+
const response = await kaspa.getAddress("44'/111111'/0'/0/0");
|
|
36
|
+
const publicKey = response.publicKey;
|
|
37
|
+
const address = response.address;
|
|
38
|
+
console.log(address);
|
|
39
|
+
expect(publicKey).toEqual("deadbeef");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("getPublicKey without display", async () => {
|
|
43
|
+
const transport = await openTransportReplayer(
|
|
44
|
+
RecordStore.fromString(`
|
|
45
|
+
=> e005000015058000002c8001b207800000000000000000000000
|
|
46
|
+
<= deadbeef9000
|
|
47
|
+
`),
|
|
48
|
+
);
|
|
49
|
+
const kaspa = new Kaspa(transport);
|
|
50
|
+
const publicKey = (await kaspa.getAddress("44'/111111'/0'/0/0", false))
|
|
51
|
+
.publicKey;
|
|
52
|
+
expect(publicKey).toEqual("deadbeef");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("getPublicKey with display", async () => {
|
|
56
|
+
const transport = await openTransportReplayer(
|
|
57
|
+
RecordStore.fromString(`
|
|
58
|
+
=> e005010015058000002c8001b207800000000000000000000000
|
|
59
|
+
<= deadbeef9000
|
|
60
|
+
`),
|
|
61
|
+
);
|
|
62
|
+
const kaspa = new Kaspa(transport);
|
|
63
|
+
const publicKey = (await kaspa.getAddress("44'/111111'/0'/0/0", true))
|
|
64
|
+
.publicKey;
|
|
65
|
+
expect(publicKey).toEqual("deadbeef");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("getAddress", async () => {
|
|
69
|
+
const transport = await openTransportReplayer(
|
|
70
|
+
RecordStore.fromString(`
|
|
71
|
+
=> e005010015058000002c8001b207800000000000000000000000
|
|
72
|
+
<= 4104600d27e2c82127e38ee0b7317e45c8f683a47f5075d14b6b379d26ed81b08815e6f942844f514018b4e7de02cf6582e1ed65f1960d39dca389409fb439d13594208f3ddd2b84a83d9db8a7375a59bd1ec69be7ed57882eb9abef694761171f2af79000
|
|
73
|
+
`),
|
|
74
|
+
);
|
|
75
|
+
const kaspa = new Kaspa(transport);
|
|
76
|
+
const address = (await kaspa.getAddress("44'/111111'/0'/0/0", true))
|
|
77
|
+
.address;
|
|
78
|
+
|
|
79
|
+
expect(address).toEqual(
|
|
80
|
+
"kaspa:qpsq6flzeqsj0cuwuzmnzlj9ermg8frl2p6azjmtx7wjdmvpkzyp24kndspxw",
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("signTransaction with simple data", async () => {
|
|
85
|
+
const transport = await openTransportReplayer(
|
|
86
|
+
RecordStore.fromString(`
|
|
87
|
+
=> e00600800d00000101010203040580000000
|
|
88
|
+
<= 9000
|
|
89
|
+
=> e00601802a000000000010a1d02011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac
|
|
90
|
+
<= 9000
|
|
91
|
+
=> e00602002e000000000010c8e040b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70000000000000
|
|
92
|
+
<= 000040ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a32000112233445566778899aabbccddeeff00112233445566778899aabbccddeeff9000
|
|
93
|
+
`),
|
|
94
|
+
);
|
|
95
|
+
const kaspa = new Kaspa(transport);
|
|
96
|
+
|
|
97
|
+
const txin = new TransactionInput({
|
|
98
|
+
prevTxId:
|
|
99
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
100
|
+
value: 1100000,
|
|
101
|
+
addressType: 0,
|
|
102
|
+
addressIndex: 0,
|
|
103
|
+
outpointIndex: 0,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const txout = new TransactionOutput({
|
|
107
|
+
value: 1090000,
|
|
108
|
+
scriptPublicKey:
|
|
109
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const tx = new KaspaHwTransaction({
|
|
113
|
+
version: 0,
|
|
114
|
+
inputs: [txin],
|
|
115
|
+
outputs: [txout],
|
|
116
|
+
changeAddressType: 1,
|
|
117
|
+
changeAddressIndex: 0x02030405,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await kaspa.signTransaction(tx);
|
|
122
|
+
expect(txin.signature).toEqual(
|
|
123
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3",
|
|
124
|
+
);
|
|
125
|
+
expect(txin.sighash).toEqual(
|
|
126
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
|
|
127
|
+
);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
console.error(e);
|
|
130
|
+
expect(e).toBe(null);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("signTransaction with multi inputs", async () => {
|
|
135
|
+
const transport = await openTransportReplayer(
|
|
136
|
+
RecordStore.fromString(`
|
|
137
|
+
=> e00600800d00000102010203040580000000
|
|
138
|
+
<= 9000
|
|
139
|
+
=> e00601802a000000000010a1d02011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac
|
|
140
|
+
<= 9000
|
|
141
|
+
=> e00602802e000000000010c8e040b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70000000000000
|
|
142
|
+
<= 9000
|
|
143
|
+
=> e00602002e000000000010c8e040aa22362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70000000000000
|
|
144
|
+
<= 010040ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a32000112233445566778899aabbccddeeff00112233445566778899aabbccddeeff9000
|
|
145
|
+
=> e006030000
|
|
146
|
+
<= 000140b33f7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a32000112233445566778899aabbccddeeff00112233445566778899aabbccddeeff9000
|
|
147
|
+
`),
|
|
148
|
+
);
|
|
149
|
+
const kaspa = new Kaspa(transport);
|
|
150
|
+
|
|
151
|
+
const txin1 = new TransactionInput({
|
|
152
|
+
prevTxId:
|
|
153
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
154
|
+
value: 1100000,
|
|
155
|
+
addressType: 0,
|
|
156
|
+
addressIndex: 0,
|
|
157
|
+
outpointIndex: 0,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const txin2 = new TransactionInput({
|
|
161
|
+
prevTxId:
|
|
162
|
+
"40aa22362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
163
|
+
value: 1100000,
|
|
164
|
+
addressType: 0,
|
|
165
|
+
addressIndex: 0,
|
|
166
|
+
outpointIndex: 0,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const txout = new TransactionOutput({
|
|
170
|
+
value: 1090000,
|
|
171
|
+
scriptPublicKey:
|
|
172
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const tx = new KaspaHwTransaction({
|
|
176
|
+
version: 0,
|
|
177
|
+
inputs: [txin1, txin2],
|
|
178
|
+
outputs: [txout],
|
|
179
|
+
changeAddressType: 1,
|
|
180
|
+
changeAddressIndex: 0x02030405,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
await kaspa.signTransaction(tx);
|
|
185
|
+
expect(txin1.signature).toEqual(
|
|
186
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3",
|
|
187
|
+
);
|
|
188
|
+
expect(txin1.sighash).toEqual(
|
|
189
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
expect(txin2.signature).toEqual(
|
|
193
|
+
"b33f7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3",
|
|
194
|
+
);
|
|
195
|
+
expect(txin2.sighash).toEqual(
|
|
196
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
|
|
197
|
+
);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
console.error(e);
|
|
200
|
+
expect(e).toBe(null);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("signTransaction should always have sigLen = 64", async () => {
|
|
205
|
+
const transport = await openTransportReplayer(
|
|
206
|
+
RecordStore.fromString(`
|
|
207
|
+
=> e00600800d00000101010203040580000000
|
|
208
|
+
<= 9000
|
|
209
|
+
=> e00601802a000000000010a1d02011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac
|
|
210
|
+
<= 9000
|
|
211
|
+
=> e00602002e000000000010c8e040b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70000000000000
|
|
212
|
+
<= 00004100ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a32000112233445566778899aabbccddeeff00112233445566778899aabbccddeeff9000
|
|
213
|
+
`),
|
|
214
|
+
);
|
|
215
|
+
const kaspa = new Kaspa(transport);
|
|
216
|
+
|
|
217
|
+
const txin = new TransactionInput({
|
|
218
|
+
prevTxId:
|
|
219
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
220
|
+
value: 1100000,
|
|
221
|
+
addressType: 0,
|
|
222
|
+
addressIndex: 0,
|
|
223
|
+
outpointIndex: 0,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const txout = new TransactionOutput({
|
|
227
|
+
value: 1090000,
|
|
228
|
+
scriptPublicKey:
|
|
229
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const tx = new KaspaHwTransaction({
|
|
233
|
+
version: 0,
|
|
234
|
+
inputs: [txin],
|
|
235
|
+
outputs: [txout],
|
|
236
|
+
changeAddressType: 1,
|
|
237
|
+
changeAddressIndex: 0x02030405,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
let err: any = null;
|
|
241
|
+
try {
|
|
242
|
+
await kaspa.signTransaction(tx);
|
|
243
|
+
} catch (e) {
|
|
244
|
+
err = e;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
expect(err.name).not.toBe("RecordStoreWrongAPDU");
|
|
248
|
+
expect(err).not.toBe(null);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("signTransaction should always have sighashLen = 32", async () => {
|
|
252
|
+
const transport = await openTransportReplayer(
|
|
253
|
+
RecordStore.fromString(`
|
|
254
|
+
=> e00600800d00000101010203040580000000
|
|
255
|
+
<= 9000
|
|
256
|
+
=> e00601802a000000000010a1d02011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac
|
|
257
|
+
<= 9000
|
|
258
|
+
=> e00602002e000000000010c8e040b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70000000000000
|
|
259
|
+
<= 000040ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3210000112233445566778899aabbccddeeff00112233445566778899aabbccddeeff9000
|
|
260
|
+
`),
|
|
261
|
+
);
|
|
262
|
+
const kaspa = new Kaspa(transport);
|
|
263
|
+
|
|
264
|
+
const txin = new TransactionInput({
|
|
265
|
+
prevTxId:
|
|
266
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
267
|
+
value: 1100000,
|
|
268
|
+
addressType: 0,
|
|
269
|
+
addressIndex: 0,
|
|
270
|
+
outpointIndex: 0,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const txout = new TransactionOutput({
|
|
274
|
+
value: 1090000,
|
|
275
|
+
scriptPublicKey:
|
|
276
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const tx = new KaspaHwTransaction({
|
|
280
|
+
version: 0,
|
|
281
|
+
inputs: [txin],
|
|
282
|
+
outputs: [txout],
|
|
283
|
+
changeAddressType: 1,
|
|
284
|
+
changeAddressIndex: 0x02030405,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
let err: any = null;
|
|
288
|
+
try {
|
|
289
|
+
await kaspa.signTransaction(tx);
|
|
290
|
+
} catch (e) {
|
|
291
|
+
err = e;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
expect(err.name).not.toBe("RecordStoreWrongAPDU");
|
|
295
|
+
expect(err).not.toBe(null);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("Transaction should set default change address index and type", () => {
|
|
299
|
+
const tx = new KaspaHwTransaction({
|
|
300
|
+
version: 0,
|
|
301
|
+
inputs: [],
|
|
302
|
+
outputs: [],
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(tx.changeAddressIndex).toEqual(0);
|
|
306
|
+
expect(tx.changeAddressType).toEqual(0);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("TransactionInput should show null for signatureScript when unsigned", () => {
|
|
310
|
+
const txin = new TransactionInput({
|
|
311
|
+
prevTxId: "",
|
|
312
|
+
value: 0,
|
|
313
|
+
addressType: 0,
|
|
314
|
+
addressIndex: 0,
|
|
315
|
+
outpointIndex: 0,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(txin.toApiJSON().signatureScript).toEqual(null);
|
|
319
|
+
|
|
320
|
+
const expectedSignature =
|
|
321
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3";
|
|
322
|
+
txin.setSignature(expectedSignature);
|
|
323
|
+
|
|
324
|
+
expect(txin.toApiJSON().signatureScript).toEqual(
|
|
325
|
+
`41${expectedSignature}01`,
|
|
326
|
+
);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it("signMessage with simple data", async () => {
|
|
330
|
+
const expectedSignature =
|
|
331
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3";
|
|
332
|
+
const expectedMessageHash =
|
|
333
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
|
|
334
|
+
const transport = await openTransportReplayer(
|
|
335
|
+
RecordStore.fromString(`
|
|
336
|
+
=> e0070000160000000000800000000c48656c6c6f204b6173706121
|
|
337
|
+
<= 40${expectedSignature}20${expectedMessageHash}9000
|
|
338
|
+
`),
|
|
339
|
+
);
|
|
340
|
+
const kaspa = new Kaspa(transport);
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
const { signature, messageHash } = await kaspa.signMessage(
|
|
344
|
+
"Hello Kaspa!",
|
|
345
|
+
0,
|
|
346
|
+
0,
|
|
347
|
+
);
|
|
348
|
+
expect(signature).toEqual(expectedSignature);
|
|
349
|
+
expect(messageHash).toEqual(messageHash);
|
|
350
|
+
} catch (e) {
|
|
351
|
+
console.error(e);
|
|
352
|
+
expect(e).toBe(null);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("signMessage requires valid address index", async () => {
|
|
357
|
+
const expectedSignature =
|
|
358
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3";
|
|
359
|
+
const expectedMessageHash =
|
|
360
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
|
|
361
|
+
const transport = await openTransportReplayer(
|
|
362
|
+
RecordStore.fromString(`
|
|
363
|
+
=> e00700001600000000008000000000c48656c6c6f204b6173706121
|
|
364
|
+
<= 40${expectedSignature}20${expectedMessageHash}9000
|
|
365
|
+
`),
|
|
366
|
+
);
|
|
367
|
+
const kaspa = new Kaspa(transport);
|
|
368
|
+
|
|
369
|
+
let err: any = null;
|
|
370
|
+
try {
|
|
371
|
+
const { signature, messageHash } = await kaspa.signMessage(
|
|
372
|
+
"Hello Kaspa!",
|
|
373
|
+
0,
|
|
374
|
+
-1,
|
|
375
|
+
);
|
|
376
|
+
expect(signature).toEqual(expectedSignature);
|
|
377
|
+
expect(messageHash).toEqual(messageHash);
|
|
378
|
+
} catch (e) {
|
|
379
|
+
err = e;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
expect(err).not.toBe(null);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("signMessage requires valid account", async () => {
|
|
386
|
+
const expectedSignature =
|
|
387
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3";
|
|
388
|
+
const expectedMessageHash =
|
|
389
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
|
|
390
|
+
const transport = await openTransportReplayer(
|
|
391
|
+
RecordStore.fromString(`
|
|
392
|
+
=> e00700001600000000008000000000c48656c6c6f204b6173706121
|
|
393
|
+
<= 40${expectedSignature}20${expectedMessageHash}9000
|
|
394
|
+
`),
|
|
395
|
+
);
|
|
396
|
+
const kaspa = new Kaspa(transport);
|
|
397
|
+
|
|
398
|
+
let err: any = null;
|
|
399
|
+
try {
|
|
400
|
+
const { signature, messageHash } = await kaspa.signMessage(
|
|
401
|
+
"Hello Kaspa!",
|
|
402
|
+
0,
|
|
403
|
+
0,
|
|
404
|
+
0x80000000 - 1,
|
|
405
|
+
);
|
|
406
|
+
expect(signature).toEqual(expectedSignature);
|
|
407
|
+
expect(messageHash).toEqual(messageHash);
|
|
408
|
+
} catch (e) {
|
|
409
|
+
err = e;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
expect(err).not.toBe(null);
|
|
413
|
+
|
|
414
|
+
err = null;
|
|
415
|
+
try {
|
|
416
|
+
const { signature, messageHash } = await kaspa.signMessage(
|
|
417
|
+
"Hello Kaspa!",
|
|
418
|
+
0,
|
|
419
|
+
0,
|
|
420
|
+
0xffffffff + 1,
|
|
421
|
+
);
|
|
422
|
+
expect(signature).toEqual(expectedSignature);
|
|
423
|
+
expect(messageHash).toEqual(messageHash);
|
|
424
|
+
} catch (e) {
|
|
425
|
+
err = e;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
expect(err).not.toBe(null);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("signMessage sets default values for index and account", async () => {
|
|
432
|
+
const expectedSignature =
|
|
433
|
+
"ec4a7f581dc2450ab43b412a67bdfdafa6f98281f854a1508852042e41ef86695ec7f0fa36122193fa201ce783618710d65c85cf94640cb93e965f5158fd84a3";
|
|
434
|
+
const expectedMessageHash =
|
|
435
|
+
"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
|
|
436
|
+
const transport = await openTransportReplayer(
|
|
437
|
+
RecordStore.fromString(`
|
|
438
|
+
=> e00700001600000000008000000000c48656c6c6f204b6173706121
|
|
439
|
+
<= 40${expectedSignature}20${expectedMessageHash}9000
|
|
440
|
+
`),
|
|
441
|
+
);
|
|
442
|
+
const kaspa = new Kaspa(transport);
|
|
443
|
+
|
|
444
|
+
let err: any = null;
|
|
445
|
+
try {
|
|
446
|
+
const { signature, messageHash } =
|
|
447
|
+
await kaspa.signMessage("Hello Kaspa!");
|
|
448
|
+
expect(signature).toEqual(expectedSignature);
|
|
449
|
+
expect(messageHash).toEqual(messageHash);
|
|
450
|
+
} catch (e) {
|
|
451
|
+
err = e;
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
describe("Transaction", () => {
|
|
457
|
+
it("should serialize", () => {
|
|
458
|
+
const txin = new TransactionInput({
|
|
459
|
+
prevTxId:
|
|
460
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
461
|
+
value: 1100000,
|
|
462
|
+
addressType: 0,
|
|
463
|
+
addressIndex: 0,
|
|
464
|
+
outpointIndex: 0,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
const txout = new TransactionOutput({
|
|
468
|
+
value: 1090000,
|
|
469
|
+
scriptPublicKey:
|
|
470
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
const tx = new KaspaHwTransaction({
|
|
474
|
+
version: 0,
|
|
475
|
+
inputs: [txin],
|
|
476
|
+
outputs: [txout],
|
|
477
|
+
changeAddressType: 1,
|
|
478
|
+
changeAddressIndex: 0x02030405,
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
const expectation = Buffer.from([
|
|
482
|
+
0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x80, 0x00, 0x00,
|
|
483
|
+
0x00,
|
|
484
|
+
]);
|
|
485
|
+
|
|
486
|
+
expect(tx.serialize().equals(expectation)).toBeTruthy();
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it("should check that change address type is 0 or 1", () => {
|
|
490
|
+
const txin = new TransactionInput({
|
|
491
|
+
prevTxId:
|
|
492
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
493
|
+
value: 1100000,
|
|
494
|
+
addressType: 0,
|
|
495
|
+
addressIndex: 0,
|
|
496
|
+
outpointIndex: 0,
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const txout = new TransactionOutput({
|
|
500
|
+
value: 1090000,
|
|
501
|
+
scriptPublicKey:
|
|
502
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
let err: any = null;
|
|
506
|
+
try {
|
|
507
|
+
new KaspaHwTransaction({
|
|
508
|
+
version: 0,
|
|
509
|
+
inputs: [txin],
|
|
510
|
+
outputs: [txout],
|
|
511
|
+
changeAddressType: 2,
|
|
512
|
+
changeAddressIndex: 0x02030405,
|
|
513
|
+
});
|
|
514
|
+
} catch (e) {
|
|
515
|
+
err = e;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
expect(err).not.toBe(null);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it("should check that account is in 0x80000000 and 0xFFFFFFFF", () => {
|
|
522
|
+
const txin = new TransactionInput({
|
|
523
|
+
prevTxId:
|
|
524
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
525
|
+
value: 1100000,
|
|
526
|
+
addressType: 0,
|
|
527
|
+
addressIndex: 0,
|
|
528
|
+
outpointIndex: 0,
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
const txout = new TransactionOutput({
|
|
532
|
+
value: 1090000,
|
|
533
|
+
scriptPublicKey:
|
|
534
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
let err: any = null;
|
|
538
|
+
try {
|
|
539
|
+
new KaspaHwTransaction({
|
|
540
|
+
version: 0,
|
|
541
|
+
inputs: [txin],
|
|
542
|
+
outputs: [txout],
|
|
543
|
+
changeAddressType: 0,
|
|
544
|
+
changeAddressIndex: 0x02030405,
|
|
545
|
+
account: 0x80000000 - 1,
|
|
546
|
+
});
|
|
547
|
+
} catch (e) {
|
|
548
|
+
err = e;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
expect(err).not.toBe(null);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
it("should check that change address index to be in range", () => {
|
|
555
|
+
const txin = new TransactionInput({
|
|
556
|
+
prevTxId:
|
|
557
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
558
|
+
value: 1100000,
|
|
559
|
+
addressType: 0,
|
|
560
|
+
addressIndex: 0,
|
|
561
|
+
outpointIndex: 0,
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
const txout = new TransactionOutput({
|
|
565
|
+
value: 1090000,
|
|
566
|
+
scriptPublicKey:
|
|
567
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
let err: any = null;
|
|
571
|
+
try {
|
|
572
|
+
new KaspaHwTransaction({
|
|
573
|
+
version: 0,
|
|
574
|
+
inputs: [txin],
|
|
575
|
+
outputs: [txout],
|
|
576
|
+
changeAddressType: 0,
|
|
577
|
+
changeAddressIndex: -1,
|
|
578
|
+
});
|
|
579
|
+
} catch (e) {
|
|
580
|
+
err = e;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
expect(err).not.toBe(null);
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
it("should check that API JSON is producible", () => {
|
|
587
|
+
const txin = new TransactionInput({
|
|
588
|
+
prevTxId:
|
|
589
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
590
|
+
value: 1100000,
|
|
591
|
+
addressType: 0,
|
|
592
|
+
addressIndex: 0,
|
|
593
|
+
outpointIndex: 0,
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
const txout = new TransactionOutput({
|
|
597
|
+
value: 1090000,
|
|
598
|
+
scriptPublicKey:
|
|
599
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
const tx = new KaspaHwTransaction({
|
|
603
|
+
version: 0,
|
|
604
|
+
inputs: [txin],
|
|
605
|
+
outputs: [txout],
|
|
606
|
+
changeAddressType: 1,
|
|
607
|
+
changeAddressIndex: 0x02030405,
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
const json = tx.toApiJSON().transaction;
|
|
611
|
+
expect(json.version).toEqual(0);
|
|
612
|
+
expect(json.inputs.length).toEqual(1);
|
|
613
|
+
expect(json.outputs.length).toEqual(1);
|
|
614
|
+
expect(json.lockTime).toEqual(0);
|
|
615
|
+
expect(json.subnetworkId).toEqual(
|
|
616
|
+
"0000000000000000000000000000000000000000",
|
|
617
|
+
);
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
describe("TransactionInput", () => {
|
|
622
|
+
it("should allow for highest possible kaspa value", () => {
|
|
623
|
+
let err: any = null;
|
|
624
|
+
|
|
625
|
+
try {
|
|
626
|
+
const txin1 = new TransactionInput({
|
|
627
|
+
prevTxId:
|
|
628
|
+
"40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70",
|
|
629
|
+
value: 18446744073709551615,
|
|
630
|
+
addressType: 0,
|
|
631
|
+
addressIndex: 0,
|
|
632
|
+
outpointIndex: 0,
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
txin1.serialize();
|
|
636
|
+
|
|
637
|
+
txin1.toApiJSON();
|
|
638
|
+
} catch (e) {
|
|
639
|
+
err = e;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
expect(err).toBe(null);
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
describe("TransactionOutput", () => {
|
|
647
|
+
it("should throw no error if only scriptPublicKey and value is set", () => {
|
|
648
|
+
let err: any = null;
|
|
649
|
+
try {
|
|
650
|
+
new TransactionOutput({
|
|
651
|
+
value: 1090000,
|
|
652
|
+
scriptPublicKey:
|
|
653
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
654
|
+
});
|
|
655
|
+
} catch (e) {
|
|
656
|
+
err = e;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
expect(err).toBe(null);
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
it("should serialize value and scriptPublicKey", () => {
|
|
663
|
+
const serial = new TransactionOutput({
|
|
664
|
+
value: 1090000,
|
|
665
|
+
scriptPublicKey:
|
|
666
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
667
|
+
}).serialize();
|
|
668
|
+
|
|
669
|
+
const expectation = Buffer.from([
|
|
670
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa1, 0xd0, 0x20, 0x11, 0xa7, 0x21,
|
|
671
|
+
0x5f, 0x66, 0x8e, 0x92, 0x10, 0x13, 0xeb, 0x7a, 0xac, 0x9b, 0x7e, 0x64,
|
|
672
|
+
0xb9, 0xec, 0x6e, 0x75, 0x7c, 0x1b, 0x64, 0x8e, 0x89, 0x38, 0x8c, 0x91,
|
|
673
|
+
0x9f, 0x67, 0x6a, 0xa8, 0x8c, 0xac,
|
|
674
|
+
]);
|
|
675
|
+
|
|
676
|
+
expect(serial.equals(expectation)).toBeTruthy();
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it("should throw errors if value is < 0 or > 0xFFFFFFFFFFFFFFFF", () => {
|
|
680
|
+
let err: any = null;
|
|
681
|
+
try {
|
|
682
|
+
new TransactionOutput({
|
|
683
|
+
value: 0,
|
|
684
|
+
scriptPublicKey:
|
|
685
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
686
|
+
});
|
|
687
|
+
} catch (e) {
|
|
688
|
+
err = e;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
expect(err).not.toBe(null);
|
|
692
|
+
|
|
693
|
+
try {
|
|
694
|
+
new TransactionOutput({
|
|
695
|
+
value: 0x10000000000000000,
|
|
696
|
+
scriptPublicKey:
|
|
697
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
698
|
+
});
|
|
699
|
+
} catch (e) {
|
|
700
|
+
err = e;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
expect(err).not.toBe(null);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
it("should allow for highest possible kaspa value", () => {
|
|
707
|
+
let err: any = null;
|
|
708
|
+
try {
|
|
709
|
+
const output = new TransactionOutput({
|
|
710
|
+
value: Number.MAX_SAFE_INTEGER,
|
|
711
|
+
scriptPublicKey:
|
|
712
|
+
"2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac",
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
output.serialize();
|
|
716
|
+
|
|
717
|
+
output.toApiJSON();
|
|
718
|
+
} catch (e) {
|
|
719
|
+
err = e;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
expect(err).toBe(null);
|
|
723
|
+
});
|
|
724
|
+
});
|