ecash-lib 4.5.2 → 4.7.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 (84) hide show
  1. package/README.md +40 -38
  2. package/dist/address/address.d.ts +6 -10
  3. package/dist/address/address.d.ts.map +1 -1
  4. package/dist/address/address.js +17 -19
  5. package/dist/address/address.js.map +1 -1
  6. package/dist/address/legacyaddr.d.ts +1 -1
  7. package/dist/address/legacyaddr.d.ts.map +1 -1
  8. package/dist/ecc.js +2 -2
  9. package/dist/ecc.js.map +1 -1
  10. package/dist/ffi/ecash_lib_wasm_bg_browser.js +22118 -2600
  11. package/dist/ffi/ecash_lib_wasm_bg_browser.wasm +0 -0
  12. package/dist/ffi/ecash_lib_wasm_bg_nodejs.wasm +0 -0
  13. package/dist/hash.js +7 -8
  14. package/dist/hash.js.map +1 -1
  15. package/dist/hdwallet.d.ts +32 -0
  16. package/dist/hdwallet.d.ts.map +1 -1
  17. package/dist/hdwallet.js +94 -0
  18. package/dist/hdwallet.js.map +1 -1
  19. package/dist/hmac.js +3 -3
  20. package/dist/hmac.js.map +1 -1
  21. package/dist/index.js +17 -7
  22. package/dist/index.js.map +1 -1
  23. package/dist/initBrowser.js +17 -7
  24. package/dist/initBrowser.js.map +1 -1
  25. package/dist/initNodeJs.js +17 -7
  26. package/dist/initNodeJs.js.map +1 -1
  27. package/dist/io/bytes.js +2 -2
  28. package/dist/io/bytes.js.map +1 -1
  29. package/dist/io/hex.js +4 -5
  30. package/dist/io/hex.js.map +1 -1
  31. package/dist/io/str.js +2 -3
  32. package/dist/io/str.js.map +1 -1
  33. package/dist/io/varsize.js +2 -3
  34. package/dist/io/varsize.js.map +1 -1
  35. package/dist/messages.d.ts.map +1 -1
  36. package/dist/messages.js.map +1 -1
  37. package/dist/mnemonic.js +3 -4
  38. package/dist/mnemonic.js.map +1 -1
  39. package/dist/op.js +5 -6
  40. package/dist/op.js.map +1 -1
  41. package/dist/parse/opreturn.js +4 -5
  42. package/dist/parse/opreturn.js.map +1 -1
  43. package/dist/payment/asn1.js +2 -3
  44. package/dist/payment/asn1.js.map +1 -1
  45. package/dist/payment/index.js +17 -7
  46. package/dist/payment/index.js.map +1 -1
  47. package/dist/pbkdf2.js +1 -2
  48. package/dist/pbkdf2.js.map +1 -1
  49. package/dist/publicKeyCrypto.js +2 -2
  50. package/dist/publicKeyCrypto.js.map +1 -1
  51. package/dist/sigHashType.js.map +1 -1
  52. package/dist/test/testRunner.d.ts +0 -1
  53. package/dist/test/testRunner.d.ts.map +1 -1
  54. package/dist/test/testRunner.js +17 -7
  55. package/dist/test/testRunner.js.map +1 -1
  56. package/dist/token/alp.d.ts +1 -1
  57. package/dist/token/alp.d.ts.map +1 -1
  58. package/dist/token/alp.js +5 -5
  59. package/dist/token/alp.js.map +1 -1
  60. package/dist/token/alp.parse.js +1 -2
  61. package/dist/token/alp.parse.js.map +1 -1
  62. package/dist/token/common.d.ts +4 -4
  63. package/dist/token/common.d.ts.map +1 -1
  64. package/dist/token/empp.js +2 -3
  65. package/dist/token/empp.js.map +1 -1
  66. package/dist/token/slp.d.ts +1 -1
  67. package/dist/token/slp.d.ts.map +1 -1
  68. package/dist/token/slp.js +7 -7
  69. package/dist/token/slp.js.map +1 -1
  70. package/dist/token/slp.parse.js +1 -2
  71. package/dist/token/slp.parse.js.map +1 -1
  72. package/dist/tx.js +7 -7
  73. package/dist/tx.js.map +1 -1
  74. package/dist/txBuilder.d.ts.map +1 -1
  75. package/dist/txBuilder.js +4 -4
  76. package/dist/txBuilder.js.map +1 -1
  77. package/package.json +5 -5
  78. package/src/address/address.ts +27 -19
  79. package/src/ffi/ecash_lib_wasm_bg_browser.js +22118 -2600
  80. package/src/ffi/ecash_lib_wasm_bg_browser.wasm +0 -0
  81. package/src/ffi/ecash_lib_wasm_bg_nodejs.wasm +0 -0
  82. package/src/hdwallet.ts +122 -1
  83. package/src/messages.ts +4 -4
  84. package/src/sigHashType.ts +2 -2
package/src/hdwallet.ts CHANGED
@@ -4,10 +4,17 @@
4
4
 
5
5
  import { Ecc } from './ecc.js';
6
6
  import { hmacSha512 } from './hmac.js';
7
- import { shaRmd160 } from './hash.js';
7
+ import { shaRmd160, sha256d } from './hash.js';
8
8
  import { Bytes } from './io/bytes.js';
9
9
  import { strToBytes } from './io/str.js';
10
10
  import { WriterBytes } from './io/writerbytes.js';
11
+ import { encodeBase58 } from 'b58-ts';
12
+ import { decodeBase58Check } from './address/legacyaddr.js';
13
+
14
+ // BIP32 extended public key version bytes
15
+ // These match the values defined in Electrum ABC's networks.py
16
+ const XPUB_VERSION_MAINNET = 0x0488b21e;
17
+ const XPUB_VERSION_TESTNET = 0x043587cf;
11
18
 
12
19
  const HIGHEST_BIT = 0x80000000;
13
20
 
@@ -69,6 +76,48 @@ export class HdNode {
69
76
  return this._chainCode;
70
77
  }
71
78
 
79
+ /**
80
+ * Encode this HdNode as an xpub (extended public key) string
81
+ *
82
+ * An xpub is a base58check-encoded string containing:
83
+ * - 4 bytes: version (0x0488B21E for mainnet xpub, 0x043587CF for testnet xpub)
84
+ * - 1 byte: depth
85
+ * - 4 bytes: parent fingerprint
86
+ * - 4 bytes: child index
87
+ * - 32 bytes: chain code (needed to derive child keys)
88
+ * - 33 bytes: public key (compressed)
89
+ *
90
+ * @param version - Version bytes (defaults to XPUB_VERSION_MAINNET)
91
+ * @returns Base58check-encoded xpub string
92
+ */
93
+ public xpub(version: number = XPUB_VERSION_MAINNET): string {
94
+ // Validate public key is compressed
95
+ if (
96
+ this._pubkey.length !== 33 ||
97
+ (this._pubkey[0] !== 0x02 && this._pubkey[0] !== 0x03)
98
+ ) {
99
+ throw new Error(
100
+ 'Public key must be compressed (33 bytes, starts with 0x02 or 0x03)',
101
+ );
102
+ }
103
+
104
+ // Write xpub data (78 bytes total)
105
+ const writer = new WriterBytes(78);
106
+ writer.putU32(version, 'BE');
107
+ writer.putU8(this._depth);
108
+ writer.putU32(this._parentFingerprint, 'BE');
109
+ writer.putU32(this._index, 'BE');
110
+ writer.putBytes(this._chainCode);
111
+ writer.putBytes(this._pubkey);
112
+
113
+ // Encode with base58check
114
+ const checksum = sha256d(writer.data);
115
+ const dataWithChecksum = new Uint8Array(78 + 4);
116
+ dataWithChecksum.set(writer.data, 0);
117
+ dataWithChecksum.set(checksum.subarray(0, 4), 78);
118
+ return encodeBase58(dataWithChecksum);
119
+ }
120
+
72
121
  public derive(index: number): HdNode {
73
122
  const isHardened = index >= HIGHEST_BIT;
74
123
  const data = new WriterBytes(1 + 32 + 4);
@@ -175,4 +224,76 @@ export class HdNode {
175
224
  const hashedRight = hashed.slice(32);
176
225
  return HdNode.fromPrivateKey(hashedLeft, hashedRight);
177
226
  }
227
+
228
+ /**
229
+ * Create an HdNode from an xpub (extended public key) string
230
+ *
231
+ * An xpub is a base58check-encoded string containing:
232
+ * - 4 bytes: version (0x0488B21E for mainnet xpub, 0x043587CF for testnet xpub)
233
+ * - 1 byte: depth
234
+ * - 4 bytes: parent fingerprint
235
+ * - 4 bytes: child index
236
+ * - 32 bytes: chain code
237
+ * - 33 bytes: public key (compressed)
238
+ *
239
+ * The resulting HdNode will not have a private key (watch-only).
240
+ *
241
+ * @param xpub - The extended public key string
242
+ * @returns HdNode created from the xpub (without private key)
243
+ */
244
+ public static fromXpub(xpub: string): HdNode {
245
+ const payload = decodeBase58Check(xpub);
246
+
247
+ if (payload.length !== 78) {
248
+ throw new Error(
249
+ `Invalid xpub: expected 78 bytes, got ${payload.length}`,
250
+ );
251
+ }
252
+
253
+ const bytes = new Bytes(payload);
254
+
255
+ // Read version (4 bytes, big-endian)
256
+ const version = bytes.readU32('BE');
257
+ // Validate version (mainnet or testnet xpub)
258
+ if (
259
+ version !== XPUB_VERSION_MAINNET &&
260
+ version !== XPUB_VERSION_TESTNET
261
+ ) {
262
+ throw new Error(
263
+ `Invalid xpub version: expected 0x${XPUB_VERSION_MAINNET.toString(16).toUpperCase()} (mainnet) or 0x${XPUB_VERSION_TESTNET.toString(16).toUpperCase()} (testnet), got 0x${version.toString(16)}`,
264
+ );
265
+ }
266
+
267
+ // Read depth (1 byte)
268
+ const depth = bytes.readU8();
269
+
270
+ // Read parent fingerprint (4 bytes, big-endian)
271
+ const parentFingerprint = bytes.readU32('BE');
272
+
273
+ // Read child index (4 bytes, big-endian)
274
+ const index = bytes.readU32('BE');
275
+
276
+ // Read chain code (32 bytes)
277
+ const chainCode = bytes.readBytes(32);
278
+
279
+ // Read public key (33 bytes, compressed)
280
+ const pubkey = bytes.readBytes(33);
281
+
282
+ // Validate public key format (should start with 0x02 or 0x03 for compressed)
283
+ if (pubkey[0] !== 0x02 && pubkey[0] !== 0x03) {
284
+ throw new Error(
285
+ `Invalid xpub: public key must be compressed (start with 0x02 or 0x03), got 0x${pubkey[0].toString(16)}`,
286
+ );
287
+ }
288
+
289
+ // Create HdNode without private key (watch-only)
290
+ return new HdNode({
291
+ seckey: undefined,
292
+ pubkey,
293
+ chainCode,
294
+ depth,
295
+ index,
296
+ parentFingerprint,
297
+ });
298
+ }
178
299
  }
package/src/messages.ts CHANGED
@@ -50,10 +50,10 @@ export const magicHash = (
50
50
  messageBytes.length <= 0xfc
51
51
  ? 1
52
52
  : messageBytes.length <= 0xffff
53
- ? 3
54
- : messageBytes.length <= 0xffffffff
55
- ? 5
56
- : 9;
53
+ ? 3
54
+ : messageBytes.length <= 0xffffffff
55
+ ? 5
56
+ : 9;
57
57
 
58
58
  // Create a WriterBytes instance with enough capacity
59
59
  const writer = new WriterBytes(
@@ -48,8 +48,8 @@ export class SigHashType {
48
48
  outputFlags == 1
49
49
  ? SigHashTypeOutputs.ALL
50
50
  : outputFlags == 2
51
- ? SigHashTypeOutputs.NONE
52
- : SigHashTypeOutputs.SINGLE,
51
+ ? SigHashTypeOutputs.NONE
52
+ : SigHashTypeOutputs.SINGLE,
53
53
  });
54
54
  }
55
55