quantumcoin 7.0.10 → 7.0.12

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 (171) hide show
  1. package/README-SDK.md +16 -5
  2. package/README.md +14 -3
  3. package/config.js +10 -2
  4. package/examples/example.js +0 -5
  5. package/examples/example.ts +0 -5
  6. package/examples/node_modules/.bin/esbuild +16 -0
  7. package/examples/node_modules/.bin/esbuild.cmd +17 -0
  8. package/examples/node_modules/.bin/esbuild.ps1 +28 -0
  9. package/examples/node_modules/.bin/sdkgen +16 -0
  10. package/examples/node_modules/.bin/sdkgen.cmd +17 -0
  11. package/examples/node_modules/.bin/sdkgen.ps1 +28 -0
  12. package/examples/node_modules/.bin/tsx +16 -0
  13. package/examples/node_modules/.bin/tsx.cmd +17 -0
  14. package/examples/node_modules/.bin/tsx.ps1 +28 -0
  15. package/examples/node_modules/.package-lock.json +144 -0
  16. package/examples/node_modules/@esbuild/win32-x64/README.md +3 -0
  17. package/examples/node_modules/@esbuild/win32-x64/esbuild.exe +0 -0
  18. package/examples/node_modules/@esbuild/win32-x64/package.json +20 -0
  19. package/examples/node_modules/esbuild/LICENSE.md +21 -0
  20. package/examples/node_modules/esbuild/README.md +3 -0
  21. package/examples/node_modules/esbuild/bin/esbuild +223 -0
  22. package/examples/node_modules/esbuild/install.js +289 -0
  23. package/examples/node_modules/esbuild/lib/main.d.ts +716 -0
  24. package/examples/node_modules/esbuild/lib/main.js +2532 -0
  25. package/examples/node_modules/esbuild/package.json +49 -0
  26. package/examples/node_modules/get-tsconfig/LICENSE +21 -0
  27. package/examples/node_modules/get-tsconfig/README.md +235 -0
  28. package/examples/node_modules/get-tsconfig/dist/index.cjs +7 -0
  29. package/examples/node_modules/get-tsconfig/dist/index.d.cts +2088 -0
  30. package/examples/node_modules/get-tsconfig/dist/index.d.mts +2088 -0
  31. package/examples/node_modules/get-tsconfig/dist/index.mjs +7 -0
  32. package/examples/node_modules/get-tsconfig/package.json +46 -0
  33. package/examples/node_modules/quantum-coin-js-sdk/LICENSE +21 -0
  34. package/examples/node_modules/quantum-coin-js-sdk/LICENSE-wasm_exec.js.txt +30 -0
  35. package/examples/node_modules/quantum-coin-js-sdk/README.md +1675 -0
  36. package/examples/node_modules/quantum-coin-js-sdk/example/README.md +14 -0
  37. package/examples/node_modules/quantum-coin-js-sdk/example/conversion-example.js +19 -0
  38. package/examples/node_modules/quantum-coin-js-sdk/example/example-create-contract.js +396 -0
  39. package/examples/node_modules/quantum-coin-js-sdk/example/example-encode-decode-rlp.js +225 -0
  40. package/examples/node_modules/quantum-coin-js-sdk/example/example-event-pack-unpack.js +391 -0
  41. package/examples/node_modules/quantum-coin-js-sdk/example/example-misc.js +101 -0
  42. package/examples/node_modules/quantum-coin-js-sdk/example/example-rpc-send-signRawTransaction.js +318 -0
  43. package/examples/node_modules/quantum-coin-js-sdk/example/example-rpc-send.js +116 -0
  44. package/examples/node_modules/quantum-coin-js-sdk/example/example-send.js +70 -0
  45. package/examples/node_modules/quantum-coin-js-sdk/example/example-token-pack-unpack.js +961 -0
  46. package/examples/node_modules/quantum-coin-js-sdk/example/example-wallet-version4.js +35 -0
  47. package/examples/node_modules/quantum-coin-js-sdk/example/example-wallet.js +43 -0
  48. package/examples/node_modules/quantum-coin-js-sdk/example/example.js +405 -0
  49. package/examples/node_modules/quantum-coin-js-sdk/example/package-lock.json +134 -0
  50. package/examples/node_modules/quantum-coin-js-sdk/example/package.json +15 -0
  51. package/examples/node_modules/quantum-coin-js-sdk/index.d.ts +1031 -0
  52. package/examples/node_modules/quantum-coin-js-sdk/index.js +3144 -0
  53. package/examples/node_modules/quantum-coin-js-sdk/package.json +34 -0
  54. package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-32.json +1 -0
  55. package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-36.json +1 -0
  56. package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-48.json +1 -0
  57. package/examples/node_modules/quantum-coin-js-sdk/tests/generate-verify-vectors.js +91 -0
  58. package/examples/node_modules/quantum-coin-js-sdk/tests/non-transactional.preinit.test.js +41 -0
  59. package/examples/node_modules/quantum-coin-js-sdk/tests/non-transactional.test.js +1389 -0
  60. package/examples/node_modules/quantum-coin-js-sdk/tests/sign-raw-keytype5-context-null.test.js +107 -0
  61. package/examples/node_modules/quantum-coin-js-sdk/tests/sign-raw-transaction.test.js +196 -0
  62. package/examples/node_modules/quantum-coin-js-sdk/tests/sign-verify.test.js +311 -0
  63. package/examples/node_modules/quantum-coin-js-sdk/tests/transactional.relay.test.js +131 -0
  64. package/examples/node_modules/quantum-coin-js-sdk/tests/transactional.rpc.test.js +103 -0
  65. package/examples/node_modules/quantum-coin-js-sdk/tests/verify-vectors.json +95035 -0
  66. package/examples/node_modules/quantum-coin-js-sdk/wasmBase64.d.ts +9 -0
  67. package/examples/node_modules/quantum-coin-js-sdk/wasmBase64.js +16 -0
  68. package/examples/node_modules/quantum-coin-js-sdk/wasm_exec.d.ts +0 -0
  69. package/examples/node_modules/quantum-coin-js-sdk/wasm_exec.js +587 -0
  70. package/examples/node_modules/resolve-pkg-maps/LICENSE +21 -0
  71. package/examples/node_modules/resolve-pkg-maps/README.md +216 -0
  72. package/examples/node_modules/resolve-pkg-maps/dist/index.cjs +1 -0
  73. package/examples/node_modules/resolve-pkg-maps/dist/index.d.cts +11 -0
  74. package/examples/node_modules/resolve-pkg-maps/dist/index.d.mts +11 -0
  75. package/examples/node_modules/resolve-pkg-maps/dist/index.mjs +1 -0
  76. package/examples/node_modules/resolve-pkg-maps/package.json +42 -0
  77. package/examples/node_modules/seed-words/.github/workflows/publish-npmjs.yaml +22 -0
  78. package/examples/node_modules/seed-words/BUILD.md +7 -0
  79. package/examples/node_modules/seed-words/LICENSE +121 -0
  80. package/examples/node_modules/seed-words/README.md +67 -0
  81. package/examples/node_modules/seed-words/dist/seedwords.d.ts +39 -0
  82. package/examples/node_modules/seed-words/package.json +27 -0
  83. package/examples/node_modules/seed-words/seedwords.js +315 -0
  84. package/examples/node_modules/seed-words/seedwords.txt +65536 -0
  85. package/examples/node_modules/seed-words/tsconfig.json +21 -0
  86. package/examples/node_modules/tsx/LICENSE +21 -0
  87. package/examples/node_modules/tsx/README.md +32 -0
  88. package/examples/node_modules/tsx/dist/cjs/api/index.cjs +1 -0
  89. package/examples/node_modules/tsx/dist/cjs/api/index.d.cts +35 -0
  90. package/examples/node_modules/tsx/dist/cjs/api/index.d.mts +35 -0
  91. package/examples/node_modules/tsx/dist/cjs/api/index.mjs +1 -0
  92. package/examples/node_modules/tsx/dist/cjs/index.cjs +1 -0
  93. package/examples/node_modules/tsx/dist/cjs/index.mjs +1 -0
  94. package/examples/node_modules/tsx/dist/cli.cjs +54 -0
  95. package/examples/node_modules/tsx/dist/cli.mjs +55 -0
  96. package/examples/node_modules/tsx/dist/client-BQVF1NaW.mjs +1 -0
  97. package/examples/node_modules/tsx/dist/client-D6NvIMSC.cjs +1 -0
  98. package/examples/node_modules/tsx/dist/esm/api/index.cjs +1 -0
  99. package/examples/node_modules/tsx/dist/esm/api/index.d.cts +35 -0
  100. package/examples/node_modules/tsx/dist/esm/api/index.d.mts +35 -0
  101. package/examples/node_modules/tsx/dist/esm/api/index.mjs +1 -0
  102. package/examples/node_modules/tsx/dist/esm/index.cjs +2 -0
  103. package/examples/node_modules/tsx/dist/esm/index.mjs +2 -0
  104. package/examples/node_modules/tsx/dist/get-pipe-path-BHW2eJdv.mjs +1 -0
  105. package/examples/node_modules/tsx/dist/get-pipe-path-BoR10qr8.cjs +1 -0
  106. package/examples/node_modules/tsx/dist/index-7AaEi15b.mjs +14 -0
  107. package/examples/node_modules/tsx/dist/index-BWFBUo6r.cjs +1 -0
  108. package/examples/node_modules/tsx/dist/index-gbaejti9.mjs +1 -0
  109. package/examples/node_modules/tsx/dist/index-gckBtVBf.cjs +14 -0
  110. package/examples/node_modules/tsx/dist/lexer-DQCqS3nf.mjs +3 -0
  111. package/examples/node_modules/tsx/dist/lexer-DgIbo0BU.cjs +3 -0
  112. package/examples/node_modules/tsx/dist/loader.cjs +1 -0
  113. package/examples/node_modules/tsx/dist/loader.mjs +1 -0
  114. package/examples/node_modules/tsx/dist/node-features-_8ZFwP_x.mjs +1 -0
  115. package/examples/node_modules/tsx/dist/node-features-roYmp9jK.cjs +1 -0
  116. package/examples/node_modules/tsx/dist/package-CeBgXWuR.mjs +1 -0
  117. package/examples/node_modules/tsx/dist/package-Dxt5kIHw.cjs +1 -0
  118. package/examples/node_modules/tsx/dist/patch-repl.cjs +1 -0
  119. package/examples/node_modules/tsx/dist/patch-repl.mjs +1 -0
  120. package/examples/node_modules/tsx/dist/preflight.cjs +1 -0
  121. package/examples/node_modules/tsx/dist/preflight.mjs +1 -0
  122. package/examples/node_modules/tsx/dist/register-2sWVXuRQ.cjs +1 -0
  123. package/examples/node_modules/tsx/dist/register-B7jrtLTO.mjs +1 -0
  124. package/examples/node_modules/tsx/dist/register-CFH5oNdT.mjs +4 -0
  125. package/examples/node_modules/tsx/dist/register-D46fvsV_.cjs +4 -0
  126. package/examples/node_modules/tsx/dist/repl.cjs +3 -0
  127. package/examples/node_modules/tsx/dist/repl.mjs +3 -0
  128. package/examples/node_modules/tsx/dist/require-D4F1Lv60.cjs +1 -0
  129. package/examples/node_modules/tsx/dist/require-DQxpCAr4.mjs +1 -0
  130. package/examples/node_modules/tsx/dist/suppress-warnings.cjs +1 -0
  131. package/examples/node_modules/tsx/dist/suppress-warnings.mjs +1 -0
  132. package/examples/node_modules/tsx/dist/temporary-directory-B83uKxJF.cjs +1 -0
  133. package/examples/node_modules/tsx/dist/temporary-directory-CwHp0_NW.mjs +1 -0
  134. package/examples/node_modules/tsx/dist/types-Cxp8y2TL.d.ts +5 -0
  135. package/examples/node_modules/tsx/package.json +68 -0
  136. package/examples/offline-signing.js +0 -2
  137. package/examples/offline-signing.ts +0 -1
  138. package/examples/package-lock.json +422 -73
  139. package/examples/package.json +1 -1
  140. package/examples/wallet-offline.js +1 -9
  141. package/examples/wallet-offline.ts +1 -9
  142. package/generate-sdk.js +5 -7
  143. package/package.json +2 -2
  144. package/src/abi/interface.js +13 -7
  145. package/src/abi/js-abi-coder.js +23 -18
  146. package/src/constants.d.ts +0 -5
  147. package/src/constants.js +0 -7
  148. package/src/contract/contract-factory.js +9 -3
  149. package/src/contract/contract.js +9 -3
  150. package/src/errors/index.js +12 -0
  151. package/src/index.d.ts +0 -3
  152. package/src/providers/extra-providers.js +20 -6
  153. package/src/providers/json-rpc-provider.js +15 -5
  154. package/src/providers/provider.d.ts +0 -2
  155. package/src/providers/provider.js +1 -3
  156. package/src/utils/address.d.ts +0 -14
  157. package/src/utils/address.js +12 -49
  158. package/src/utils/hashing.d.ts +0 -6
  159. package/src/utils/hashing.js +8 -23
  160. package/src/utils/index.d.ts +0 -3
  161. package/src/utils/rlp.js +7 -4
  162. package/src/wallet/wallet.d.ts +7 -13
  163. package/src/wallet/wallet.js +136 -97
  164. package/test/security/malformed-input.test.js +295 -1
  165. package/test/unit/address-wallet.test.js +329 -129
  166. package/test/unit/address-wallet.test.ts +328 -128
  167. package/test/unit/hashing.test.js +0 -11
  168. package/test/unit/hashing.test.ts +0 -11
  169. package/test/unit/providers.test.js +3 -1
  170. package/test/unit/providers.test.ts +3 -1
  171. package/SPEC.md +0 -3845
@@ -8,18 +8,22 @@
8
8
  const qcsdk = require("quantum-coin-js-sdk");
9
9
  const { assertArgument, makeError } = require("../errors");
10
10
  const { arrayify, bytesToHex, hexToBytes, isHexString, normalizeHex } = require("../internal/hex");
11
- const { hashMessage } = require("./hashing");
11
+
12
12
 
13
13
  function _requireInitialized() {
14
- // The spec requires Initialize() to be called before using the SDK.
15
- // config.js tracks initialization state for this package.
16
14
  // eslint-disable-next-line global-require
17
- const { isInitialized } = require("../../config");
18
- if (!isInitialized()) {
19
- throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", {
20
- operation: "address-utils",
21
- });
15
+ const { isInitialized, getInitializationPromise } = require("../../config");
16
+ if (isInitialized()) return;
17
+ if (getInitializationPromise() != null) {
18
+ throw makeError(
19
+ "QuantumCoin SDK is still initializing. Await the Initialize() promise before using SDK methods.",
20
+ "UNKNOWN_ERROR",
21
+ { operation: "requireInitialized" },
22
+ );
22
23
  }
24
+ throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", {
25
+ operation: "address-utils",
26
+ });
23
27
  }
24
28
 
25
29
  /**
@@ -127,45 +131,6 @@ function computeAddress(key) {
127
131
  return normalizeHex(out);
128
132
  }
129
133
 
130
- function _digestMessage(message) {
131
- const digestHex = hashMessage(message);
132
- const digest = Array.from(hexToBytes(digestHex));
133
- assertArgument(digest.length === 32, "invalid digest length", "digest", digest.length);
134
- return digest;
135
- }
136
-
137
- function _signatureToBytes(signature) {
138
- assertArgument(typeof signature === "string", "signature must be a hex string", "signature", signature);
139
- assertArgument(isHexString(signature), "invalid signature hex", "signature", signature);
140
- return Array.from(hexToBytes(signature));
141
- }
142
-
143
- /**
144
- * Verifies a message signature and recovers the address.
145
- * @param {string|Uint8Array} message
146
- * @param {string} signature Hex string signature
147
- * @returns {string}
148
- */
149
- function verifyMessage(message, signature) {
150
- return recoverAddress(message, signature);
151
- }
152
-
153
- /**
154
- * Recovers the address from a message signature.
155
- * @param {string|Uint8Array} message
156
- * @param {string} signature Hex string signature
157
- * @returns {string}
158
- */
159
- function recoverAddress(message, signature) {
160
- _requireInitialized();
161
- const digest = _digestMessage(message);
162
- const sigBytes = _signatureToBytes(signature);
163
- const pubHex = qcsdk.publicKeyFromSignature(digest, sigBytes);
164
- if (typeof pubHex !== "string") throw makeError("publicKeyFromSignature failed", "UNKNOWN_ERROR", {});
165
- const addr = computeAddress(pubHex);
166
- return addr;
167
- }
168
-
169
134
  module.exports = {
170
135
  isAddress,
171
136
  getAddress,
@@ -175,7 +140,5 @@ module.exports = {
175
140
  getCreateAddress,
176
141
  getCreate2Address,
177
142
  computeAddress,
178
- verifyMessage,
179
- recoverAddress,
180
143
  };
181
144
 
@@ -4,12 +4,6 @@
4
4
  * @returns {string}
5
5
  */
6
6
  export function keccak256(data: string | Uint8Array): string;
7
- /**
8
- * EIP-191 personal-sign message digest (ethers.js hashMessage pattern).
9
- * @param {string|Uint8Array} message
10
- * @returns {string}
11
- */
12
- export function hashMessage(message: string | Uint8Array): string;
13
7
  /**
14
8
  * sha256 hash of BytesLike.
15
9
  * @param {string|Uint8Array} data
@@ -7,9 +7,7 @@
7
7
  */
8
8
 
9
9
  const crypto = require("crypto");
10
- const { MessagePrefix } = require("../constants");
11
10
  const { arrayify, bytesToHex, utf8ToBytes } = require("../internal/hex");
12
- const { concat } = require("./encoding");
13
11
 
14
12
  const _MASK64 = (1n << 64n) - 1n;
15
13
 
@@ -192,18 +190,6 @@ function ripemd160(data) {
192
190
  return _hash("ripemd160", data);
193
191
  }
194
192
 
195
- /**
196
- * EIP-191 personal-sign message digest (ethers.js hashMessage pattern).
197
- * Prefixes message with MessagePrefix and decimal length, then keccak256.
198
- * If message is a string, it is converted to UTF-8 bytes first.
199
- * @param {string|Uint8Array} message
200
- * @returns {string} Hex digest
201
- */
202
- function hashMessage(message) {
203
- const msgBytes = typeof message === "string" ? utf8ToBytes(message) : arrayify(message);
204
- return keccak256(concat([utf8ToBytes(MessagePrefix), utf8ToBytes(String(msgBytes.length)), msgBytes]));
205
- }
206
-
207
193
  /**
208
194
  * ethers-style id(text) => keccak256(utf8Bytes(text))
209
195
  * @param {string} text
@@ -230,8 +216,8 @@ function randomBytes(length) {
230
216
  * @returns {string}
231
217
  */
232
218
  function computeHmac(algorithm, key, data) {
233
- const k = arrayify(key);
234
- const d = arrayify(data);
219
+ const k = typeof key === "string" ? utf8ToBytes(key) : arrayify(key);
220
+ const d = typeof data === "string" ? utf8ToBytes(data) : arrayify(data);
235
221
  const h = crypto.createHmac(algorithm, Buffer.from(k)).update(Buffer.from(d)).digest();
236
222
  return bytesToHex(new Uint8Array(h));
237
223
  }
@@ -246,8 +232,8 @@ function computeHmac(algorithm, key, data) {
246
232
  * @returns {string}
247
233
  */
248
234
  function pbkdf2(password, salt, iterations, keylen, algorithm) {
249
- const p = arrayify(password);
250
- const s = arrayify(salt);
235
+ const p = typeof password === "string" ? utf8ToBytes(password) : arrayify(password);
236
+ const s = typeof salt === "string" ? utf8ToBytes(salt) : arrayify(salt);
251
237
  const a = algorithm || "sha256";
252
238
  const out = crypto.pbkdf2Sync(Buffer.from(p), Buffer.from(s), iterations, keylen, a);
253
239
  return bytesToHex(new Uint8Array(out));
@@ -264,8 +250,8 @@ function pbkdf2(password, salt, iterations, keylen, algorithm) {
264
250
  * @returns {Promise<string>}
265
251
  */
266
252
  function scrypt(password, salt, N, r, p, dkLen) {
267
- const pw = arrayify(password);
268
- const sa = arrayify(salt);
253
+ const pw = typeof password === "string" ? utf8ToBytes(password) : arrayify(password);
254
+ const sa = typeof salt === "string" ? utf8ToBytes(salt) : arrayify(salt);
269
255
  return new Promise((resolve, reject) => {
270
256
  crypto.scrypt(
271
257
  Buffer.from(pw),
@@ -291,15 +277,14 @@ function scrypt(password, salt, N, r, p, dkLen) {
291
277
  * @returns {string}
292
278
  */
293
279
  function scryptSync(password, salt, N, r, p, dkLen) {
294
- const pw = arrayify(password);
295
- const sa = arrayify(salt);
280
+ const pw = typeof password === "string" ? utf8ToBytes(password) : arrayify(password);
281
+ const sa = typeof salt === "string" ? utf8ToBytes(salt) : arrayify(salt);
296
282
  const out = crypto.scryptSync(Buffer.from(pw), Buffer.from(sa), dkLen, { N, r, p, maxmem: 257 * 1024 * 1024 }); //257 instead of 256 for buffer for compat for N=262144, r=8, p=1
297
283
  return bytesToHex(new Uint8Array(out));
298
284
  }
299
285
 
300
286
  module.exports = {
301
287
  keccak256,
302
- hashMessage,
303
288
  sha256,
304
289
  sha512,
305
290
  ripemd160,
@@ -12,7 +12,6 @@ declare const _exports: {
12
12
  encodeRlp(value: any): string;
13
13
  decodeRlp(data: string): any;
14
14
  keccak256(data: string | Uint8Array): string;
15
- hashMessage(message: string | Uint8Array): string;
16
15
  sha256(data: string | Uint8Array): string;
17
16
  sha512(data: string | Uint8Array): string;
18
17
  ripemd160(data: string | Uint8Array): string;
@@ -59,8 +58,6 @@ declare const _exports: {
59
58
  }): string;
60
59
  getCreate2Address(from: string, salt: string, initCodeHash: string): string;
61
60
  computeAddress(key: string | Uint8Array): string;
62
- verifyMessage(message: string | Uint8Array, signature: string): string;
63
- recoverAddress(message: string | Uint8Array, signature: string): string;
64
61
  FixedNumber: typeof import("./fixednumber").FixedNumber;
65
62
  };
66
63
  export = _exports;
package/src/utils/rlp.js CHANGED
@@ -110,7 +110,10 @@ function _readLen(bytes, offset, lenOfLen) {
110
110
  return len;
111
111
  }
112
112
 
113
- function _decode(bytes, start, end) {
113
+ const MAX_RLP_DEPTH = 64;
114
+
115
+ function _decode(bytes, start, end, depth) {
116
+ if (depth > MAX_RLP_DEPTH) throw new Error("RLP: maximum nesting depth exceeded");
114
117
  if (start >= end) throw new Error("RLP: empty input");
115
118
  const prefix = bytes[start];
116
119
 
@@ -149,7 +152,7 @@ function _decode(bytes, start, end) {
149
152
  const out = [];
150
153
  let pos = dataStart;
151
154
  while (pos < dataEnd) {
152
- const decoded = _decode(bytes, pos, dataEnd);
155
+ const decoded = _decode(bytes, pos, dataEnd, depth + 1);
153
156
  out.push(decoded.value);
154
157
  pos = decoded.next;
155
158
  }
@@ -166,7 +169,7 @@ function _decode(bytes, start, end) {
166
169
  const out = [];
167
170
  let pos = dataStart;
168
171
  while (pos < dataEnd) {
169
- const decoded = _decode(bytes, pos, dataEnd);
172
+ const decoded = _decode(bytes, pos, dataEnd, depth + 1);
170
173
  out.push(decoded.value);
171
174
  pos = decoded.next;
172
175
  }
@@ -191,7 +194,7 @@ function encodeRlp(value) {
191
194
  function decodeRlp(data) {
192
195
  if (typeof data !== "string") throw new TypeError("RLP data must be a hex string");
193
196
  const bytes = arrayify(data);
194
- const decoded = _decode(bytes, 0, bytes.length);
197
+ const decoded = _decode(bytes, 0, bytes.length, 0);
195
198
  if (decoded.next !== bytes.length) throw new Error("RLP: trailing data");
196
199
  return decoded.value;
197
200
  }
@@ -38,14 +38,9 @@ export class BaseWallet extends AbstractSigner {
38
38
  _qcWallet: any;
39
39
  /** @type {string} */
40
40
  address: string;
41
+ readonly publicKey: string;
42
+ readonly seed: string | null;
41
43
  getAddress(): Promise<string>;
42
- /**
43
- * Sign a message synchronously.
44
- * Signature format: combined publicKey+signature as a hex string.
45
- * @param {string|Uint8Array} message
46
- * @returns {string}
47
- */
48
- signMessageSync(message: string | Uint8Array): string;
49
44
  /**
50
45
  * Sign a transaction using quantum-coin-js-sdk signRawTransaction().
51
46
  * @param {import("../providers/provider").TransactionRequest} tx
@@ -63,6 +58,11 @@ export class BaseWallet extends AbstractSigner {
63
58
  * Wallet - convenience methods around BaseWallet.
64
59
  */
65
60
  export class Wallet extends BaseWallet {
61
+ /**
62
+ * Returns the seed phrase (list of words) if this wallet has a seed, else null.
63
+ * Derived from the stored pre-expansion seed via seed-words.getWordListFromSeedArray.
64
+ */
65
+ getPhrase(): string[] | null;
66
66
  /**
67
67
  * Returns the recommended signing context for this wallet.
68
68
  * Setting fullSign to true may incur additional gas cost.
@@ -77,12 +77,6 @@ export class Wallet extends BaseWallet {
77
77
  * @returns {Wallet}
78
78
  */
79
79
  static createRandom(provider?: import("../providers/provider").AbstractProvider | undefined, keyType?: number | null): Wallet;
80
- /**
81
- * Creates a new random seed word list (32 words for keyType 3, 36 for keyType 5).
82
- * @param {number|null=} keyType Optional key type: null (default=3), 3, or 5
83
- * @returns {string[]}
84
- */
85
- static createRandomSeed(keyType?: number | null): string[];
86
80
  /**
87
81
  * Creates a wallet from raw seed bytes.
88
82
  * @param {number[]} seed Raw seed bytes: 64 (keyType 3), 72 (keyType 5), or 96 (legacy)
@@ -9,25 +9,54 @@
9
9
  */
10
10
 
11
11
  const qcsdk = require("quantum-coin-js-sdk");
12
+ const seedWords = require("seed-words");
12
13
  const { JsonRpcProvider } = require("../providers/json-rpc-provider");
13
- const { assertArgument, makeError } = require("../errors");
14
+ const { assertArgument, assertSecretArgument, makeError } = require("../errors");
14
15
  const { arrayify, bytesToHex, hexToBytes, isHexString, normalizeHex } = require("../internal/hex");
15
- const { hashMessage } = require("../utils/hashing");
16
16
  const { getAddress } = require("../utils/address");
17
17
  const { WeiPerEther } = require("../constants");
18
18
 
19
19
  function _requireInitialized() {
20
20
  // eslint-disable-next-line global-require
21
- const { isInitialized } = require("../../config");
22
- if (!isInitialized()) {
23
- throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", { operation: "wallet" });
21
+ const { isInitialized, getInitializationPromise } = require("../../config");
22
+ if (isInitialized()) return;
23
+ if (getInitializationPromise() != null) {
24
+ throw makeError(
25
+ "QuantumCoin SDK is still initializing. Await the Initialize() promise before using SDK methods.",
26
+ "UNKNOWN_ERROR",
27
+ { operation: "requireInitialized" },
28
+ );
24
29
  }
30
+ throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", { operation: "wallet" });
25
31
  }
26
32
 
27
33
  function _bytesToNumberArray(bytes) {
28
34
  return Array.from(bytes);
29
35
  }
30
36
 
37
+ const _maxSafeInt = 0x1fffffffffffffn; // 2^53 - 1
38
+
39
+ function _getBigInt(value, name) {
40
+ if (typeof value === "bigint") return value;
41
+ if (typeof value === "number") {
42
+ assertArgument(Number.isInteger(value), "underflow", name, value);
43
+ assertArgument(value >= -Number(_maxSafeInt) && value <= Number(_maxSafeInt), "overflow", name, value);
44
+ return BigInt(value);
45
+ }
46
+ if (typeof value === "string") {
47
+ if (value === "0x" || value === "0X") return 0n;
48
+ try { return BigInt(value); }
49
+ catch { assertArgument(false, "invalid BigNumberish string", name, value); }
50
+ }
51
+ assertArgument(false, "invalid BigNumberish", name, value);
52
+ }
53
+
54
+ function _getNumber(value, name) {
55
+ const bi = _getBigInt(value, name);
56
+ assertArgument(bi >= -_maxSafeInt && bi <= _maxSafeInt, "overflow", name, value);
57
+ return Number(bi);
58
+ }
59
+
31
60
  /**
32
61
  * SigningKey wrapper (PQC private/public key bytes).
33
62
  */
@@ -37,9 +66,18 @@ class SigningKey {
37
66
  * @param {Uint8Array} publicKeyBytes
38
67
  */
39
68
  constructor(privateKeyBytes, publicKeyBytes) {
40
- this.privateKeyBytes = new Uint8Array(privateKeyBytes);
69
+ Object.defineProperty(this, "privateKeyBytes", {
70
+ enumerable: false,
71
+ configurable: false,
72
+ writable: false,
73
+ value: new Uint8Array(privateKeyBytes),
74
+ });
41
75
  this.publicKeyBytes = new Uint8Array(publicKeyBytes);
42
76
  }
77
+
78
+ toJSON() {
79
+ return {};
80
+ }
43
81
  }
44
82
 
45
83
  /**
@@ -71,56 +109,52 @@ class BaseWallet extends AbstractSigner {
71
109
  constructor(signingKey, provider, precomputed, qcWallet) {
72
110
  super(provider || null);
73
111
  _requireInitialized();
74
- this.signingKey = signingKey;
75
- this._qcWallet = qcWallet || null;
112
+
113
+ Object.defineProperty(this, "signingKey", {
114
+ enumerable: false,
115
+ configurable: false,
116
+ writable: false,
117
+ value: signingKey,
118
+ });
119
+ Object.defineProperty(this, "_qcWallet", {
120
+ enumerable: false,
121
+ configurable: true,
122
+ writable: true,
123
+ value: qcWallet || null,
124
+ });
76
125
 
77
126
  /** @type {string} */
78
127
  this.address = precomputed?.address || "";
79
128
 
80
129
  Object.defineProperty(this, "privateKey", {
81
- enumerable: true,
130
+ enumerable: false,
82
131
  get: () => bytesToHex(this.signingKey.privateKeyBytes),
83
132
  });
133
+
134
+ Object.defineProperty(this, "publicKey", {
135
+ enumerable: true,
136
+ get: () => bytesToHex(this.signingKey.publicKeyBytes),
137
+ });
138
+
139
+ Object.defineProperty(this, "_seed", {
140
+ enumerable: false,
141
+ configurable: true,
142
+ writable: true,
143
+ value: null,
144
+ });
145
+
146
+ Object.defineProperty(this, "seed", {
147
+ enumerable: false,
148
+ get: () => this._seed,
149
+ });
84
150
  }
85
151
 
86
- async getAddress() {
87
- return this.address;
152
+ toJSON() {
153
+ return { address: this.address };
88
154
  }
89
155
 
90
- /**
91
- * Sign a message synchronously.
92
- * Signature format: combined publicKey+signature as a hex string.
93
- * @param {string|Uint8Array} message
94
- * @returns {string}
95
- */
96
- signMessageSync(message) {
97
- _requireInitialized();
98
- const digestHex = hashMessage(message);
99
- const digest = hexToBytes(digestHex);
100
- const signResult = qcsdk.sign(this.signingKey.privateKeyBytes, digest, null);
101
- if (signResult.resultCode !== 0) {
102
- throw makeError("sign failed", "UNKNOWN_ERROR", { resultCode: signResult.resultCode });
103
- }
104
- const sigBytes = signResult.signature;
105
- if (!sigBytes) throw makeError("sign returned no signature", "UNKNOWN_ERROR", {});
106
- const sigArr = Array.from(sigBytes instanceof Uint8Array ? sigBytes : sigBytes);
107
- let combined = qcsdk.combinePublicKeySignature(
108
- _bytesToNumberArray(this.signingKey.publicKeyBytes),
109
- sigArr,
110
- );
111
- if (combined != null && typeof combined === "object") {
112
- if (typeof combined.String === "function") combined = combined.String();
113
- else if (combined instanceof Uint8Array) combined = bytesToHex(combined);
114
- else if (Array.isArray(combined)) combined = bytesToHex(new Uint8Array(combined));
115
- else if (typeof combined.length === "number" && combined.length >= 0) combined = bytesToHex(new Uint8Array(Array.from(combined)));
116
- }
117
- if (combined == null || typeof combined !== "string") {
118
- throw makeError("combinePublicKeySignature failed (SDK may not support this key type for message signing)", "UNKNOWN_ERROR", {
119
- combinedType: typeof combined,
120
- sigLength: sigArr.length,
121
- });
122
- }
123
- return normalizeHex(combined);
156
+ async getAddress() {
157
+ return this.address;
124
158
  }
125
159
 
126
160
  /**
@@ -133,27 +167,8 @@ class BaseWallet extends AbstractSigner {
133
167
  assertArgument(tx && typeof tx === "object", "invalid tx", "tx", tx);
134
168
 
135
169
  const toAddress = tx.to == null ? null : getAddress(tx.to);
136
- const valueInWei =
137
- tx.value == null
138
- ? 0n
139
- : typeof tx.value === "bigint"
140
- ? tx.value
141
- : typeof tx.value === "number"
142
- ? BigInt(tx.value)
143
- : typeof tx.value === "string"
144
- ? BigInt(tx.value.startsWith("0x") ? tx.value : tx.value)
145
- : 0n;
146
-
147
- const gasLimit =
148
- tx.gasLimit == null
149
- ? 21000
150
- : typeof tx.gasLimit === "bigint"
151
- ? Number(tx.gasLimit)
152
- : typeof tx.gasLimit === "number"
153
- ? tx.gasLimit
154
- : typeof tx.gasLimit === "string"
155
- ? Number(BigInt(tx.gasLimit))
156
- : 21000;
170
+ const valueInWei = tx.value == null ? 0n : _getBigInt(tx.value, "tx.value");
171
+ const gasLimit = tx.gasLimit == null ? 21000 : _getNumber(tx.gasLimit, "tx.gasLimit");
157
172
 
158
173
  const data = tx.data == null ? null : normalizeHex(tx.data);
159
174
  const remarks = tx.remarks == null ? null : normalizeHex(tx.remarks);
@@ -299,13 +314,19 @@ class Wallet extends BaseWallet {
299
314
  }
300
315
 
301
316
  /**
302
- * Encrypts and serializes this wallet to JSON.
317
+ * Encrypts and serializes this wallet to JSON.
303
318
  * @param {string|Uint8Array} password
304
319
  * @returns {string}
305
320
  */
306
321
  encryptSync(password) {
307
322
  _requireInitialized();
308
- const pw = typeof password === "string" ? password : Buffer.from(arrayify(password)).toString("utf8");
323
+ if (this._seed != null) {
324
+ return Wallet.encryptSeedSync(hexToBytes(this._seed), password);
325
+ }
326
+ const pw = typeof password === "string"
327
+ ? password.normalize("NFC")
328
+ : Buffer.from(arrayify(password)).toString("utf8").normalize("NFC");
329
+ assertSecretArgument(pw.length >= 12, "password must be at least 12 characters", "password");
309
330
  const json = qcsdk.serializeEncryptedWallet(this._qcWallet, pw);
310
331
  if (typeof json !== "string") throw makeError("serializeEncryptedWallet failed", "UNKNOWN_ERROR", {});
311
332
  return json;
@@ -325,12 +346,34 @@ class Wallet extends BaseWallet {
325
346
  assertArgument(Array.isArray(seedArr), "seed must be an array of numbers or Uint8Array", "seed", seed);
326
347
  const allowedLengths = [64, 72, 96];
327
348
  assertArgument(allowedLengths.includes(seedArr.length), "seed must be 64, 72, or 96 bytes", "seed", seedArr.length);
328
- const pw = typeof password === "string" ? password : Buffer.from(arrayify(password)).toString("utf8");
349
+ const pw = typeof password === "string"
350
+ ? password.normalize("NFC")
351
+ : Buffer.from(arrayify(password)).toString("utf8").normalize("NFC");
352
+ assertSecretArgument(pw.length >= 12, "password must be at least 12 characters", "password");
329
353
  const json = qcsdk.serializeSeedAsEncryptedWallet(seedArr, pw);
330
354
  if (typeof json !== "string") throw makeError("serializeSeedAsEncryptedWallet failed", "UNKNOWN_ERROR", {});
331
355
  return json;
332
356
  }
333
357
 
358
+ /**
359
+ * Returns the seed phrase (list of words) if this wallet has a seed, else null.
360
+ * Derived from the stored pre-expansion seed via seed-words.getWordListFromSeedArray.
361
+ *
362
+ * Non-null for wallets created via createRandom, fromPhrase, fromSeed, and
363
+ * fromEncryptedJsonSync when the JSON is a version-5 keystore produced by
364
+ * encryptSync on a seed-bearing wallet or by encryptSeedSync.
365
+ * Null for fromKeys and for v3/v4 keystores without preExpansionSeed.
366
+ *
367
+ * @returns {string[]|null}
368
+ */
369
+ getPhrase() {
370
+ _requireInitialized();
371
+ if (this._seed == null) return null;
372
+ const bytes = Array.from(hexToBytes(this._seed));
373
+ const words = seedWords.getWordListFromSeedArray(bytes);
374
+ return Array.isArray(words) ? words : null;
375
+ }
376
+
334
377
  /**
335
378
  * Returns the recommended signing context for this wallet.
336
379
  * Setting fullSign to true may incur additional gas cost.
@@ -355,7 +398,10 @@ class Wallet extends BaseWallet {
355
398
  * @returns {Wallet}
356
399
  */
357
400
  connect(provider) {
358
- return new Wallet(this.signingKey, provider);
401
+ const w = new Wallet(this.signingKey, provider);
402
+ w._qcWallet = this._qcWallet;
403
+ w._seed = this._seed;
404
+ return w;
359
405
  }
360
406
 
361
407
  /**
@@ -369,29 +415,11 @@ class Wallet extends BaseWallet {
369
415
  if (keyType != null) {
370
416
  assertArgument(keyType === 3 || keyType === 5, "keyType must be null, 3, or 5", "keyType", keyType);
371
417
  }
372
- const qcWallet = qcsdk.newWallet(keyType ?? null);
373
- if (!qcWallet || typeof qcWallet === "number") {
374
- throw makeError("newWallet failed", "UNKNOWN_ERROR", { result: qcWallet });
375
- }
376
- return Wallet._fromQcWallet(qcWallet, provider || null);
377
- }
378
-
379
- /**
380
- * Creates a new random seed word list (32 words for keyType 3, 36 for keyType 5).
381
- * Use the returned words with `Wallet.fromPhrase()` to create a wallet.
382
- * @param {number|null=} keyType Optional key type: null (default=3), 3, or 5
383
- * @returns {string[]}
384
- */
385
- static createRandomSeed(keyType) {
386
- _requireInitialized();
387
- if (keyType != null) {
388
- assertArgument(keyType === 3 || keyType === 5, "keyType must be null, 3, or 5", "keyType", keyType);
389
- }
390
- const words = qcsdk.newWalletSeed(keyType ?? null);
418
+ const words = qcsdk.newWalletSeedWords(keyType ?? null);
391
419
  if (!words || !Array.isArray(words)) {
392
- throw makeError("newWalletSeed failed", "UNKNOWN_ERROR", { result: words });
420
+ throw makeError("newWalletSeedWords failed", "UNKNOWN_ERROR", { result: words });
393
421
  }
394
- return words;
422
+ return Wallet.fromPhrase(words, provider);
395
423
  }
396
424
 
397
425
  /**
@@ -465,8 +493,8 @@ class Wallet extends BaseWallet {
465
493
  _requireInitialized();
466
494
  const privBytes = typeof privateKey === "string" ? hexToBytes(privateKey) : arrayify(privateKey);
467
495
  const pubBytes = typeof publicKey === "string" ? hexToBytes(publicKey) : arrayify(publicKey);
468
- assertArgument(privBytes.length > 0, "privateKey must not be empty", "privateKey", privateKey);
469
- assertArgument(pubBytes.length > 0, "publicKey must not be empty", "publicKey", publicKey);
496
+ assertSecretArgument(privBytes.length > 0, "privateKey must not be empty", "privateKey");
497
+ assertSecretArgument(pubBytes.length > 0, "publicKey must not be empty", "publicKey");
470
498
 
471
499
  const privArr = _bytesToNumberArray(privBytes);
472
500
  const pubArr = _bytesToNumberArray(pubBytes);
@@ -489,15 +517,20 @@ class Wallet extends BaseWallet {
489
517
  * @returns {Wallet}
490
518
  */
491
519
  static _fromQcWallet(qcWallet, provider) {
492
- // Preserve key material from quantum-coin-js-sdk Wallet.
493
- // newWallet() returns Uint8Array keys; other constructors may return number[].
494
520
  const privSrc = qcWallet.privateKey;
495
521
  const pubSrc = qcWallet.publicKey;
496
522
 
523
+ if (!privSrc || (privSrc instanceof Uint8Array && privSrc.length === 0) || (Array.isArray(privSrc) && privSrc.length === 0)) {
524
+ throw makeError("qcWallet.privateKey is empty or missing", "UNKNOWN_ERROR", {});
525
+ }
526
+ if (!pubSrc || (pubSrc instanceof Uint8Array && pubSrc.length === 0) || (Array.isArray(pubSrc) && pubSrc.length === 0)) {
527
+ throw makeError("qcWallet.publicKey is empty or missing", "UNKNOWN_ERROR", {});
528
+ }
529
+
497
530
  const privBytes =
498
- privSrc instanceof Uint8Array ? new Uint8Array(privSrc) : Uint8Array.from(Array.from(privSrc || []).map((n) => (Number(n) & 0xff)));
531
+ privSrc instanceof Uint8Array ? new Uint8Array(privSrc) : Uint8Array.from(Array.from(privSrc).map((n) => (Number(n) & 0xff)));
499
532
  const pubBytes =
500
- pubSrc instanceof Uint8Array ? new Uint8Array(pubSrc) : Uint8Array.from(Array.from(pubSrc || []).map((n) => (Number(n) & 0xff)));
533
+ pubSrc instanceof Uint8Array ? new Uint8Array(pubSrc) : Uint8Array.from(Array.from(pubSrc).map((n) => (Number(n) & 0xff)));
501
534
  const key = new SigningKey(privBytes, pubBytes);
502
535
 
503
536
  const w = new Wallet(key, provider || null);
@@ -506,6 +539,12 @@ class Wallet extends BaseWallet {
506
539
  if (typeof qcWallet.address === "string") {
507
540
  w.address = normalizeHex(qcWallet.address);
508
541
  }
542
+ if (qcWallet.preExpansionSeed != null) {
543
+ const seedSrc = qcWallet.preExpansionSeed;
544
+ const seedBytes =
545
+ seedSrc instanceof Uint8Array ? seedSrc : Uint8Array.from(Array.from(seedSrc).map((n) => (Number(n) & 0xff)));
546
+ w._seed = bytesToHex(seedBytes);
547
+ }
509
548
  return w;
510
549
  }
511
550
  }