quantumcoin 7.0.3 → 7.0.5

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 +758 -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 +596 -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 +208 -203
  65. package/src/providers/provider.js +393 -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 +168 -160
  85. package/src/wallet/wallet.js +500 -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 +141 -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 +392 -257
  118. package/test/unit/address-wallet.test.ts +379 -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
@@ -0,0 +1,379 @@
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
+ import { describe, it } from "node:test";
9
+ import assert from "node:assert/strict";
10
+
11
+ import { Initialize } from "../../config";
12
+ import qc from "../../index";
13
+ import { logSuite, logTest, logAddress } from "../verbose-logger";
14
+ import {
15
+ TEST_ENCRYPTED_JSON_48,
16
+ TEST_ENCRYPTED_JSON_32,
17
+ TEST_ENCRYPTED_JSON_36,
18
+ } from "./fixtures/encrypted-keystores-48-32-36";
19
+
20
+ describe("Address + Wallet (offline)", () => {
21
+ logSuite("Address + Wallet (offline)");
22
+ const TEST_WALLET_ENCRYPTED_JSON =
23
+ "{\"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}";
24
+ const TEST_WALLET_PASSPHRASE = "QuantumCoinExample123!";
25
+ const TEST_WALLET_ADDRESS = "0x1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6";
26
+
27
+ const TEST_SEED_WORDS = [
28
+ "cylamidal","suculate","sealmate","radiploid","equifaxis","and","antipoise","stitchesy","perelade","lite","gourtarel","thursat",
29
+ "overdrome","cogulate","nonviva","stewnut","floribund","enduivist","decatary","elvenwort","indoucate","ravelent","vocalus","wetshirt",
30
+ "rutatory","percect","breaktout","corpation","myricorus","veofreat","junkard","supercarp","sukerus","tautang","facetype","shishkin",
31
+ "insulal","hobstone","stumbed","tecutonic","jumplike","hegwirth","idea","bhagatpur","pavastava","kukuluan","mageiline","extranite"
32
+ ];
33
+ const TEST_SEED_ADDRESS = "0x3Ce22c0e2714196734E42B0D4D5AD11284260502A560e46c2Cd857391564142F".toLowerCase();
34
+
35
+ const TEST_SEED_WORDS_32 = TEST_SEED_WORDS.slice(0, 32);
36
+ const TEST_SEED_WORDS_36 = TEST_SEED_WORDS.slice(0, 36);
37
+ const TEST_SEED_ADDRESS_32 = "0x38b12df2d4762a04a183f936c47747a1f13d0b0ba72066b43b4b6d7f776e9e25";
38
+ const TEST_SEED_ADDRESS_36 = "0x030e264c853bd859c53fae3ad6ef0e011dc799685e2b05d5efa7ac50f10ca075";
39
+ const PASSPHRASE_PHRASE = "mySecurePassword123";
40
+
41
+ it("validates and normalizes 32-byte addresses", async () => {
42
+ logTest("validates and normalizes 32-byte addresses", {});
43
+ await Initialize(null);
44
+ const wallet = qc.Wallet.createRandom();
45
+ logAddress("wallet", wallet.address);
46
+ assert.equal(qc.isAddress(wallet.address), true);
47
+ assert.equal(qc.getAddress(wallet.address), wallet.address.toLowerCase());
48
+ });
49
+
50
+ it("fromEncryptedJsonSync opens a known wallet (hardcoded)", async () => {
51
+ logTest("fromEncryptedJsonSync opens a known wallet (hardcoded)", {});
52
+ await Initialize(null);
53
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
54
+ logAddress("wallet", wallet.address);
55
+ assert.equal(wallet.address, TEST_WALLET_ADDRESS);
56
+ assert.equal(qc.isAddress(wallet.address), true);
57
+ });
58
+
59
+ it("fromEncryptedJsonSync opens 48-word phrase wallet (hardcoded encrypted JSON)", async () => {
60
+ await Initialize(null);
61
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_ENCRYPTED_JSON_48, PASSPHRASE_PHRASE);
62
+ assert.equal(wallet.address, TEST_SEED_ADDRESS);
63
+ assert.equal(qc.isAddress(wallet.address), true);
64
+ });
65
+
66
+ it("fromEncryptedJsonSync opens 32-word phrase wallet (hardcoded encrypted JSON)", async () => {
67
+ await Initialize(null);
68
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_ENCRYPTED_JSON_32, PASSPHRASE_PHRASE);
69
+ assert.equal(wallet.address, TEST_SEED_ADDRESS_32);
70
+ assert.equal(qc.isAddress(wallet.address), true);
71
+ });
72
+
73
+ it("fromEncryptedJsonSync opens 36-word phrase wallet (hardcoded encrypted JSON)", async () => {
74
+ await Initialize(null);
75
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_ENCRYPTED_JSON_36, PASSPHRASE_PHRASE);
76
+ assert.equal(wallet.address, TEST_SEED_ADDRESS_36);
77
+ assert.equal(qc.isAddress(wallet.address), true);
78
+ });
79
+
80
+ it("encryptSync + fromEncryptedJsonSync roundtrip (deterministic address)", async () => {
81
+ await Initialize(null);
82
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
83
+ const json = wallet.encryptSync("mySecurePassword123");
84
+ assert.equal(typeof json, "string");
85
+ assert.ok(json.includes("address"));
86
+ const wallet2 = qc.Wallet.fromEncryptedJsonSync(json, "mySecurePassword123");
87
+ assert.equal(wallet2.address, wallet.address);
88
+ });
89
+
90
+ it("encryptSync accepts Uint8Array password", async () => {
91
+ await Initialize(null);
92
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
93
+ const pw = qc.toUtf8Bytes("mySecurePassword123");
94
+ const json = wallet.encryptSync(pw);
95
+ assert.equal(typeof json, "string");
96
+ assert.ok(json.includes("address"));
97
+ });
98
+
99
+ it("Wallet constructor accepts privateKey hex string (roundtrip address)", async () => {
100
+ await Initialize(null);
101
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
102
+ const wallet2 = new qc.Wallet(wallet.privateKey);
103
+ assert.equal(wallet2.address, wallet.address);
104
+ });
105
+
106
+ it("fromPhrase supports string[] and string inputs (48 words)", async () => {
107
+ await Initialize(null);
108
+ assert.equal(TEST_SEED_WORDS.length, 48);
109
+
110
+ const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
111
+ const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS.join(" "));
112
+ const w3 = qc.Wallet.fromPhrase(TEST_SEED_WORDS.join(","));
113
+
114
+ assert.equal(w1.address, TEST_SEED_ADDRESS);
115
+ assert.equal(w2.address, TEST_SEED_ADDRESS);
116
+ assert.equal(w3.address, TEST_SEED_ADDRESS);
117
+ });
118
+
119
+ it("fromPhrase supports 32-word seed phrase", async () => {
120
+ await Initialize(null);
121
+ assert.equal(TEST_SEED_WORDS_32.length, 32);
122
+
123
+ const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
124
+ const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32.join(" "));
125
+
126
+ assert.equal(w1.address, TEST_SEED_ADDRESS_32);
127
+ assert.equal(w2.address, TEST_SEED_ADDRESS_32);
128
+ });
129
+
130
+ it("fromPhrase supports 36-word seed phrase", async () => {
131
+ await Initialize(null);
132
+ assert.equal(TEST_SEED_WORDS_36.length, 36);
133
+
134
+ const w1 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
135
+ const w2 = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36.join(" "));
136
+
137
+ assert.equal(w1.address, TEST_SEED_ADDRESS_36);
138
+ assert.equal(w2.address, TEST_SEED_ADDRESS_36);
139
+ });
140
+
141
+ it("fromPhrase rejects invalid phrase lengths (must be 32, 36, or 48 words)", async () => {
142
+ await Initialize(null);
143
+ assert.throws(() => qc.Wallet.fromPhrase("one two three"), /32, 36, or 48 words/i);
144
+ assert.throws(() => qc.Wallet.fromPhrase(new Array(47).fill("word")), /32, 36, or 48 words/i);
145
+ assert.throws(() => qc.Wallet.fromPhrase(new Array(12).fill("word")), /32, 36, or 48 words/i);
146
+ });
147
+
148
+ it("fromKeys creates wallet from privateKey + publicKey bytes (roundtrip address)", async () => {
149
+ await Initialize(null);
150
+ const original = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
151
+ const privBytes = original.signingKey.privateKeyBytes;
152
+ const pubBytes = original.signingKey.publicKeyBytes;
153
+
154
+ const fromBytes = qc.Wallet.fromKeys(privBytes, pubBytes);
155
+ assert.equal(fromBytes.address, original.address);
156
+ assert.equal(qc.isAddress(fromBytes.address), true);
157
+
158
+ const fromHex = qc.Wallet.fromKeys(original.privateKey, qc.hexlify(pubBytes));
159
+ assert.equal(fromHex.address, original.address);
160
+ });
161
+
162
+ it("fromKeys rejects empty keys", async () => {
163
+ await Initialize(null);
164
+ assert.throws(() => qc.Wallet.fromKeys(new Uint8Array(0), new Uint8Array(1)), /privateKey must not be empty/);
165
+ assert.throws(() => qc.Wallet.fromKeys(new Uint8Array(1), new Uint8Array(0)), /publicKey must not be empty/);
166
+ });
167
+
168
+ it("fromKeys wallet can sign messages", async () => {
169
+ await Initialize(null);
170
+ const original = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
171
+ const restored = qc.Wallet.fromKeys(
172
+ original.signingKey.privateKeyBytes,
173
+ original.signingKey.publicKeyBytes,
174
+ );
175
+ assert.equal(restored.address, original.address);
176
+
177
+ const msg = "fromKeys signing test";
178
+ const sig = restored.signMessageSync(msg);
179
+ assert.equal(typeof sig, "string");
180
+ assert.ok(sig.startsWith("0x"));
181
+ const recovered = qc.verifyMessage(msg, sig);
182
+ assert.equal(recovered, original.address.toLowerCase());
183
+ });
184
+
185
+ it("signMessageSync + verifyMessage roundtrip (known wallet)", async () => {
186
+ await Initialize(null);
187
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
188
+ const sig = wallet.signMessageSync("Hello, QuantumCoin!");
189
+ assert.equal(typeof sig, "string");
190
+ assert.ok(sig.startsWith("0x"));
191
+ const recovered = qc.verifyMessage("Hello, QuantumCoin!", sig);
192
+ assert.equal(recovered, wallet.address.toLowerCase());
193
+ });
194
+
195
+ it("signMessageSync returns combined signature hex and verifyMessage roundtrip (fromPhrase wallet)", async () => {
196
+ await Initialize(null);
197
+ const wallet = qc.Wallet.fromPhrase(TEST_SEED_WORDS);
198
+ const msg = "test message";
199
+ const sig = wallet.signMessageSync(msg);
200
+ assert.equal(typeof sig, "string");
201
+ assert.ok(sig.startsWith("0x"));
202
+ assert.ok(sig.length > 4);
203
+ const recovered = qc.verifyMessage(msg, sig);
204
+ assert.equal(recovered, wallet.address.toLowerCase());
205
+ });
206
+
207
+ it("signMessageSync + verifyMessage roundtrip (32-word phrase wallet)", async () => {
208
+ await Initialize(null);
209
+ const wallet = qc.Wallet.fromPhrase(TEST_SEED_WORDS_32);
210
+ const msg = "hello 32";
211
+ const sig = wallet.signMessageSync(msg);
212
+ assert.equal(typeof sig, "string");
213
+ assert.ok(sig.startsWith("0x"));
214
+ const recovered = qc.verifyMessage(msg, sig);
215
+ assert.equal(recovered, wallet.address.toLowerCase());
216
+ assert.equal(recovered, TEST_SEED_ADDRESS_32.toLowerCase());
217
+ });
218
+
219
+ it("signMessageSync + verifyMessage roundtrip (36-word phrase wallet)", async () => {
220
+ await Initialize(null);
221
+ const wallet = qc.Wallet.fromPhrase(TEST_SEED_WORDS_36);
222
+ const msg = "hello 36";
223
+ const sig = wallet.signMessageSync(msg);
224
+ assert.equal(typeof sig, "string");
225
+ assert.ok(sig.startsWith("0x"));
226
+ const recovered = qc.verifyMessage(msg, sig);
227
+ assert.equal(recovered, wallet.address.toLowerCase());
228
+ assert.equal(recovered, TEST_SEED_ADDRESS_36.toLowerCase());
229
+ });
230
+
231
+ it("signTransaction works offline and returns raw tx hex", async () => {
232
+ await Initialize(null);
233
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
234
+ const to = qc.Wallet.createRandom().address;
235
+ const raw = await wallet.signTransaction({
236
+ to,
237
+ value: 0n,
238
+ gasLimit: 21000,
239
+ nonce: 0,
240
+ chainId: 123123,
241
+ remarks: null,
242
+ });
243
+ assert.equal(typeof raw, "string");
244
+ assert.ok(raw.startsWith("0x"));
245
+ });
246
+
247
+ it("signTransaction resolves nonce when omitted (and treats remarks omitted vs null the same)", async () => {
248
+ await Initialize(null);
249
+ const calls = { count: 0, tags: [] as string[] };
250
+ const fakeProvider = {
251
+ chainId: 123123,
252
+ getTransactionCount: async (_addr: string, tag?: string) => {
253
+ calls.count++;
254
+ calls.tags.push(tag ?? "pending");
255
+ return 5;
256
+ },
257
+ };
258
+
259
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider as unknown as qc.Provider);
260
+ const to = qc.Wallet.createRandom().address;
261
+
262
+ const raw1 = await wallet.signTransaction({ to });
263
+ const raw2 = await wallet.signTransaction({ to, remarks: null });
264
+
265
+ assert.ok(typeof raw1 === "string" && raw1.startsWith("0x"));
266
+ assert.ok(typeof raw2 === "string" && raw2.startsWith("0x"));
267
+ assert.equal(calls.count >= 1, true);
268
+ assert.equal(calls.tags[0], "pending");
269
+ });
270
+
271
+ it("signTransaction supports contract creation (to: null) with explicit nonce", async () => {
272
+ await Initialize(null);
273
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
274
+ const raw = await wallet.signTransaction({
275
+ to: null,
276
+ data: "0x",
277
+ nonce: 0,
278
+ gasLimit: 500000,
279
+ chainId: 123123,
280
+ });
281
+ assert.ok(typeof raw === "string" && raw.startsWith("0x"));
282
+ });
283
+
284
+ it("signTransaction rejects remarks > 32 bytes", async () => {
285
+ await Initialize(null);
286
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
287
+ const to = qc.Wallet.createRandom().address;
288
+ const tooLong = "0x" + "11".repeat(33);
289
+ await assert.rejects(
290
+ () =>
291
+ wallet.signTransaction({
292
+ to,
293
+ value: 0n,
294
+ gasLimit: 21000,
295
+ nonce: 0,
296
+ chainId: 123123,
297
+ remarks: tooLong,
298
+ }),
299
+ );
300
+ });
301
+
302
+ it("connect(provider) returns a new wallet with provider attached", async () => {
303
+ await Initialize(null);
304
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
305
+ const fakeProvider = {
306
+ chainId: 123123,
307
+ getBalance: async () => 123n,
308
+ getTransactionCount: async () => 7,
309
+ sendTransaction: async () => ({ hash: "0x" + "11".repeat(32), wait: async () => ({ blockNumber: 1 }) }),
310
+ };
311
+ const connected = wallet.connect(fakeProvider as unknown as qc.Provider);
312
+ assert.equal(connected.address, wallet.address);
313
+ assert.equal(connected.provider, fakeProvider);
314
+ });
315
+
316
+ it("sendTransaction uses provider.sendTransaction with signed raw tx (no broadcast in test)", async () => {
317
+ await Initialize(null);
318
+ const calls = { send: 0, raw: null as string | null };
319
+ const fakeProvider = {
320
+ chainId: 123123,
321
+ getTransactionCount: async () => 0,
322
+ sendTransaction: async (raw: string) => {
323
+ calls.send++;
324
+ calls.raw = raw;
325
+ return { hash: "0x" + "22".repeat(32), wait: async () => ({ blockNumber: 1 }) };
326
+ },
327
+ };
328
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider as unknown as qc.Provider);
329
+ const to = qc.Wallet.createRandom().address;
330
+ const resp = await wallet.sendTransaction({ to, value: 0n, gasLimit: 21000, nonce: 0 });
331
+ assert.equal(calls.send, 1);
332
+ assert.equal(typeof calls.raw, "string");
333
+ assert.ok(calls.raw!.startsWith("0x"));
334
+ assert.ok(resp && resp.hash);
335
+ });
336
+
337
+ it("NonceManager caches nonce and increments between sends (offline)", async () => {
338
+ await Initialize(null);
339
+ const calls = { getNonce: 0, nonces: [] as number[] };
340
+ const fakeProvider = {
341
+ chainId: 123123,
342
+ getTransactionCount: async () => {
343
+ calls.getNonce++;
344
+ return 10;
345
+ },
346
+ sendTransaction: async () => ({ hash: "0x" + "33".repeat(32), wait: async () => ({ blockNumber: 1 }) }),
347
+ };
348
+ const wallet = qc.Wallet.fromEncryptedJsonSync(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE, fakeProvider as unknown as qc.Provider);
349
+ const nm = new qc.NonceManager(wallet);
350
+
351
+ const originalSend = wallet.sendTransaction.bind(wallet);
352
+ wallet.sendTransaction = async (tx: Parameters<typeof wallet.sendTransaction>[0]) => {
353
+ calls.nonces.push(tx.nonce as number);
354
+ return originalSend(tx);
355
+ };
356
+
357
+ const to = qc.Wallet.createRandom().address;
358
+ await nm.sendTransaction({ to, value: 0n, gasLimit: 21000 });
359
+ await nm.sendTransaction({ to, value: 0n, gasLimit: 21000 });
360
+
361
+ assert.equal(calls.getNonce, 1);
362
+ assert.deepEqual(calls.nonces, [10, 11]);
363
+ });
364
+
365
+ it("VoidSigner exposes getAddress()", async () => {
366
+ await Initialize(null);
367
+ const addr = qc.Wallet.createRandom().address;
368
+ const vs = new qc.VoidSigner(addr, null);
369
+ assert.equal(await vs.getAddress(), addr.toLowerCase());
370
+ });
371
+
372
+ it("resolveAddress supports string, Addressable, and Promise inputs", async () => {
373
+ await Initialize(null);
374
+ const wallet = qc.Wallet.createRandom();
375
+ assert.equal(qc.resolveAddress(wallet.address), wallet.address.toLowerCase());
376
+ assert.equal(await qc.resolveAddress(wallet), wallet.address.toLowerCase());
377
+ assert.equal(await qc.resolveAddress(Promise.resolve(wallet.address)), wallet.address.toLowerCase());
378
+ });
379
+ });
@@ -1,82 +1,85 @@
1
- /**
2
- * @testCategory unit
3
- * @blockchainRequired false
4
- * @transactional false
5
- * @description BrowserProvider (EIP-1193 wrapper) + debug event sink validation
6
- */
7
-
8
- const { describe, it } = require("node:test");
9
- const assert = require("node:assert/strict");
10
-
11
- const qc = require("../../index");
12
-
13
- describe("BrowserProvider", () => {
14
- it("wraps an EIP-1193 provider and emits debug events", async () => {
15
- /** @type {any[]} */
16
- const calls = [];
17
-
18
- const fakeEip1193 = {
19
- request: async ({ method, params }) => {
20
- calls.push({ method, params });
21
- if (method === "eth_accounts") {
22
- return ["0x" + "11".repeat(32)];
23
- }
24
- if (method === "eth_blockNumber") {
25
- return "0x10";
26
- }
27
- if (method === "eth_getBlockByNumber") {
28
- // params: [ "latest", false ]
29
- return {
30
- number: "0x10",
31
- hash: "0x" + "aa".repeat(32),
32
- parentHash: "0x" + "bb".repeat(32),
33
- timestamp: "0x1",
34
- transactions: [],
35
- };
36
- }
37
- throw new Error(`unsupported method: ${method}`);
38
- },
39
- };
40
-
41
- const provider = new qc.BrowserProvider(fakeEip1193);
42
-
43
- /** @type {any[]} */
44
- const debug = [];
45
- provider.on("debug", (ev) => debug.push(ev));
46
-
47
- const bn = await provider.getBlockNumber();
48
- assert.equal(bn, 16);
49
-
50
- const latest = await provider.getBlock("latest");
51
- assert.equal(latest.number, 16);
52
- assert.ok(typeof latest.hash === "string");
53
-
54
- const signer = await provider.getSigner();
55
- const addr = await signer.getAddress();
56
- assert.equal(addr.toLowerCase(), ("0x" + "11".repeat(32)).toLowerCase());
57
- assert.equal(await provider.hasSigner(addr), true);
58
-
59
- // Validate calls shape
60
- assert.deepEqual(
61
- calls.map((c) => c.method),
62
- ["eth_blockNumber", "eth_getBlockByNumber", "eth_accounts", "eth_accounts"],
63
- );
64
-
65
- // Validate debug event sink: send+receive per request in order
66
- const actions = debug.map((d) => d && d.action);
67
- assert.deepEqual(actions, [
68
- "sendEip1193Payload",
69
- "receiveEip1193Result",
70
- "sendEip1193Payload",
71
- "receiveEip1193Result",
72
- "sendEip1193Payload",
73
- "receiveEip1193Result",
74
- "sendEip1193Payload",
75
- "receiveEip1193Result",
76
- ]);
77
-
78
- assert.equal(debug[0].payload.method, "eth_blockNumber");
79
- assert.equal(debug[2].payload.method, "eth_getBlockByNumber");
80
- });
81
- });
82
-
1
+ /**
2
+ * @testCategory unit
3
+ * @blockchainRequired false
4
+ * @transactional false
5
+ * @description BrowserProvider (EIP-1193 wrapper) + debug event sink validation
6
+ */
7
+
8
+ const { describe, it } = require("node:test");
9
+ const assert = require("node:assert/strict");
10
+
11
+ const qc = require("../../index");
12
+ const { logSuite, logTest } = require("../verbose-logger");
13
+
14
+ describe("BrowserProvider", () => {
15
+ logSuite("BrowserProvider");
16
+ it("wraps an EIP-1193 provider and emits debug events", async () => {
17
+ logTest("wraps an EIP-1193 provider and emits debug events", {});
18
+ /** @type {any[]} */
19
+ const calls = [];
20
+
21
+ const fakeEip1193 = {
22
+ request: async ({ method, params }) => {
23
+ calls.push({ method, params });
24
+ if (method === "eth_accounts") {
25
+ return ["0x" + "11".repeat(32)];
26
+ }
27
+ if (method === "eth_blockNumber") {
28
+ return "0x10";
29
+ }
30
+ if (method === "eth_getBlockByNumber") {
31
+ // params: [ "latest", false ]
32
+ return {
33
+ number: "0x10",
34
+ hash: "0x" + "aa".repeat(32),
35
+ parentHash: "0x" + "bb".repeat(32),
36
+ timestamp: "0x1",
37
+ transactions: [],
38
+ };
39
+ }
40
+ throw new Error(`unsupported method: ${method}`);
41
+ },
42
+ };
43
+
44
+ const provider = new qc.BrowserProvider(fakeEip1193);
45
+
46
+ /** @type {any[]} */
47
+ const debug = [];
48
+ provider.on("debug", (ev) => debug.push(ev));
49
+
50
+ const bn = await provider.getBlockNumber();
51
+ assert.equal(bn, 16);
52
+
53
+ const latest = await provider.getBlock("latest");
54
+ assert.equal(latest.number, 16);
55
+ assert.ok(typeof latest.hash === "string");
56
+
57
+ const signer = await provider.getSigner();
58
+ const addr = await signer.getAddress();
59
+ assert.equal(addr.toLowerCase(), ("0x" + "11".repeat(32)).toLowerCase());
60
+ assert.equal(await provider.hasSigner(addr), true);
61
+
62
+ // Validate calls shape
63
+ assert.deepEqual(
64
+ calls.map((c) => c.method),
65
+ ["eth_blockNumber", "eth_getBlockByNumber", "eth_accounts", "eth_accounts"],
66
+ );
67
+
68
+ // Validate debug event sink: send+receive per request in order
69
+ const actions = debug.map((d) => d && d.action);
70
+ assert.deepEqual(actions, [
71
+ "sendEip1193Payload",
72
+ "receiveEip1193Result",
73
+ "sendEip1193Payload",
74
+ "receiveEip1193Result",
75
+ "sendEip1193Payload",
76
+ "receiveEip1193Result",
77
+ "sendEip1193Payload",
78
+ "receiveEip1193Result",
79
+ ]);
80
+
81
+ assert.equal(debug[0].payload.method, "eth_blockNumber");
82
+ assert.equal(debug[2].payload.method, "eth_getBlockByNumber");
83
+ });
84
+ });
85
+
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @testCategory unit
3
+ * @blockchainRequired false
4
+ * @transactional false
5
+ * @description BrowserProvider (EIP-1193 wrapper) + debug event sink validation
6
+ */
7
+
8
+ import { describe, it } from "node:test";
9
+ import assert from "node:assert/strict";
10
+
11
+ import qc from "../../index";
12
+ import { logSuite, logTest } from "../verbose-logger";
13
+
14
+ describe("BrowserProvider", () => {
15
+ logSuite("BrowserProvider");
16
+ it("wraps an EIP-1193 provider and emits debug events", async () => {
17
+ logTest("wraps an EIP-1193 provider and emits debug events", {});
18
+ const calls: { method: string; params?: unknown }[] = [];
19
+
20
+ const fakeEip1193 = {
21
+ request: async ({ method, params }: { method: string; params?: unknown }) => {
22
+ calls.push({ method, params });
23
+ if (method === "eth_accounts") {
24
+ return ["0x" + "11".repeat(32)];
25
+ }
26
+ if (method === "eth_blockNumber") {
27
+ return "0x10";
28
+ }
29
+ if (method === "eth_getBlockByNumber") {
30
+ return {
31
+ number: "0x10",
32
+ hash: "0x" + "aa".repeat(32),
33
+ parentHash: "0x" + "bb".repeat(32),
34
+ timestamp: "0x1",
35
+ transactions: [],
36
+ };
37
+ }
38
+ throw new Error(`unsupported method: ${method}`);
39
+ },
40
+ };
41
+
42
+ const provider = new qc.BrowserProvider(fakeEip1193);
43
+
44
+ const debug: { action?: string; payload?: { method: string } }[] = [];
45
+ provider.on("debug", (ev) => debug.push(ev));
46
+
47
+ const bn = await provider.getBlockNumber();
48
+ assert.equal(bn, 16);
49
+
50
+ const latest = await provider.getBlock("latest");
51
+ assert.equal(latest.number, 16);
52
+ assert.ok(typeof latest.hash === "string");
53
+
54
+ const signer = await provider.getSigner();
55
+ const addr = await signer.getAddress();
56
+ assert.equal(addr.toLowerCase(), ("0x" + "11".repeat(32)).toLowerCase());
57
+ assert.equal(await provider.hasSigner(addr), true);
58
+
59
+ assert.deepEqual(
60
+ calls.map((c) => c.method),
61
+ ["eth_blockNumber", "eth_getBlockByNumber", "eth_accounts", "eth_accounts"],
62
+ );
63
+
64
+ const actions = debug.map((d) => d && d.action);
65
+ assert.deepEqual(actions, [
66
+ "sendEip1193Payload",
67
+ "receiveEip1193Result",
68
+ "sendEip1193Payload",
69
+ "receiveEip1193Result",
70
+ "sendEip1193Payload",
71
+ "receiveEip1193Result",
72
+ "sendEip1193Payload",
73
+ "receiveEip1193Result",
74
+ ]);
75
+
76
+ assert.equal(debug[0].payload!.method, "eth_blockNumber");
77
+ assert.equal(debug[2].payload!.method, "eth_getBlockByNumber");
78
+ });
79
+ });