@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
@@ -0,0 +1,95 @@
1
+ import base32 from "./base32";
2
+ function convertBits(data, from, to, strict = false) {
3
+ strict = strict || false;
4
+ let accumulator = 0;
5
+ let bits = 0;
6
+ const result = [];
7
+ const mask = (1 << to) - 1;
8
+ for (let i = 0; i < data.length; i++) {
9
+ const value = data[i];
10
+ if (value < 0 || value >> from !== 0) {
11
+ throw new Error(`Invalid argument: value = ${value}`);
12
+ }
13
+ accumulator = (accumulator << from) | value;
14
+ bits += from;
15
+ while (bits >= to) {
16
+ bits -= to;
17
+ result.push((accumulator >> bits) & mask);
18
+ }
19
+ }
20
+ if (!strict) {
21
+ if (bits > 0) {
22
+ result.push((accumulator << (to - bits)) & mask);
23
+ }
24
+ }
25
+ else {
26
+ if (!(bits >= from || (accumulator << (to - bits)) & mask)) {
27
+ throw new Error("Conversion requires padding but strict mode was used");
28
+ }
29
+ }
30
+ return result;
31
+ }
32
+ function prefixToArray(prefix) {
33
+ const result = [];
34
+ for (let i = 0; i < prefix.length; i++) {
35
+ const char = prefix.charCodeAt(i);
36
+ result.push(char & 31);
37
+ }
38
+ return result;
39
+ }
40
+ const GENERATOR1 = [0x98, 0x79, 0xf3, 0xae, 0x1e];
41
+ const GENERATOR2 = [0xf2bc8e61, 0xb76d99e2, 0x3e5fb3c4, 0x2eabe2a8, 0x4f43e470];
42
+ function polymod(data) {
43
+ // Treat c as 8 bits + 32 bits
44
+ let c0 = 0, c1 = 1, C = 0;
45
+ for (let j = 0; j < data.length; j++) {
46
+ // Set C to c shifted by 35
47
+ C = c0 >>> 3;
48
+ // 0x[07]ffffffff
49
+ c0 &= 0x07;
50
+ // Shift as a whole number
51
+ c0 <<= 5;
52
+ c0 |= c1 >>> 27;
53
+ // 0xffffffff >>> 5
54
+ c1 &= 0x07ffffff;
55
+ c1 <<= 5;
56
+ // xor the last 5 bits
57
+ c1 ^= data[j];
58
+ for (let i = 0; i < GENERATOR1.length; ++i) {
59
+ if (C & (1 << i)) {
60
+ c0 ^= GENERATOR1[i];
61
+ c1 ^= GENERATOR2[i];
62
+ }
63
+ }
64
+ }
65
+ c1 ^= 1;
66
+ // Negative numbers -> large positive numbers
67
+ if (c1 < 0) {
68
+ c1 ^= 1 << 31;
69
+ c1 += (1 << 30) * 2;
70
+ }
71
+ // Unless bitwise operations are used,
72
+ // numbers are consisting of 52 bits, except
73
+ // the sign bit. The result is max 40 bits,
74
+ // so it fits perfectly in one number!
75
+ return c0 * (1 << 30) * 4 + c1;
76
+ }
77
+ function checksumToArray(checksum) {
78
+ const result = [];
79
+ for (let i = 0; i < 8; ++i) {
80
+ result.push(checksum & 31);
81
+ checksum /= 32;
82
+ }
83
+ return result.reverse();
84
+ }
85
+ export function publicKeyToAddress(hashBuffer) {
86
+ const eight0 = [0, 0, 0, 0, 0, 0, 0, 0];
87
+ const prefixData = prefixToArray("kaspa").concat([0]);
88
+ const versionByte = 0;
89
+ const arr = Array.prototype.slice.call(hashBuffer, 0);
90
+ const payloadData = convertBits([versionByte].concat(arr), 8, 5);
91
+ const checksumData = prefixData.concat(payloadData).concat(eight0);
92
+ const payload = payloadData.concat(checksumToArray(polymod(checksumData)));
93
+ return "kaspa:" + base32.encode(payload);
94
+ }
95
+ //# sourceMappingURL=kaspa-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kaspa-util.js","sourceRoot":"","sources":["../src/kaspa-util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /// <reference types="node" />
2
+ type TransactionApiJSON = {
3
+ transaction: {
4
+ version: number;
5
+ inputs: TransactionInputApiJSON[];
6
+ outputs: TransactionOutputApiJSON[];
7
+ lockTime: number;
8
+ subnetworkId: string;
9
+ };
10
+ };
11
+ export declare class KaspaHwTransaction {
12
+ inputs: TransactionInput[];
13
+ outputs: TransactionOutput[];
14
+ version: number;
15
+ changeAddressType: number;
16
+ changeAddressIndex: number;
17
+ account: number;
18
+ constructor(txData: {
19
+ inputs: TransactionInput[];
20
+ outputs: TransactionOutput[];
21
+ version: number;
22
+ changeAddressType?: number;
23
+ changeAddressIndex?: number;
24
+ account?: number;
25
+ });
26
+ serialize(): Buffer;
27
+ /**
28
+ * Convert this transaction to a JSON object that api.kaspa.org will accept
29
+ */
30
+ toApiJSON(): TransactionApiJSON;
31
+ }
32
+ type TransactionInputApiJSON = {
33
+ previousOutpoint: {
34
+ transactionId: string;
35
+ index: number;
36
+ };
37
+ signatureScript: string | null;
38
+ sequence: number;
39
+ sigOpCount: number;
40
+ };
41
+ export declare class TransactionInput {
42
+ signature?: string | null;
43
+ sighash?: string | null;
44
+ value: number;
45
+ prevTxId: string;
46
+ outpointIndex: number;
47
+ addressType: number;
48
+ addressIndex: number;
49
+ constructor(inputData: {
50
+ value: number;
51
+ prevTxId: string;
52
+ outpointIndex: number;
53
+ addressType: number;
54
+ addressIndex: number;
55
+ });
56
+ serialize(): Buffer;
57
+ /**
58
+ *
59
+ * @param {string} signature
60
+ */
61
+ setSignature(signature: string): void;
62
+ setSighash(sighash: string): void;
63
+ toApiJSON(): TransactionInputApiJSON;
64
+ }
65
+ type TransactionOutputApiJSON = {
66
+ amount: number;
67
+ scriptPublicKey: {
68
+ version: number;
69
+ scriptPublicKey: string;
70
+ };
71
+ };
72
+ export declare class TransactionOutput {
73
+ value: number;
74
+ scriptPublicKey: string;
75
+ constructor(outputData: {
76
+ value: number;
77
+ scriptPublicKey: string;
78
+ });
79
+ serialize(): Buffer;
80
+ toApiJSON(): TransactionOutputApiJSON;
81
+ }
82
+ export declare function toBigEndianHex(numberToConvert: number): string;
83
+ declare const _default: {
84
+ Transaction: typeof KaspaHwTransaction;
85
+ TransactionInput: typeof TransactionInput;
86
+ TransactionOutput: typeof TransactionOutput;
87
+ };
88
+ export default _default;
89
+ //# sourceMappingURL=kaspaHwTransaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kaspaHwTransaction.d.ts","sourceRoot":"","sources":["../src/kaspaHwTransaction.ts"],"names":[],"mappings":";AAAA,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,uBAAuB,EAAE,CAAC;QAClC,OAAO,EAAE,wBAAwB,EAAE,CAAC;QACpC,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,qBAAa,kBAAkB;IAC7B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;gBAEJ,MAAM,EAAE;QAClB,MAAM,EAAE,gBAAgB,EAAE,CAAC;QAC3B,OAAO,EAAE,iBAAiB,EAAE,CAAC;QAC7B,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;IAoCD,SAAS,IAAI,MAAM;IA6BnB;;OAEG;IACH,SAAS,IAAI,kBAAkB;CAWhC;AAED,KAAK,uBAAuB,GAAG;IAC7B,gBAAgB,EAAE;QAChB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,gBAAgB;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;gBAET,SAAS,EAAE;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB;IAUD,SAAS,IAAI,MAAM;IAqBnB;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIjC,SAAS,IAAI,uBAAuB;CAWrC;AAED,KAAK,wBAAwB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH,CAAC;AAEF,qBAAa,iBAAiB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;gBAEZ,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE;IAgBlE,SAAS,IAAI,MAAM;IAKnB,SAAS,IAAI,wBAAwB;CAStC;AAED,wBAAgB,cAAc,CAAC,eAAe,EAAE,MAAM,UAMrD;;;;;;AAED,wBAIE"}
@@ -0,0 +1,150 @@
1
+ export class KaspaHwTransaction {
2
+ constructor(txData) {
3
+ var _a, _b, _c;
4
+ /**
5
+ * @type {TransactionInput[]}
6
+ */
7
+ this.inputs = txData.inputs;
8
+ /**
9
+ * @type {TransactionOutput[]}
10
+ */
11
+ this.outputs = txData.outputs;
12
+ /**
13
+ * @type {int}
14
+ */
15
+ this.version = txData.version;
16
+ this.changeAddressType = (_a = txData.changeAddressType) !== null && _a !== void 0 ? _a : 0;
17
+ this.changeAddressIndex = (_b = txData.changeAddressIndex) !== null && _b !== void 0 ? _b : 0;
18
+ this.account = (_c = txData.account) !== null && _c !== void 0 ? _c : 0x80000000;
19
+ if (!(this.changeAddressType === 0 || this.changeAddressType === 1)) {
20
+ throw new Error("changeAddressType must be 0 or 1 if set");
21
+ }
22
+ if (this.account < 0x80000000 || this.account > 0xffffffff) {
23
+ throw new Error("account must be between 0x80000000 and 0xFFFFFFFF");
24
+ }
25
+ if (this.changeAddressIndex < 0x00000000 ||
26
+ this.changeAddressIndex > 0xffffffff) {
27
+ throw new Error(`changeAddressIndex must be between 0x00000000 and 0xFFFFFFFF`);
28
+ }
29
+ }
30
+ serialize() {
31
+ const versionBuf = Buffer.alloc(2);
32
+ versionBuf.writeUInt16BE(this.version);
33
+ const outputLenBuf = Buffer.alloc(1);
34
+ outputLenBuf.writeUInt8(this.outputs.length);
35
+ const inputLenBuf = Buffer.alloc(1);
36
+ inputLenBuf.writeUInt8(this.inputs.length);
37
+ const changeAddressTypeBuf = Buffer.alloc(1);
38
+ changeAddressTypeBuf.writeUInt8(this.changeAddressType);
39
+ const changeAddressIndexBuf = Buffer.alloc(4);
40
+ changeAddressIndexBuf.writeUInt32BE(this.changeAddressIndex);
41
+ const accountBuf = Buffer.alloc(4);
42
+ accountBuf.writeUInt32BE(this.account);
43
+ return Buffer.concat([
44
+ versionBuf,
45
+ outputLenBuf,
46
+ inputLenBuf,
47
+ changeAddressTypeBuf,
48
+ changeAddressIndexBuf,
49
+ accountBuf,
50
+ ]);
51
+ }
52
+ /**
53
+ * Convert this transaction to a JSON object that api.kaspa.org will accept
54
+ */
55
+ toApiJSON() {
56
+ return {
57
+ transaction: {
58
+ version: this.version,
59
+ inputs: this.inputs.map((i) => i.toApiJSON()),
60
+ outputs: this.outputs.map((o) => o.toApiJSON()),
61
+ lockTime: 0,
62
+ subnetworkId: "0000000000000000000000000000000000000000",
63
+ },
64
+ };
65
+ }
66
+ }
67
+ export class TransactionInput {
68
+ constructor(inputData) {
69
+ this.value = inputData.value;
70
+ this.prevTxId = inputData.prevTxId;
71
+ this.outpointIndex = inputData.outpointIndex;
72
+ this.addressType = inputData.addressType;
73
+ this.addressIndex = inputData.addressIndex;
74
+ this.signature = null;
75
+ this.sighash = null;
76
+ }
77
+ serialize() {
78
+ const valueBuf = Buffer.from(toBigEndianHex(this.value), "hex");
79
+ const addressTypeBuf = Buffer.alloc(1);
80
+ addressTypeBuf.writeUInt8(this.addressType);
81
+ const addressIndexBuf = Buffer.alloc(4);
82
+ addressIndexBuf.writeUInt32BE(this.addressIndex);
83
+ const outpointIndexBuf = Buffer.alloc(1);
84
+ outpointIndexBuf.writeUInt8(this.outpointIndex);
85
+ return Buffer.concat([
86
+ valueBuf,
87
+ Buffer.from(this.prevTxId, "hex"),
88
+ addressTypeBuf,
89
+ addressIndexBuf,
90
+ outpointIndexBuf,
91
+ ]);
92
+ }
93
+ /**
94
+ *
95
+ * @param {string} signature
96
+ */
97
+ setSignature(signature) {
98
+ this.signature = signature;
99
+ }
100
+ setSighash(sighash) {
101
+ this.sighash = sighash;
102
+ }
103
+ toApiJSON() {
104
+ return {
105
+ previousOutpoint: {
106
+ transactionId: this.prevTxId,
107
+ index: this.outpointIndex,
108
+ },
109
+ signatureScript: this.signature ? `41${this.signature}01` : null,
110
+ sequence: 0,
111
+ sigOpCount: 1,
112
+ };
113
+ }
114
+ }
115
+ export class TransactionOutput {
116
+ constructor(outputData) {
117
+ if (!outputData.value ||
118
+ outputData.value < 0 ||
119
+ outputData.value > Number.MAX_SAFE_INTEGER) {
120
+ throw new Error(`value must be set to a value greater than 0 and less than ${Number.MAX_SAFE_INTEGER.toString()}`);
121
+ }
122
+ this.value = outputData.value;
123
+ // Only then do we care about the script public key
124
+ this.scriptPublicKey = outputData.scriptPublicKey;
125
+ }
126
+ serialize() {
127
+ const valueBuf = Buffer.from(toBigEndianHex(this.value), "hex");
128
+ return Buffer.concat([valueBuf, Buffer.from(this.scriptPublicKey, "hex")]);
129
+ }
130
+ toApiJSON() {
131
+ return {
132
+ amount: this.value,
133
+ scriptPublicKey: {
134
+ version: 0,
135
+ scriptPublicKey: this.scriptPublicKey,
136
+ },
137
+ };
138
+ }
139
+ }
140
+ export function toBigEndianHex(numberToConvert) {
141
+ let baseStr = "0000000000000000";
142
+ baseStr += numberToConvert.toString(16);
143
+ return baseStr.substring(baseStr.length - 16, baseStr.length);
144
+ }
145
+ export default {
146
+ Transaction: KaspaHwTransaction,
147
+ TransactionInput,
148
+ TransactionOutput,
149
+ };
150
+ //# sourceMappingURL=kaspaHwTransaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kaspaHwTransaction.js","sourceRoot":"","sources":["../src/kaspaHwTransaction.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@ledgerhq/hw-app-kaspa",
3
+ "version": "1.3.0-nightly.0",
4
+ "description": "",
5
+ "main": "lib/index.js",
6
+ "module": "lib-es/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/coderofstuff/hw-app-kaspa.git"
11
+ },
12
+ "keywords": [
13
+ "Ledger"
14
+ ],
15
+ "author": "coderofstuff",
16
+ "license": "ISC",
17
+ "bugs": {
18
+ "url": "https://github.com/coderofstuff/hw-app-kaspa/issues"
19
+ },
20
+ "homepage": "https://github.com/coderofstuff/hw-app-kaspa#readme",
21
+ "dependencies": {
22
+ "bignumber.js": "^9.1.2",
23
+ "bip32-path": "^0.4.2",
24
+ "@ledgerhq/errors": "^6.25.0",
25
+ "@ledgerhq/hw-transport": "^6.31.10"
26
+ },
27
+ "devDependencies": {
28
+ "@ledgerhq/hw-transport-mocker": "^6.28.5",
29
+ "@ledgerhq/hw-transport-node-speculos": "^6.28.5",
30
+ "@types/jest": "^29.5.12",
31
+ "@types/node": "^20.11.30",
32
+ "jest": "^29.7.0",
33
+ "ts-jest": "^29.1.2",
34
+ "ts-node": "^10.9.2"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc && tsc -m ES6 --outDir lib-es",
38
+ "watch": "tsc --watch",
39
+ "test": "jest",
40
+ "lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx --cache",
41
+ "lint:fix": "pnpm lint --fix"
42
+ }
43
+ }
package/src/Kaspa.ts ADDED
@@ -0,0 +1,261 @@
1
+ import Transport from "@ledgerhq/hw-transport";
2
+ import { StatusCodes } from "@ledgerhq/errors";
3
+
4
+ import { publicKeyToAddress } from "./kaspa-util";
5
+ import { KaspaHwTransaction } from "./kaspaHwTransaction";
6
+
7
+ import BIP32Path from "bip32-path";
8
+
9
+ // Get Address
10
+ const P1_NON_CONFIRM = 0x00;
11
+ const P1_CONFIRM = 0x01;
12
+
13
+ // Sign Transaction
14
+ const P1_HEADER = 0x00;
15
+ const P1_OUTPUTS = 0x01;
16
+ const P1_INPUTS = 0x02;
17
+ const P1_NEXT_SIGNATURE = 0x03;
18
+
19
+ const P2_LAST = 0x00;
20
+ const P2_MORE = 0x80;
21
+
22
+ const LEDGER_CLA = 0xe0;
23
+
24
+ const INS = {
25
+ GET_VERSION: 0x04,
26
+ GET_ADDRESS: 0x05,
27
+ SIGN_TX: 0x06,
28
+ SIGN_MESSAGE: 0x07,
29
+ };
30
+
31
+ function pathToBuffer(originalPath) {
32
+ const pathNums = BIP32Path.fromString(originalPath).toPathArray();
33
+ return serializePath(pathNums);
34
+ }
35
+
36
+ function serializePath(path) {
37
+ const buf = Buffer.alloc(1 + path.length * 4);
38
+ buf.writeUInt8(path.length, 0);
39
+ for (const [i, num] of path.entries()) {
40
+ buf.writeUInt32BE(num, 1 + i * 4);
41
+ }
42
+ return buf;
43
+ }
44
+
45
+ export default class Kaspa {
46
+ transport: Transport;
47
+
48
+ constructor(transport: Transport) {
49
+ this.transport = transport;
50
+ this.transport.decorateAppAPIMethods(
51
+ this,
52
+ ["getVersion", "getAddress", "signTransaction", "signMessage"],
53
+ "kaspa",
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Get Kaspa address (public key) for a BIP32 path.
59
+ *
60
+ * @param {string} path a BIP32 path
61
+ * @param {boolean} display flag to show display
62
+ * @return an object with the address field
63
+ *
64
+ * @example
65
+ * kaspa.getAddress("44'/111111'/0'").then(r => r.address)
66
+ */
67
+ async getAddress(
68
+ path: string,
69
+ display: boolean = false,
70
+ ): Promise<{
71
+ publicKey: string;
72
+ address: string;
73
+ }> {
74
+ const pathBuffer = pathToBuffer(path);
75
+
76
+ const p1 = display ? P1_CONFIRM : P1_NON_CONFIRM;
77
+
78
+ const publicKeyBuffer: Buffer = await this.sendToDevice(
79
+ INS.GET_ADDRESS,
80
+ p1,
81
+ pathBuffer,
82
+ );
83
+
84
+ return {
85
+ publicKey: publicKeyBuffer.toString("hex"),
86
+ address: publicKeyToAddress(publicKeyBuffer.subarray(2, 34)),
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Sign a Kaspa transaction. Applies the signatures into the input objects
92
+ *
93
+ * @param {KaspaHwTransaction} transaction - the Transaction object
94
+ *
95
+ *
96
+ * @example
97
+ * kaspa.signTransaction(transaction)
98
+ */
99
+ async signTransaction(transaction: KaspaHwTransaction): Promise<void> {
100
+ const header = transaction.serialize();
101
+
102
+ await this.sendToDevice(INS.SIGN_TX, P1_HEADER, header, P2_MORE);
103
+
104
+ for (const output of transaction.outputs) {
105
+ await this.sendToDevice(
106
+ INS.SIGN_TX,
107
+ P1_OUTPUTS,
108
+ output.serialize(),
109
+ P2_MORE,
110
+ );
111
+ }
112
+
113
+ let signatureBuffer: Buffer | null = null;
114
+
115
+ for (let i = 0; i < transaction.inputs.length; i++) {
116
+ const p2 = i >= transaction.inputs.length - 1 ? P2_LAST : P2_MORE;
117
+ const input = transaction.inputs[i];
118
+ signatureBuffer = await this.sendToDevice(
119
+ INS.SIGN_TX,
120
+ P1_INPUTS,
121
+ input.serialize(),
122
+ p2,
123
+ );
124
+ }
125
+
126
+ while (signatureBuffer) {
127
+ const [hasMore, inputIndex, sigLen, ...signatureAndSighash] =
128
+ signatureBuffer;
129
+ const sigBuf = signatureAndSighash.slice(0, sigLen);
130
+ const sighashLen = signatureAndSighash[64];
131
+ const sighashBuf = signatureAndSighash.slice(65, 65 + sighashLen);
132
+
133
+ if (sigLen != 64) {
134
+ throw new Error(
135
+ `Expected signature length is 64. Received ${sigLen} for input ${inputIndex}`,
136
+ );
137
+ }
138
+
139
+ if (sighashLen != 32) {
140
+ throw new Error(
141
+ `Expected sighash length is 32. Received ${sighashLen} for input ${inputIndex}`,
142
+ );
143
+ }
144
+
145
+ transaction.inputs[inputIndex].setSignature(
146
+ Buffer.from(sigBuf).toString("hex"),
147
+ );
148
+ transaction.inputs[inputIndex].setSighash(
149
+ Buffer.from(sighashBuf).toString("hex"),
150
+ );
151
+
152
+ // Keep going as long as hasMore is true-ish
153
+ if (!hasMore) {
154
+ break;
155
+ }
156
+
157
+ signatureBuffer = await this.sendToDevice(INS.SIGN_TX, P1_NEXT_SIGNATURE);
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Sign personal message on the device
163
+ * @param {String} message - the personal message string to sign. Max 120 len for Nano S, 200 len for others
164
+ * @param {0|1} addressType
165
+ * @param {number} addressIndex
166
+ *
167
+ * @returns {Buffer} application config object
168
+ *
169
+ * @example
170
+ * kaspa.signMessage(message).then(r => r.version)
171
+ */
172
+ async signMessage(
173
+ message: string,
174
+ addressType?: 0 | 1,
175
+ addressIndex?: number,
176
+ account?: number,
177
+ ) {
178
+ account = account ?? 0x80000000;
179
+ addressIndex = addressIndex ?? 0;
180
+ addressType = addressType ?? 0;
181
+
182
+ if (account < 0x80000000 || account > 0xffffffff) {
183
+ throw new Error("Account must be between 0x80000000 and 0xFFFFFFFF");
184
+ }
185
+
186
+ if (addressIndex < 0 || addressIndex > 0xffffffff) {
187
+ throw new Error(
188
+ "Address index must be an integer in range [0, 0xFFFFFFFF]",
189
+ );
190
+ }
191
+
192
+ const addressTypeBuf = Buffer.alloc(1);
193
+ addressTypeBuf.writeUInt8(addressType || 0);
194
+
195
+ const addressIndexBuf = Buffer.alloc(4);
196
+ addressIndexBuf.writeUInt32BE(addressIndex || 0);
197
+
198
+ const accountBuf = Buffer.alloc(4);
199
+ accountBuf.writeUInt32BE(account);
200
+
201
+ const messageBuffer = Buffer.from(message);
202
+ const messageLenBuf = Buffer.alloc(1);
203
+ messageLenBuf.writeUInt8(messageBuffer.length);
204
+
205
+ const payload = Buffer.concat([
206
+ addressTypeBuf,
207
+ addressIndexBuf,
208
+ accountBuf,
209
+ messageLenBuf,
210
+ messageBuffer,
211
+ ]);
212
+
213
+ const signatureBuffer = await this.sendToDevice(
214
+ INS.SIGN_MESSAGE,
215
+ P1_NON_CONFIRM,
216
+ payload,
217
+ );
218
+ const [sigLen, ...signatureAndMessageHash] = signatureBuffer;
219
+ const signature = Buffer.from(
220
+ signatureAndMessageHash.slice(0, sigLen),
221
+ ).toString("hex");
222
+ const messageHashLen = signatureAndMessageHash[64];
223
+ const messageHash = Buffer.from(
224
+ signatureAndMessageHash.slice(65, 65 + messageHashLen),
225
+ ).toString("hex");
226
+
227
+ return { signature, messageHash };
228
+ }
229
+
230
+ /**
231
+ * Get application configuration.
232
+ *
233
+ * @returns {Buffer} application config object
234
+ *
235
+ * @example
236
+ * kaspa.getVersion().then(r => r.version)
237
+ */
238
+ async getVersion() {
239
+ const [major, minor, patch] = await this.sendToDevice(
240
+ INS.GET_VERSION,
241
+ P1_NON_CONFIRM,
242
+ );
243
+
244
+ return { version: `${major}.${minor}.${patch}` };
245
+ }
246
+
247
+ async sendToDevice(instruction, p1, payload = Buffer.alloc(0), p2 = P2_LAST) {
248
+ const acceptStatusList = [StatusCodes.OK];
249
+
250
+ const reply = await this.transport.send(
251
+ LEDGER_CLA,
252
+ instruction,
253
+ p1,
254
+ p2,
255
+ payload,
256
+ acceptStatusList,
257
+ );
258
+
259
+ return reply.subarray(0, reply.length - 2);
260
+ }
261
+ }