@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.
Files changed (54) hide show
  1. package/.prettierrc +4 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/CHANGELOG.md +7 -0
  4. package/LICENSE.txt +21 -0
  5. package/README.md +105 -0
  6. package/jest.config.ts +10 -0
  7. package/lib/Kaspa.d.ts +59 -0
  8. package/lib/Kaspa.d.ts.map +1 -0
  9. package/lib/Kaspa.js +185 -0
  10. package/lib/Kaspa.js.map +1 -0
  11. package/lib/base32.d.ts +11 -0
  12. package/lib/base32.d.ts.map +1 -0
  13. package/lib/base32.js +36 -0
  14. package/lib/base32.js.map +1 -0
  15. package/lib/index.d.ts +4 -0
  16. package/lib/index.d.ts.map +1 -0
  17. package/lib/index.js +13 -0
  18. package/lib/index.js.map +1 -0
  19. package/lib/kaspa-util.d.ts +3 -0
  20. package/lib/kaspa-util.d.ts.map +1 -0
  21. package/lib/kaspa-util.js +102 -0
  22. package/lib/kaspa-util.js.map +1 -0
  23. package/lib/kaspaHwTransaction.d.ts +89 -0
  24. package/lib/kaspaHwTransaction.d.ts.map +1 -0
  25. package/lib/kaspaHwTransaction.js +157 -0
  26. package/lib/kaspaHwTransaction.js.map +1 -0
  27. package/lib-es/Kaspa.d.ts +59 -0
  28. package/lib-es/Kaspa.d.ts.map +1 -0
  29. package/lib-es/Kaspa.js +179 -0
  30. package/lib-es/Kaspa.js.map +1 -0
  31. package/lib-es/base32.d.ts +11 -0
  32. package/lib-es/base32.d.ts.map +1 -0
  33. package/lib-es/base32.js +33 -0
  34. package/lib-es/base32.js.map +1 -0
  35. package/lib-es/index.d.ts +4 -0
  36. package/lib-es/index.d.ts.map +1 -0
  37. package/lib-es/index.js +4 -0
  38. package/lib-es/index.js.map +1 -0
  39. package/lib-es/kaspa-util.d.ts +3 -0
  40. package/lib-es/kaspa-util.d.ts.map +1 -0
  41. package/lib-es/kaspa-util.js +95 -0
  42. package/lib-es/kaspa-util.js.map +1 -0
  43. package/lib-es/kaspaHwTransaction.d.ts +89 -0
  44. package/lib-es/kaspaHwTransaction.d.ts.map +1 -0
  45. package/lib-es/kaspaHwTransaction.js +150 -0
  46. package/lib-es/kaspaHwTransaction.js.map +1 -0
  47. package/package.json +43 -0
  48. package/src/Kaspa.ts +261 -0
  49. package/src/base32.ts +36 -0
  50. package/src/index.ts +9 -0
  51. package/src/kaspa-util.ts +107 -0
  52. package/src/kaspaHwTransaction.ts +244 -0
  53. package/tests/kaspa.test.ts +724 -0
  54. package/tsconfig.json +25 -0
package/src/base32.ts ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /***
3
+ * https://github.com/bitcoincashjs/cashaddr
4
+ * Copyright (c) 2018 Matias Alejo Garcia
5
+ * Copyright (c) 2017 Emilio Almansi
6
+ * Distributed under the MIT software license, see the accompanying
7
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.
8
+ */
9
+
10
+ /***
11
+ * Charset containing the 32 symbols used in the base32 encoding.
12
+ */
13
+ const CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
14
+
15
+ /***
16
+ * Encodes the given array of 5-bit integers as a base32-encoded string.
17
+ *
18
+ * @param {Array} data Array of integers between 0 and 31 inclusive.
19
+ */
20
+ export function encode(data: Array<number>) {
21
+ let base32 = "";
22
+ for (let i = 0; i < data.length; i++) {
23
+ const value = data[i];
24
+ if (!(0 <= value && value < 32)) {
25
+ throw new Error("value " + value);
26
+ }
27
+ base32 += CHARSET[value];
28
+ }
29
+ return base32;
30
+ }
31
+
32
+ const base32 = {
33
+ encode,
34
+ };
35
+
36
+ export default base32;
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ import Kaspa from "./Kaspa";
2
+
3
+ export {
4
+ TransactionInput,
5
+ TransactionOutput,
6
+ KaspaHwTransaction,
7
+ } from "./kaspaHwTransaction";
8
+
9
+ export default Kaspa;
@@ -0,0 +1,107 @@
1
+ import base32 from "./base32";
2
+
3
+ function convertBits(
4
+ data: number[],
5
+ from: number,
6
+ to: number,
7
+ strict: boolean = false,
8
+ ): number[] {
9
+ strict = strict || false;
10
+ let accumulator = 0;
11
+ let bits = 0;
12
+ const result: number[] = [];
13
+ const mask = (1 << to) - 1;
14
+ for (let i = 0; i < data.length; i++) {
15
+ const value = data[i];
16
+ if (value < 0 || value >> from !== 0) {
17
+ throw new Error(`Invalid argument: value = ${value}`);
18
+ }
19
+
20
+ accumulator = (accumulator << from) | value;
21
+ bits += from;
22
+ while (bits >= to) {
23
+ bits -= to;
24
+ result.push((accumulator >> bits) & mask);
25
+ }
26
+ }
27
+ if (!strict) {
28
+ if (bits > 0) {
29
+ result.push((accumulator << (to - bits)) & mask);
30
+ }
31
+ } else {
32
+ if (!(bits >= from || (accumulator << (to - bits)) & mask)) {
33
+ throw new Error("Conversion requires padding but strict mode was used");
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+
39
+ function prefixToArray(prefix): number[] {
40
+ const result: number[] = [];
41
+ for (let i = 0; i < prefix.length; i++) {
42
+ const char = prefix.charCodeAt(i);
43
+ result.push(char & 31);
44
+ }
45
+ return result;
46
+ }
47
+
48
+ const GENERATOR1 = [0x98, 0x79, 0xf3, 0xae, 0x1e];
49
+ const GENERATOR2 = [0xf2bc8e61, 0xb76d99e2, 0x3e5fb3c4, 0x2eabe2a8, 0x4f43e470];
50
+
51
+ function polymod(data) {
52
+ // Treat c as 8 bits + 32 bits
53
+ let c0 = 0,
54
+ c1 = 1,
55
+ C = 0;
56
+ for (let j = 0; j < data.length; j++) {
57
+ // Set C to c shifted by 35
58
+ C = c0 >>> 3;
59
+ // 0x[07]ffffffff
60
+ c0 &= 0x07;
61
+ // Shift as a whole number
62
+ c0 <<= 5;
63
+ c0 |= c1 >>> 27;
64
+ // 0xffffffff >>> 5
65
+ c1 &= 0x07ffffff;
66
+ c1 <<= 5;
67
+ // xor the last 5 bits
68
+ c1 ^= data[j];
69
+ for (let i = 0; i < GENERATOR1.length; ++i) {
70
+ if (C & (1 << i)) {
71
+ c0 ^= GENERATOR1[i];
72
+ c1 ^= GENERATOR2[i];
73
+ }
74
+ }
75
+ }
76
+ c1 ^= 1;
77
+ // Negative numbers -> large positive numbers
78
+ if (c1 < 0) {
79
+ c1 ^= 1 << 31;
80
+ c1 += (1 << 30) * 2;
81
+ }
82
+ // Unless bitwise operations are used,
83
+ // numbers are consisting of 52 bits, except
84
+ // the sign bit. The result is max 40 bits,
85
+ // so it fits perfectly in one number!
86
+ return c0 * (1 << 30) * 4 + c1;
87
+ }
88
+
89
+ function checksumToArray(checksum) {
90
+ const result: number[] = [];
91
+ for (let i = 0; i < 8; ++i) {
92
+ result.push(checksum & 31);
93
+ checksum /= 32;
94
+ }
95
+ return result.reverse();
96
+ }
97
+
98
+ export function publicKeyToAddress(hashBuffer: Buffer): string {
99
+ const eight0: number[] = [0, 0, 0, 0, 0, 0, 0, 0];
100
+ const prefixData: number[] = prefixToArray("kaspa").concat([0]);
101
+ const versionByte: number = 0;
102
+ const arr: number[] = Array.prototype.slice.call(hashBuffer, 0);
103
+ const payloadData: number[] = convertBits([versionByte].concat(arr), 8, 5);
104
+ const checksumData: number[] = prefixData.concat(payloadData).concat(eight0);
105
+ const payload = payloadData.concat(checksumToArray(polymod(checksumData)));
106
+ return "kaspa:" + base32.encode(payload);
107
+ }
@@ -0,0 +1,244 @@
1
+ type TransactionApiJSON = {
2
+ transaction: {
3
+ version: number;
4
+ inputs: TransactionInputApiJSON[];
5
+ outputs: TransactionOutputApiJSON[];
6
+ lockTime: number;
7
+ subnetworkId: string;
8
+ };
9
+ };
10
+
11
+ export class KaspaHwTransaction {
12
+ inputs: TransactionInput[];
13
+ outputs: TransactionOutput[];
14
+ version: number;
15
+ changeAddressType: number;
16
+ changeAddressIndex: number;
17
+ account: number;
18
+
19
+ constructor(txData: {
20
+ inputs: TransactionInput[];
21
+ outputs: TransactionOutput[];
22
+ version: number;
23
+ changeAddressType?: number;
24
+ changeAddressIndex?: number;
25
+ account?: number;
26
+ }) {
27
+ /**
28
+ * @type {TransactionInput[]}
29
+ */
30
+ this.inputs = txData.inputs;
31
+ /**
32
+ * @type {TransactionOutput[]}
33
+ */
34
+ this.outputs = txData.outputs;
35
+ /**
36
+ * @type {int}
37
+ */
38
+ this.version = txData.version;
39
+
40
+ this.changeAddressType = txData.changeAddressType ?? 0;
41
+ this.changeAddressIndex = txData.changeAddressIndex ?? 0;
42
+ this.account = txData.account ?? 0x80000000;
43
+
44
+ if (!(this.changeAddressType === 0 || this.changeAddressType === 1)) {
45
+ throw new Error("changeAddressType must be 0 or 1 if set");
46
+ }
47
+
48
+ if (this.account < 0x80000000 || this.account > 0xffffffff) {
49
+ throw new Error("account must be between 0x80000000 and 0xFFFFFFFF");
50
+ }
51
+
52
+ if (
53
+ this.changeAddressIndex < 0x00000000 ||
54
+ this.changeAddressIndex > 0xffffffff
55
+ ) {
56
+ throw new Error(
57
+ `changeAddressIndex must be between 0x00000000 and 0xFFFFFFFF`,
58
+ );
59
+ }
60
+ }
61
+
62
+ serialize(): Buffer {
63
+ const versionBuf = Buffer.alloc(2);
64
+ versionBuf.writeUInt16BE(this.version);
65
+
66
+ const outputLenBuf = Buffer.alloc(1);
67
+ outputLenBuf.writeUInt8(this.outputs.length);
68
+
69
+ const inputLenBuf = Buffer.alloc(1);
70
+ inputLenBuf.writeUInt8(this.inputs.length);
71
+
72
+ const changeAddressTypeBuf = Buffer.alloc(1);
73
+ changeAddressTypeBuf.writeUInt8(this.changeAddressType);
74
+
75
+ const changeAddressIndexBuf = Buffer.alloc(4);
76
+ changeAddressIndexBuf.writeUInt32BE(this.changeAddressIndex);
77
+
78
+ const accountBuf = Buffer.alloc(4);
79
+ accountBuf.writeUInt32BE(this.account);
80
+
81
+ return Buffer.concat([
82
+ versionBuf,
83
+ outputLenBuf,
84
+ inputLenBuf,
85
+ changeAddressTypeBuf,
86
+ changeAddressIndexBuf,
87
+ accountBuf,
88
+ ]);
89
+ }
90
+
91
+ /**
92
+ * Convert this transaction to a JSON object that api.kaspa.org will accept
93
+ */
94
+ toApiJSON(): TransactionApiJSON {
95
+ return {
96
+ transaction: {
97
+ version: this.version,
98
+ inputs: this.inputs.map((i) => i.toApiJSON()),
99
+ outputs: this.outputs.map((o) => o.toApiJSON()),
100
+ lockTime: 0,
101
+ subnetworkId: "0000000000000000000000000000000000000000",
102
+ },
103
+ };
104
+ }
105
+ }
106
+
107
+ type TransactionInputApiJSON = {
108
+ previousOutpoint: {
109
+ transactionId: string;
110
+ index: number;
111
+ };
112
+ signatureScript: string | null;
113
+ sequence: number;
114
+ sigOpCount: number;
115
+ };
116
+
117
+ export class TransactionInput {
118
+ signature?: string | null;
119
+ sighash?: string | null;
120
+ value: number;
121
+ prevTxId: string;
122
+ outpointIndex: number;
123
+ addressType: number;
124
+ addressIndex: number;
125
+
126
+ constructor(inputData: {
127
+ value: number;
128
+ prevTxId: string;
129
+ outpointIndex: number;
130
+ addressType: number;
131
+ addressIndex: number;
132
+ }) {
133
+ this.value = inputData.value;
134
+ this.prevTxId = inputData.prevTxId;
135
+ this.outpointIndex = inputData.outpointIndex;
136
+ this.addressType = inputData.addressType;
137
+ this.addressIndex = inputData.addressIndex;
138
+ this.signature = null;
139
+ this.sighash = null;
140
+ }
141
+
142
+ serialize(): Buffer {
143
+ const valueBuf = Buffer.from(toBigEndianHex(this.value), "hex");
144
+
145
+ const addressTypeBuf = Buffer.alloc(1);
146
+ addressTypeBuf.writeUInt8(this.addressType);
147
+
148
+ const addressIndexBuf = Buffer.alloc(4);
149
+ addressIndexBuf.writeUInt32BE(this.addressIndex);
150
+
151
+ const outpointIndexBuf = Buffer.alloc(1);
152
+ outpointIndexBuf.writeUInt8(this.outpointIndex);
153
+
154
+ return Buffer.concat([
155
+ valueBuf,
156
+ Buffer.from(this.prevTxId, "hex"),
157
+ addressTypeBuf,
158
+ addressIndexBuf,
159
+ outpointIndexBuf,
160
+ ]);
161
+ }
162
+
163
+ /**
164
+ *
165
+ * @param {string} signature
166
+ */
167
+ setSignature(signature: string): void {
168
+ this.signature = signature;
169
+ }
170
+
171
+ setSighash(sighash: string): void {
172
+ this.sighash = sighash;
173
+ }
174
+
175
+ toApiJSON(): TransactionInputApiJSON {
176
+ return {
177
+ previousOutpoint: {
178
+ transactionId: this.prevTxId,
179
+ index: this.outpointIndex,
180
+ },
181
+ signatureScript: this.signature ? `41${this.signature}01` : null,
182
+ sequence: 0,
183
+ sigOpCount: 1,
184
+ };
185
+ }
186
+ }
187
+
188
+ type TransactionOutputApiJSON = {
189
+ amount: number;
190
+ scriptPublicKey: {
191
+ version: number;
192
+ scriptPublicKey: string;
193
+ };
194
+ };
195
+
196
+ export class TransactionOutput {
197
+ value: number;
198
+ scriptPublicKey: string;
199
+
200
+ constructor(outputData: { value: number; scriptPublicKey: string }) {
201
+ if (
202
+ !outputData.value ||
203
+ outputData.value < 0 ||
204
+ outputData.value > Number.MAX_SAFE_INTEGER
205
+ ) {
206
+ throw new Error(
207
+ `value must be set to a value greater than 0 and less than ${Number.MAX_SAFE_INTEGER.toString()}`,
208
+ );
209
+ }
210
+ this.value = outputData.value;
211
+
212
+ // Only then do we care about the script public key
213
+ this.scriptPublicKey = outputData.scriptPublicKey;
214
+ }
215
+
216
+ serialize(): Buffer {
217
+ const valueBuf: Buffer = Buffer.from(toBigEndianHex(this.value), "hex");
218
+ return Buffer.concat([valueBuf, Buffer.from(this.scriptPublicKey, "hex")]);
219
+ }
220
+
221
+ toApiJSON(): TransactionOutputApiJSON {
222
+ return {
223
+ amount: this.value,
224
+ scriptPublicKey: {
225
+ version: 0,
226
+ scriptPublicKey: this.scriptPublicKey,
227
+ },
228
+ };
229
+ }
230
+ }
231
+
232
+ export function toBigEndianHex(numberToConvert: number) {
233
+ let baseStr = "0000000000000000";
234
+
235
+ baseStr += numberToConvert.toString(16);
236
+
237
+ return baseStr.substring(baseStr.length - 16, baseStr.length);
238
+ }
239
+
240
+ export default {
241
+ Transaction: KaspaHwTransaction,
242
+ TransactionInput,
243
+ TransactionOutput,
244
+ };