quantumcoin 7.0.3 → 7.0.4

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 (155) hide show
  1. package/.github/workflows/publish-npmjs.yaml +22 -22
  2. package/.gitignore +15 -15
  3. package/LICENSE +21 -21
  4. package/README-SDK.md +756 -754
  5. package/README.md +165 -150
  6. package/SPEC.md +3845 -3843
  7. package/config.d.ts +50 -50
  8. package/config.js +115 -115
  9. package/examples/AllSolidityTypes.sol +184 -184
  10. package/examples/SimpleIERC20.sol +74 -74
  11. package/examples/events.js +41 -35
  12. package/examples/events.ts +35 -0
  13. package/examples/example-generator-sdk-js.js +100 -95
  14. package/examples/example-generator-sdk-js.ts +77 -0
  15. package/examples/example-generator-sdk-ts.js +100 -95
  16. package/examples/example-generator-sdk-ts.ts +77 -0
  17. package/examples/example.js +72 -61
  18. package/examples/example.ts +61 -0
  19. package/examples/offline-signing.js +79 -73
  20. package/examples/offline-signing.ts +66 -0
  21. package/examples/package-lock.json +48 -57
  22. package/examples/package.json +32 -16
  23. package/examples/read-operations.js +32 -27
  24. package/examples/read-operations.ts +31 -0
  25. package/examples/sdk-generator-erc20.inline.json +251 -251
  26. package/examples/solidity-types.ts +43 -43
  27. package/examples/wallet-offline.js +35 -29
  28. package/examples/wallet-offline.ts +34 -0
  29. package/generate-sdk.js +1824 -1490
  30. package/index.js +12 -12
  31. package/package.json +95 -75
  32. package/scripts/copy-declarations.js +31 -0
  33. package/scripts/run-all-one-by-one.js +151 -0
  34. package/src/abi/fragments.d.ts +42 -42
  35. package/src/abi/fragments.js +63 -63
  36. package/src/abi/index.d.ts +13 -13
  37. package/src/abi/index.js +9 -9
  38. package/src/abi/interface.d.ts +128 -132
  39. package/src/abi/interface.js +590 -590
  40. package/src/abi/js-abi-coder.d.ts +8 -0
  41. package/src/abi/js-abi-coder.js +474 -474
  42. package/src/constants.d.ts +66 -61
  43. package/src/constants.js +101 -94
  44. package/src/contract/contract-factory.d.ts +28 -28
  45. package/src/contract/contract-factory.js +105 -105
  46. package/src/contract/contract.d.ts +113 -114
  47. package/src/contract/contract.js +354 -354
  48. package/src/contract/index.d.ts +9 -9
  49. package/src/contract/index.js +9 -9
  50. package/src/errors/index.d.ts +92 -92
  51. package/src/errors/index.js +188 -188
  52. package/src/generator/index.d.ts +74 -0
  53. package/src/generator/index.js +1404 -1404
  54. package/src/index.d.ts +125 -127
  55. package/src/index.js +41 -41
  56. package/src/internal/hex.d.ts +61 -61
  57. package/src/internal/hex.js +144 -144
  58. package/src/providers/extra-providers.d.ts +139 -128
  59. package/src/providers/extra-providers.js +600 -575
  60. package/src/providers/index.d.ts +17 -16
  61. package/src/providers/index.js +10 -10
  62. package/src/providers/json-rpc-provider.d.ts +12 -12
  63. package/src/providers/json-rpc-provider.js +79 -79
  64. package/src/providers/provider.d.ts +207 -203
  65. package/src/providers/provider.js +392 -371
  66. package/src/types/index.d.ts +214 -462
  67. package/src/types/index.js +9 -9
  68. package/src/utils/address.d.ts +72 -72
  69. package/src/utils/address.js +181 -182
  70. package/src/utils/encoding.d.ts +120 -120
  71. package/src/utils/encoding.js +306 -306
  72. package/src/utils/hashing.d.ts +82 -76
  73. package/src/utils/hashing.js +313 -298
  74. package/src/utils/index.d.ts +65 -55
  75. package/src/utils/index.js +13 -13
  76. package/src/utils/result.d.ts +57 -57
  77. package/src/utils/result.js +128 -128
  78. package/src/utils/rlp.d.ts +12 -12
  79. package/src/utils/rlp.js +200 -200
  80. package/src/utils/units.d.ts +29 -29
  81. package/src/utils/units.js +107 -107
  82. package/src/wallet/index.d.ts +10 -10
  83. package/src/wallet/index.js +8 -8
  84. package/src/wallet/wallet.d.ts +160 -160
  85. package/src/wallet/wallet.js +483 -489
  86. package/test/e2e/all-solidity-types.dynamic.test.js +207 -200
  87. package/test/e2e/all-solidity-types.dynamic.test.ts +191 -0
  88. package/test/e2e/all-solidity-types.fixtures.js +231 -231
  89. package/test/e2e/all-solidity-types.generated-sdks.e2e.test.js +387 -368
  90. package/test/e2e/all-solidity-types.generated-sdks.e2e.test.ts +350 -0
  91. package/test/e2e/helpers.js +59 -47
  92. package/test/e2e/signing-context-and-fee.e2e.test.js +137 -0
  93. package/test/e2e/signing-context-and-fee.e2e.test.ts +128 -0
  94. package/test/e2e/simple-erc20.generated-sdks.e2e.test.js +168 -151
  95. package/test/e2e/simple-erc20.generated-sdks.e2e.test.ts +141 -0
  96. package/test/e2e/transactional.test.js +245 -191
  97. package/test/e2e/transactional.test.ts +208 -0
  98. package/test/e2e/typed-generator.e2e.test.js +407 -404
  99. package/test/e2e/typed-generator.e2e.test.ts +337 -0
  100. package/test/fixtures/ConstructorParam.sol +23 -23
  101. package/test/fixtures/MultiContracts.sol +37 -37
  102. package/test/fixtures/SimpleStorage.sol +18 -18
  103. package/test/fixtures/StakingContract.abi.json +1 -1
  104. package/test/integration/ipc-provider.test.js +49 -44
  105. package/test/integration/ipc-provider.test.ts +44 -0
  106. package/test/integration/provider.test.js +88 -72
  107. package/test/integration/provider.test.ts +85 -0
  108. package/test/integration/ws-provider.test.js +41 -33
  109. package/test/integration/ws-provider.test.ts +38 -0
  110. package/test/security/malformed-input.test.js +37 -31
  111. package/test/security/malformed-input.test.ts +35 -0
  112. package/test/unit/_encrypted-output.txt +6 -0
  113. package/test/unit/_log-encrypted-jsons.js +45 -0
  114. package/test/unit/_write-keystore-fixture.js +16 -0
  115. package/test/unit/abi-interface.test.js +103 -98
  116. package/test/unit/abi-interface.test.ts +102 -0
  117. package/test/unit/address-wallet.test.js +355 -257
  118. package/test/unit/address-wallet.test.ts +342 -0
  119. package/test/unit/browser-provider.test.js +85 -82
  120. package/test/unit/browser-provider.test.ts +79 -0
  121. package/test/unit/contract.test.js +85 -82
  122. package/test/unit/contract.test.ts +83 -0
  123. package/test/unit/encoding-units-rlp.test.js +92 -89
  124. package/test/unit/encoding-units-rlp.test.ts +91 -0
  125. package/test/unit/errors.test.js +77 -74
  126. package/test/unit/errors.test.ts +76 -0
  127. package/test/unit/filter-by-blockhash.test.js +55 -52
  128. package/test/unit/filter-by-blockhash.test.ts +54 -0
  129. package/test/unit/fixtures/encrypted-keystores-48-32-36.js +9 -0
  130. package/test/unit/generate-contract-cli.test.js +42 -39
  131. package/test/unit/generate-contract-cli.test.ts +41 -0
  132. package/test/unit/generate-sdk-artifacts-json.test.js +113 -110
  133. package/test/unit/generate-sdk-artifacts-json.test.ts +110 -0
  134. package/test/unit/generator.test.js +102 -99
  135. package/test/unit/generator.test.ts +101 -0
  136. package/test/unit/hashing.test.js +68 -54
  137. package/test/unit/hashing.test.ts +67 -0
  138. package/test/unit/init.test.js +39 -36
  139. package/test/unit/init.test.ts +38 -0
  140. package/test/unit/interface.test.js +56 -53
  141. package/test/unit/interface.test.ts +54 -0
  142. package/test/unit/internal-hex.test.js +50 -47
  143. package/test/unit/internal-hex.test.ts +49 -0
  144. package/test/unit/populate-transaction.test.js +65 -62
  145. package/test/unit/populate-transaction.test.ts +64 -0
  146. package/test/unit/providers.test.js +200 -144
  147. package/test/unit/providers.test.ts +196 -0
  148. package/test/unit/result.test.js +80 -77
  149. package/test/unit/result.test.ts +79 -0
  150. package/test/unit/solidity-types.test.js +49 -46
  151. package/test/unit/solidity-types.test.ts +39 -0
  152. package/test/unit/utils.test.js +57 -54
  153. package/test/unit/utils.test.ts +56 -0
  154. package/test/verbose-logger.js +74 -0
  155. package/tsconfig.build.json +14 -0
@@ -1,257 +1,355 @@
1
- /**
2
- * @testCategory unit
3
- * @blockchainRequired false
4
- * @transactional false
5
- * @description Wallet functionality: constructors, static factories, encryption, signing, nonce management (offline)
6
- */
7
-
8
- const { describe, it } = require("node:test");
9
- const assert = require("node:assert/strict");
10
-
11
- const { Initialize } = require("../../config");
12
- const qc = require("../../index");
13
-
14
- describe("Address + Wallet (offline)", () => {
15
- // ---------------------------------------------------------------------------
16
- // Hardcoded test wallet (from upstream quantum-coin-js-sdk examples)
17
- // WARNING: test-only wallet; never use for real funds.
18
- // ---------------------------------------------------------------------------
19
- const TEST_WALLET_ENCRYPTED_JSON =
20
- "{\"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}";
21
- const TEST_WALLET_PASSPHRASE = "QuantumCoinExample123!";
22
- const TEST_WALLET_ADDRESS = "0x1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6";
23
-
24
- // ---------------------------------------------------------------------------
25
- // Hardcoded seed words (generated once via quantum-coin-js-sdk.newWalletSeed()).
26
- // WARNING: test-only seed words; never use for real funds.
27
- // ---------------------------------------------------------------------------
28
- const TEST_SEED_WORDS = [
29
- "cylamidal","suculate","sealmate","radiploid","equifaxis","and","antipoise","stitchesy","perelade","lite","gourtarel","thursat",
30
- "overdrome","cogulate","nonviva","stewnut","floribund","enduivist","decatary","elvenwort","indoucate","ravelent","vocalus","wetshirt",
31
- "rutatory","percect","breaktout","corpation","myricorus","veofreat","junkard","supercarp","sukerus","tautang","facetype","shishkin",
32
- "insulal","hobstone","stumbed","tecutonic","jumplike","hegwirth","idea","bhagatpur","pavastava","kukuluan","mageiline","extranite"
33
- ];
34
- const TEST_SEED_ADDRESS = "0x3Ce22c0e2714196734E42B0D4D5AD11284260502A560e46c2Cd857391564142F".toLowerCase();
35
-
36
- it("validates and normalizes 32-byte addresses", async () => {
37
- await Initialize(null);
38
- const wallet = qc.Wallet.createRandom();
39
- assert.equal(qc.isAddress(wallet.address), true);
40
- assert.equal(qc.getAddress(wallet.address), wallet.address.toLowerCase());
41
- });
42
-
43
- it("fromEncryptedJsonSync opens a known wallet (hardcoded)", async () => {
44
- await Initialize(null);
45
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
46
- assert.equal(wallet.address, TEST_WALLET_ADDRESS);
47
- assert.equal(qc.isAddress(wallet.address), true);
48
- });
49
-
50
- it("encryptSync + fromEncryptedJsonSync roundtrip (deterministic address)", async () => {
51
- await Initialize(null);
52
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
53
- const json = wallet.encryptSync("mySecurePassword123");
54
- assert.equal(typeof json, "string");
55
- assert.ok(json.includes("address"));
56
- const wallet2 = qc.Wallet.fromEncryptedJsonSync(json, "mySecurePassword123");
57
- assert.equal(wallet2.address, wallet.address);
58
- });
59
-
60
- it("encryptSync accepts Uint8Array password", async () => {
61
- await Initialize(null);
62
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
63
- const pw = qc.toUtf8Bytes("mySecurePassword123");
64
- const json = wallet.encryptSync(pw);
65
- assert.equal(typeof json, "string");
66
- assert.ok(json.includes("address"));
67
- });
68
-
69
- it("Wallet constructor accepts privateKey hex string (roundtrip address)", async () => {
70
- await Initialize(null);
71
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
72
- const wallet2 = new qc.Wallet(wallet.privateKey);
73
- assert.equal(wallet2.address, wallet.address);
74
- });
75
-
76
- it("fromPhrase supports string[] and string inputs (48 words)", async () => {
77
- await Initialize(null);
78
- assert.equal(TEST_SEED_WORDS.length, 48);
79
-
80
- const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
81
- const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS.join(" "));
82
- const w3 = qc.Wallet.fromPhrase(TEST_SEED_WORDS.join(","));
83
-
84
- assert.equal(w1.address, TEST_SEED_ADDRESS);
85
- assert.equal(w2.address, TEST_SEED_ADDRESS);
86
- assert.equal(w3.address, TEST_SEED_ADDRESS);
87
- });
88
-
89
- it("fromPhrase rejects non-48-word phrases", async () => {
90
- await Initialize(null);
91
- assert.throws(() => qc.Wallet.fromPhrase("one two three"), /48 words/i);
92
- assert.throws(() => qc.Wallet.fromPhrase(new Array(47).fill("word")), /48 words/i);
93
- });
94
-
95
- it("signMessageSync + verifyMessage roundtrip (known wallet)", async () => {
96
- await Initialize(null);
97
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
98
- const sig = wallet.signMessageSync("Hello, QuantumCoin!");
99
- assert.equal(typeof sig, "string");
100
- assert.ok(sig.startsWith("0x"));
101
- const recovered = qc.verifyMessage("Hello, QuantumCoin!", sig);
102
- assert.equal(recovered, wallet.address.toLowerCase());
103
- });
104
-
105
- it("signTransaction works offline and returns raw tx hex", async () => {
106
- await Initialize(null);
107
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
108
- const to = qc.Wallet.createRandom().address;
109
- const raw = await wallet.signTransaction({
110
- to,
111
- value: 0n,
112
- gasLimit: 21000,
113
- nonce: 0,
114
- chainId: 123123,
115
- remarks: null,
116
- });
117
- assert.equal(typeof raw, "string");
118
- assert.ok(raw.startsWith("0x"));
119
- });
120
-
121
- it("signTransaction resolves nonce when omitted (and treats remarks omitted vs null the same)", async () => {
122
- await Initialize(null);
123
- const calls = { count: 0, tags: [] };
124
- const fakeProvider = {
125
- chainId: 123123,
126
- getTransactionCount: async (_addr, tag) => {
127
- calls.count++;
128
- calls.tags.push(tag);
129
- return 5;
130
- },
131
- };
132
-
133
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider);
134
- const to = qc.Wallet.createRandom().address;
135
-
136
- const raw1 = await wallet.signTransaction({ to }); // nonce omitted, remarks omitted, gasLimit/value/data omitted
137
- const raw2 = await wallet.signTransaction({ to, remarks: null }); // same behavior for remarks
138
-
139
- assert.ok(typeof raw1 === "string" && raw1.startsWith("0x"));
140
- // PQC signing may be non-deterministic, so do not assert raw equality.
141
- assert.ok(typeof raw2 === "string" && raw2.startsWith("0x"));
142
- assert.equal(calls.count >= 1, true);
143
- // wallet prefers "pending" first
144
- assert.equal(calls.tags[0], "pending");
145
- });
146
-
147
- it("signTransaction supports contract creation (to: null) with explicit nonce", async () => {
148
- await Initialize(null);
149
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
150
- const raw = await wallet.signTransaction({
151
- to: null,
152
- data: "0x",
153
- nonce: 0,
154
- gasLimit: 500000,
155
- chainId: 123123,
156
- });
157
- assert.ok(typeof raw === "string" && raw.startsWith("0x"));
158
- });
159
-
160
- it("signTransaction rejects remarks > 32 bytes", async () => {
161
- await Initialize(null);
162
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
163
- const to = qc.Wallet.createRandom().address;
164
- const tooLong = "0x" + "11".repeat(33);
165
- await assert.rejects(
166
- () =>
167
- wallet.signTransaction({
168
- to,
169
- value: 0n,
170
- gasLimit: 21000,
171
- nonce: 0,
172
- chainId: 123123,
173
- remarks: tooLong,
174
- }),
175
- );
176
- });
177
-
178
- it("connect(provider) returns a new wallet with provider attached", async () => {
179
- await Initialize(null);
180
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
181
- const fakeProvider = {
182
- chainId: 123123,
183
- getBalance: async () => 123n,
184
- getTransactionCount: async () => 7,
185
- sendTransaction: async () => ({ hash: "0x" + "11".repeat(32), wait: async () => ({ blockNumber: 1 }) }),
186
- };
187
- const connected = wallet.connect(fakeProvider);
188
- assert.equal(connected.address, wallet.address);
189
- assert.equal(connected.provider, fakeProvider);
190
- });
191
-
192
- it("sendTransaction uses provider.sendTransaction with signed raw tx (no broadcast in test)", async () => {
193
- await Initialize(null);
194
- const calls = { send: 0, raw: null };
195
- const fakeProvider = {
196
- chainId: 123123,
197
- getTransactionCount: async () => 0,
198
- sendTransaction: async (raw) => {
199
- calls.send++;
200
- calls.raw = raw;
201
- return { hash: "0x" + "22".repeat(32), wait: async () => ({ blockNumber: 1 }) };
202
- },
203
- };
204
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider);
205
- const to = qc.Wallet.createRandom().address;
206
- const resp = await wallet.sendTransaction({ to, value: 0n, gasLimit: 21000, nonce: 0 });
207
- assert.equal(calls.send, 1);
208
- assert.equal(typeof calls.raw, "string");
209
- assert.ok(calls.raw.startsWith("0x"));
210
- assert.ok(resp && resp.hash);
211
- });
212
-
213
- it("NonceManager caches nonce and increments between sends (offline)", async () => {
214
- await Initialize(null);
215
- const calls = { getNonce: 0, nonces: [] };
216
- const fakeProvider = {
217
- chainId: 123123,
218
- getTransactionCount: async () => {
219
- calls.getNonce++;
220
- return 10;
221
- },
222
- sendTransaction: async () => ({ hash: "0x" + "33".repeat(32), wait: async () => ({ blockNumber: 1 }) }),
223
- };
224
- const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider);
225
- const nm = new qc.NonceManager(wallet);
226
-
227
- // Intercept wallet.sendTransaction to capture nonce used (still signs tx).
228
- const originalSend = wallet.sendTransaction.bind(wallet);
229
- wallet.sendTransaction = async (tx) => {
230
- calls.nonces.push(tx.nonce);
231
- return originalSend(tx);
232
- };
233
-
234
- const to = qc.Wallet.createRandom().address;
235
- await nm.sendTransaction({ to, value: 0n, gasLimit: 21000 });
236
- await nm.sendTransaction({ to, value: 0n, gasLimit: 21000 });
237
-
238
- assert.equal(calls.getNonce, 1);
239
- assert.deepEqual(calls.nonces, [10, 11]);
240
- });
241
-
242
- it("VoidSigner exposes getAddress()", async () => {
243
- await Initialize(null);
244
- const addr = qc.Wallet.createRandom().address;
245
- const vs = new qc.VoidSigner(addr, null);
246
- assert.equal(await vs.getAddress(), addr.toLowerCase());
247
- });
248
-
249
- it("resolveAddress supports string, Addressable, and Promise inputs", async () => {
250
- await Initialize(null);
251
- const wallet = qc.Wallet.createRandom();
252
- assert.equal(qc.resolveAddress(wallet.address), wallet.address.toLowerCase());
253
- assert.equal(await qc.resolveAddress(wallet), wallet.address.toLowerCase());
254
- assert.equal(await qc.resolveAddress(Promise.resolve(wallet.address)), wallet.address.toLowerCase());
255
- });
256
- });
257
-
1
+ /**
2
+ * @testCategory unit
3
+ * @blockchainRequired false
4
+ * @transactional false
5
+ * @description Wallet functionality: constructors, static factories, encryption, signing, nonce management (offline)
6
+ */
7
+
8
+ const { describe, it } = require("node:test");
9
+ const assert = require("node:assert/strict");
10
+
11
+ const { Initialize } = require("../../config");
12
+ const qc = require("../../index");
13
+ const { logSuite, logTest, logAddress } = require("../verbose-logger");
14
+ const {
15
+ TEST_ENCRYPTED_JSON_48,
16
+ TEST_ENCRYPTED_JSON_32,
17
+ TEST_ENCRYPTED_JSON_36,
18
+ } = require("./fixtures/encrypted-keystores-48-32-36");
19
+
20
+ describe("Address + Wallet (offline)", () => {
21
+ logSuite("Address + Wallet (offline)");
22
+ // ---------------------------------------------------------------------------
23
+ // Hardcoded test wallet (from upstream quantum-coin-js-sdk examples)
24
+ // WARNING: test-only wallet; never use for real funds.
25
+ // ---------------------------------------------------------------------------
26
+ const TEST_WALLET_ENCRYPTED_JSON =
27
+ "{\"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}";
28
+ const TEST_WALLET_PASSPHRASE = "QuantumCoinExample123!";
29
+ const TEST_WALLET_ADDRESS = "0x1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6";
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Hardcoded seed words (generated once via quantum-coin-js-sdk.newWalletSeed()).
33
+ // WARNING: test-only seed words; never use for real funds.
34
+ // ---------------------------------------------------------------------------
35
+ const TEST_SEED_WORDS = [
36
+ "cylamidal","suculate","sealmate","radiploid","equifaxis","and","antipoise","stitchesy","perelade","lite","gourtarel","thursat",
37
+ "overdrome","cogulate","nonviva","stewnut","floribund","enduivist","decatary","elvenwort","indoucate","ravelent","vocalus","wetshirt",
38
+ "rutatory","percect","breaktout","corpation","myricorus","veofreat","junkard","supercarp","sukerus","tautang","facetype","shishkin",
39
+ "insulal","hobstone","stumbed","tecutonic","jumplike","hegwirth","idea","bhagatpur","pavastava","kukuluan","mageiline","extranite"
40
+ ];
41
+ const TEST_SEED_ADDRESS = "0x3Ce22c0e2714196734E42B0D4D5AD11284260502A560e46c2Cd857391564142F".toLowerCase();
42
+
43
+ // First 32 and 36 words from TEST_SEED_WORDS (addresses from Wallet.fromPhrase run)
44
+ const TEST_SEED_WORDS_32 = TEST_SEED_WORDS.slice(0, 32);
45
+ const TEST_SEED_WORDS_36 = TEST_SEED_WORDS.slice(0, 36);
46
+ const TEST_SEED_ADDRESS_32 = "0x38b12df2d4762a04a183f936c47747a1f13d0b0ba72066b43b4b6d7f776e9e25";
47
+ const TEST_SEED_ADDRESS_36 = "0x030e264c853bd859c53fae3ad6ef0e011dc799685e2b05d5efa7ac50f10ca075";
48
+ const PASSPHRASE_PHRASE = "mySecurePassword123";
49
+
50
+ it("validates and normalizes 32-byte addresses", async () => {
51
+ logTest("validates and normalizes 32-byte addresses", {});
52
+ await Initialize(null);
53
+ const wallet = qc.Wallet.createRandom();
54
+ logAddress("wallet", wallet.address);
55
+ assert.equal(qc.isAddress(wallet.address), true);
56
+ assert.equal(qc.getAddress(wallet.address), wallet.address.toLowerCase());
57
+ });
58
+
59
+ it("fromEncryptedJsonSync opens a known wallet (hardcoded)", async () => {
60
+ logTest("fromEncryptedJsonSync opens a known wallet (hardcoded)", {});
61
+ await Initialize(null);
62
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
63
+ logAddress("wallet", wallet.address);
64
+ assert.equal(wallet.address, TEST_WALLET_ADDRESS);
65
+ assert.equal(qc.isAddress(wallet.address), true);
66
+ });
67
+
68
+ it("fromEncryptedJsonSync opens 48-word phrase wallet (hardcoded encrypted JSON)", async () => {
69
+ await Initialize(null);
70
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_ENCRYPTED_JSON_48, PASSPHRASE_PHRASE);
71
+ assert.equal(wallet.address, TEST_SEED_ADDRESS);
72
+ assert.equal(qc.isAddress(wallet.address), true);
73
+ });
74
+
75
+ it("fromEncryptedJsonSync opens 32-word phrase wallet (hardcoded encrypted JSON)", async () => {
76
+ await Initialize(null);
77
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_ENCRYPTED_JSON_32, PASSPHRASE_PHRASE);
78
+ assert.equal(wallet.address, TEST_SEED_ADDRESS_32);
79
+ assert.equal(qc.isAddress(wallet.address), true);
80
+ });
81
+
82
+ it("fromEncryptedJsonSync opens 36-word phrase wallet (hardcoded encrypted JSON)", async () => {
83
+ await Initialize(null);
84
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_ENCRYPTED_JSON_36, PASSPHRASE_PHRASE);
85
+ assert.equal(wallet.address, TEST_SEED_ADDRESS_36);
86
+ assert.equal(qc.isAddress(wallet.address), true);
87
+ });
88
+
89
+ it("encryptSync + fromEncryptedJsonSync roundtrip (deterministic address)", async () => {
90
+ await Initialize(null);
91
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
92
+ const json = wallet.encryptSync("mySecurePassword123");
93
+ assert.equal(typeof json, "string");
94
+ assert.ok(json.includes("address"));
95
+ const wallet2 = qc.Wallet.fromEncryptedJsonSync(json, "mySecurePassword123");
96
+ assert.equal(wallet2.address, wallet.address);
97
+ });
98
+
99
+ it("encryptSync accepts Uint8Array password", async () => {
100
+ await Initialize(null);
101
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
102
+ const pw = qc.toUtf8Bytes("mySecurePassword123");
103
+ const json = wallet.encryptSync(pw);
104
+ assert.equal(typeof json, "string");
105
+ assert.ok(json.includes("address"));
106
+ });
107
+
108
+ it("Wallet constructor accepts privateKey hex string (roundtrip address)", async () => {
109
+ await Initialize(null);
110
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
111
+ const wallet2 = new qc.Wallet(wallet.privateKey);
112
+ assert.equal(wallet2.address, wallet.address);
113
+ });
114
+
115
+ it("fromPhrase supports string[] and string inputs (48 words)", async () => {
116
+ await Initialize(null);
117
+ assert.equal(TEST_SEED_WORDS.length, 48);
118
+
119
+ const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
120
+ const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS.join(" "));
121
+ const w3 = qc.Wallet.fromPhrase(TEST_SEED_WORDS.join(","));
122
+
123
+ assert.equal(w1.address, TEST_SEED_ADDRESS);
124
+ assert.equal(w2.address, TEST_SEED_ADDRESS);
125
+ assert.equal(w3.address, TEST_SEED_ADDRESS);
126
+ });
127
+
128
+ it("fromPhrase supports 32-word seed phrase", async () => {
129
+ await Initialize(null);
130
+ assert.equal(TEST_SEED_WORDS_32.length, 32);
131
+
132
+ const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
133
+ const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32.join(" "));
134
+
135
+ assert.equal(w1.address, TEST_SEED_ADDRESS_32);
136
+ assert.equal(w2.address, TEST_SEED_ADDRESS_32);
137
+ });
138
+
139
+ it("fromPhrase supports 36-word seed phrase", async () => {
140
+ await Initialize(null);
141
+ assert.equal(TEST_SEED_WORDS_36.length, 36);
142
+
143
+ const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
144
+ const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36.join(" "));
145
+
146
+ assert.equal(w1.address, TEST_SEED_ADDRESS_36);
147
+ assert.equal(w2.address, TEST_SEED_ADDRESS_36);
148
+ });
149
+
150
+ it("fromPhrase rejects invalid phrase lengths (must be 32, 36, or 48 words)", async () => {
151
+ await Initialize(null);
152
+ assert.throws(() => qc.Wallet.fromPhrase("one two three"), /32, 36, or 48 words/i);
153
+ assert.throws(() => qc.Wallet.fromPhrase(new Array(47).fill("word")), /32, 36, or 48 words/i);
154
+ assert.throws(() => qc.Wallet.fromPhrase(new Array(12).fill("word")), /32, 36, or 48 words/i);
155
+ });
156
+
157
+ it("signMessageSync + verifyMessage roundtrip (known wallet)", async () => {
158
+ await Initialize(null);
159
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
160
+ const sig = wallet.signMessageSync("Hello, QuantumCoin!");
161
+ assert.equal(typeof sig, "string");
162
+ assert.ok(sig.startsWith("0x"));
163
+ const recovered = qc.verifyMessage("Hello, QuantumCoin!", sig);
164
+ assert.equal(recovered, wallet.address.toLowerCase());
165
+ });
166
+
167
+ it("signMessageSync returns combined signature hex and verifyMessage roundtrip (fromPhrase wallet)", async () => {
168
+ await Initialize(null);
169
+ const wallet = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
170
+ const msg = "test message";
171
+ const sig = wallet.signMessageSync(msg);
172
+ assert.equal(typeof sig, "string");
173
+ assert.ok(sig.startsWith("0x"));
174
+ assert.ok(sig.length > 4);
175
+ const recovered = qc.verifyMessage(msg, sig);
176
+ assert.equal(recovered, wallet.address.toLowerCase());
177
+ });
178
+
179
+ it("signMessageSync + verifyMessage roundtrip (32-word phrase wallet)", async () => {
180
+ await Initialize(null);
181
+ const wallet = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
182
+ const msg = "hello 32";
183
+ const sig = wallet.signMessageSync(msg);
184
+ assert.equal(typeof sig, "string");
185
+ assert.ok(sig.startsWith("0x"));
186
+ const recovered = qc.verifyMessage(msg, sig);
187
+ assert.equal(recovered, wallet.address.toLowerCase());
188
+ assert.equal(recovered, TEST_SEED_ADDRESS_32.toLowerCase());
189
+ });
190
+
191
+ it("signMessageSync + verifyMessage roundtrip (36-word phrase wallet)", async () => {
192
+ await Initialize(null);
193
+ const wallet = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
194
+ const msg = "hello 36";
195
+ const sig = wallet.signMessageSync(msg);
196
+ assert.equal(typeof sig, "string");
197
+ assert.ok(sig.startsWith("0x"));
198
+ const recovered = qc.verifyMessage(msg, sig);
199
+ assert.equal(recovered, wallet.address.toLowerCase());
200
+ assert.equal(recovered, TEST_SEED_ADDRESS_36.toLowerCase());
201
+ });
202
+
203
+ it("signTransaction works offline and returns raw tx hex", async () => {
204
+ await Initialize(null);
205
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
206
+ const to = qc.Wallet.createRandom().address;
207
+ const raw = await wallet.signTransaction({
208
+ to,
209
+ value: 0n,
210
+ gasLimit: 21000,
211
+ nonce: 0,
212
+ chainId: 123123,
213
+ remarks: null,
214
+ });
215
+ assert.equal(typeof raw, "string");
216
+ assert.ok(raw.startsWith("0x"));
217
+ });
218
+
219
+ it("signTransaction resolves nonce when omitted (and treats remarks omitted vs null the same)", async () => {
220
+ await Initialize(null);
221
+ const calls = { count: 0, tags: [] };
222
+ const fakeProvider = {
223
+ chainId: 123123,
224
+ getTransactionCount: async (_addr, tag) => {
225
+ calls.count++;
226
+ calls.tags.push(tag);
227
+ return 5;
228
+ },
229
+ };
230
+
231
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider);
232
+ const to = qc.Wallet.createRandom().address;
233
+
234
+ const raw1 = await wallet.signTransaction({ to }); // nonce omitted, remarks omitted, gasLimit/value/data omitted
235
+ const raw2 = await wallet.signTransaction({ to, remarks: null }); // same behavior for remarks
236
+
237
+ assert.ok(typeof raw1 === "string" && raw1.startsWith("0x"));
238
+ // PQC signing may be non-deterministic, so do not assert raw equality.
239
+ assert.ok(typeof raw2 === "string" && raw2.startsWith("0x"));
240
+ assert.equal(calls.count >= 1, true);
241
+ // wallet prefers "pending" first
242
+ assert.equal(calls.tags[0], "pending");
243
+ });
244
+
245
+ it("signTransaction supports contract creation (to: null) with explicit nonce", async () => {
246
+ await Initialize(null);
247
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
248
+ const raw = await wallet.signTransaction({
249
+ to: null,
250
+ data: "0x",
251
+ nonce: 0,
252
+ gasLimit: 500000,
253
+ chainId: 123123,
254
+ });
255
+ assert.ok(typeof raw === "string" && raw.startsWith("0x"));
256
+ });
257
+
258
+ it("signTransaction rejects remarks > 32 bytes", async () => {
259
+ await Initialize(null);
260
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
261
+ const to = qc.Wallet.createRandom().address;
262
+ const tooLong = "0x" + "11".repeat(33);
263
+ await assert.rejects(
264
+ () =>
265
+ wallet.signTransaction({
266
+ to,
267
+ value: 0n,
268
+ gasLimit: 21000,
269
+ nonce: 0,
270
+ chainId: 123123,
271
+ remarks: tooLong,
272
+ }),
273
+ );
274
+ });
275
+
276
+ it("connect(provider) returns a new wallet with provider attached", async () => {
277
+ await Initialize(null);
278
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
279
+ const fakeProvider = {
280
+ chainId: 123123,
281
+ getBalance: async () => 123n,
282
+ getTransactionCount: async () => 7,
283
+ sendTransaction: async () => ({ hash: "0x" + "11".repeat(32), wait: async () => ({ blockNumber: 1 }) }),
284
+ };
285
+ const connected = wallet.connect(fakeProvider);
286
+ assert.equal(connected.address, wallet.address);
287
+ assert.equal(connected.provider, fakeProvider);
288
+ });
289
+
290
+ it("sendTransaction uses provider.sendTransaction with signed raw tx (no broadcast in test)", async () => {
291
+ await Initialize(null);
292
+ const calls = { send: 0, raw: null };
293
+ const fakeProvider = {
294
+ chainId: 123123,
295
+ getTransactionCount: async () => 0,
296
+ sendTransaction: async (raw) => {
297
+ calls.send++;
298
+ calls.raw = raw;
299
+ return { hash: "0x" + "22".repeat(32), wait: async () => ({ blockNumber: 1 }) };
300
+ },
301
+ };
302
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider);
303
+ const to = qc.Wallet.createRandom().address;
304
+ const resp = await wallet.sendTransaction({ to, value: 0n, gasLimit: 21000, nonce: 0 });
305
+ assert.equal(calls.send, 1);
306
+ assert.equal(typeof calls.raw, "string");
307
+ assert.ok(calls.raw.startsWith("0x"));
308
+ assert.ok(resp && resp.hash);
309
+ });
310
+
311
+ it("NonceManager caches nonce and increments between sends (offline)", async () => {
312
+ await Initialize(null);
313
+ const calls = { getNonce: 0, nonces: [] };
314
+ const fakeProvider = {
315
+ chainId: 123123,
316
+ getTransactionCount: async () => {
317
+ calls.getNonce++;
318
+ return 10;
319
+ },
320
+ sendTransaction: async () => ({ hash: "0x" + "33".repeat(32), wait: async () => ({ blockNumber: 1 }) }),
321
+ };
322
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider);
323
+ const nm = new qc.NonceManager(wallet);
324
+
325
+ // Intercept wallet.sendTransaction to capture nonce used (still signs tx).
326
+ const originalSend = wallet.sendTransaction.bind(wallet);
327
+ wallet.sendTransaction = async (tx) => {
328
+ calls.nonces.push(tx.nonce);
329
+ return originalSend(tx);
330
+ };
331
+
332
+ const to = qc.Wallet.createRandom().address;
333
+ await nm.sendTransaction({ to, value: 0n, gasLimit: 21000 });
334
+ await nm.sendTransaction({ to, value: 0n, gasLimit: 21000 });
335
+
336
+ assert.equal(calls.getNonce, 1);
337
+ assert.deepEqual(calls.nonces, [10, 11]);
338
+ });
339
+
340
+ it("VoidSigner exposes getAddress()", async () => {
341
+ await Initialize(null);
342
+ const addr = qc.Wallet.createRandom().address;
343
+ const vs = new qc.VoidSigner(addr, null);
344
+ assert.equal(await vs.getAddress(), addr.toLowerCase());
345
+ });
346
+
347
+ it("resolveAddress supports string, Addressable, and Promise inputs", async () => {
348
+ await Initialize(null);
349
+ const wallet = qc.Wallet.createRandom();
350
+ assert.equal(qc.resolveAddress(wallet.address), wallet.address.toLowerCase());
351
+ assert.equal(await qc.resolveAddress(wallet), wallet.address.toLowerCase());
352
+ assert.equal(await qc.resolveAddress(Promise.resolve(wallet.address)), wallet.address.toLowerCase());
353
+ });
354
+ });
355
+