quantumcoin 7.0.10 → 7.0.11
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.
- package/README-SDK.md +0 -5
- package/README.md +1 -3
- package/SPEC.md +2 -63
- package/config.js +10 -2
- package/examples/example.js +0 -5
- package/examples/example.ts +0 -5
- package/examples/node_modules/.bin/esbuild +16 -0
- package/examples/node_modules/.bin/esbuild.cmd +17 -0
- package/examples/node_modules/.bin/esbuild.ps1 +28 -0
- package/examples/node_modules/.bin/sdkgen +16 -0
- package/examples/node_modules/.bin/sdkgen.cmd +17 -0
- package/examples/node_modules/.bin/sdkgen.ps1 +28 -0
- package/examples/node_modules/.bin/tsx +16 -0
- package/examples/node_modules/.bin/tsx.cmd +17 -0
- package/examples/node_modules/.bin/tsx.ps1 +28 -0
- package/examples/node_modules/.package-lock.json +235 -0
- package/examples/node_modules/@esbuild/win32-x64/README.md +3 -0
- package/examples/node_modules/@esbuild/win32-x64/esbuild.exe +0 -0
- package/examples/node_modules/@esbuild/win32-x64/package.json +20 -0
- package/examples/node_modules/esbuild/LICENSE.md +21 -0
- package/examples/node_modules/esbuild/README.md +3 -0
- package/examples/node_modules/esbuild/bin/esbuild +223 -0
- package/examples/node_modules/esbuild/install.js +289 -0
- package/examples/node_modules/esbuild/lib/main.d.ts +716 -0
- package/examples/node_modules/esbuild/lib/main.js +2532 -0
- package/examples/node_modules/esbuild/package.json +49 -0
- package/examples/node_modules/get-tsconfig/LICENSE +21 -0
- package/examples/node_modules/get-tsconfig/README.md +235 -0
- package/examples/node_modules/get-tsconfig/dist/index.cjs +7 -0
- package/examples/node_modules/get-tsconfig/dist/index.d.cts +2088 -0
- package/examples/node_modules/get-tsconfig/dist/index.d.mts +2088 -0
- package/examples/node_modules/get-tsconfig/dist/index.mjs +7 -0
- package/examples/node_modules/get-tsconfig/package.json +46 -0
- package/examples/node_modules/quantum-coin-js-sdk/.github/workflows/publish-npmjs.yaml +22 -0
- package/examples/node_modules/quantum-coin-js-sdk/LICENSE +21 -0
- package/examples/node_modules/quantum-coin-js-sdk/LICENSE-wasm_exec.js.txt +30 -0
- package/examples/node_modules/quantum-coin-js-sdk/README.md +1665 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/README.md +14 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/conversion-example.js +19 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-create-contract.js +396 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-encode-decode-rlp.js +225 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-event-pack-unpack.js +391 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-misc.js +101 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-rpc-send-signRawTransaction.js +318 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-rpc-send.js +116 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-send.js +70 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-token-pack-unpack.js +961 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-wallet-version4.js +35 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example-wallet.js +43 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/example.js +405 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/package-lock.json +134 -0
- package/examples/node_modules/quantum-coin-js-sdk/example/package.json +15 -0
- package/examples/node_modules/quantum-coin-js-sdk/index.d.ts +1024 -0
- package/examples/node_modules/quantum-coin-js-sdk/index.js +3062 -0
- package/examples/node_modules/quantum-coin-js-sdk/package.json +34 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-32.json +1 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-36.json +1 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/encrypted-48.json +1 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/generate-verify-vectors.js +91 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/non-transactional.preinit.test.js +41 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/non-transactional.test.js +686 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/sign-raw-keytype5-context-null.test.js +107 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/sign-raw-transaction.test.js +196 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/sign-verify.test.js +311 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/transactional.relay.test.js +131 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/transactional.rpc.test.js +103 -0
- package/examples/node_modules/quantum-coin-js-sdk/tests/verify-vectors.json +95035 -0
- package/examples/node_modules/quantum-coin-js-sdk/wasmBase64.d.ts +9 -0
- package/examples/node_modules/quantum-coin-js-sdk/wasmBase64.js +16 -0
- package/examples/node_modules/quantum-coin-js-sdk/wasm_exec.d.ts +0 -0
- package/examples/node_modules/quantum-coin-js-sdk/wasm_exec.js +587 -0
- package/examples/node_modules/resolve-pkg-maps/LICENSE +21 -0
- package/examples/node_modules/resolve-pkg-maps/README.md +216 -0
- package/examples/node_modules/resolve-pkg-maps/dist/index.cjs +1 -0
- package/examples/node_modules/resolve-pkg-maps/dist/index.d.cts +11 -0
- package/examples/node_modules/resolve-pkg-maps/dist/index.d.mts +11 -0
- package/examples/node_modules/resolve-pkg-maps/dist/index.mjs +1 -0
- package/examples/node_modules/resolve-pkg-maps/package.json +42 -0
- package/examples/node_modules/seed-words/.github/workflows/publish-npmjs.yaml +22 -0
- package/examples/node_modules/seed-words/BUILD.md +7 -0
- package/examples/node_modules/seed-words/LICENSE +121 -0
- package/examples/node_modules/seed-words/README.md +67 -0
- package/examples/node_modules/seed-words/dist/seedwords.d.ts +39 -0
- package/examples/node_modules/seed-words/package.json +27 -0
- package/examples/node_modules/seed-words/seedwords.js +315 -0
- package/examples/node_modules/seed-words/seedwords.txt +65536 -0
- package/examples/node_modules/seed-words/tsconfig.json +21 -0
- package/examples/node_modules/tsx/LICENSE +21 -0
- package/examples/node_modules/tsx/README.md +32 -0
- package/examples/node_modules/tsx/dist/cjs/api/index.cjs +1 -0
- package/examples/node_modules/tsx/dist/cjs/api/index.d.cts +35 -0
- package/examples/node_modules/tsx/dist/cjs/api/index.d.mts +35 -0
- package/examples/node_modules/tsx/dist/cjs/api/index.mjs +1 -0
- package/examples/node_modules/tsx/dist/cjs/index.cjs +1 -0
- package/examples/node_modules/tsx/dist/cjs/index.mjs +1 -0
- package/examples/node_modules/tsx/dist/cli.cjs +54 -0
- package/examples/node_modules/tsx/dist/cli.mjs +55 -0
- package/examples/node_modules/tsx/dist/client-BQVF1NaW.mjs +1 -0
- package/examples/node_modules/tsx/dist/client-D6NvIMSC.cjs +1 -0
- package/examples/node_modules/tsx/dist/esm/api/index.cjs +1 -0
- package/examples/node_modules/tsx/dist/esm/api/index.d.cts +35 -0
- package/examples/node_modules/tsx/dist/esm/api/index.d.mts +35 -0
- package/examples/node_modules/tsx/dist/esm/api/index.mjs +1 -0
- package/examples/node_modules/tsx/dist/esm/index.cjs +2 -0
- package/examples/node_modules/tsx/dist/esm/index.mjs +2 -0
- package/examples/node_modules/tsx/dist/get-pipe-path-BHW2eJdv.mjs +1 -0
- package/examples/node_modules/tsx/dist/get-pipe-path-BoR10qr8.cjs +1 -0
- package/examples/node_modules/tsx/dist/index-7AaEi15b.mjs +14 -0
- package/examples/node_modules/tsx/dist/index-BWFBUo6r.cjs +1 -0
- package/examples/node_modules/tsx/dist/index-gbaejti9.mjs +1 -0
- package/examples/node_modules/tsx/dist/index-gckBtVBf.cjs +14 -0
- package/examples/node_modules/tsx/dist/lexer-DQCqS3nf.mjs +3 -0
- package/examples/node_modules/tsx/dist/lexer-DgIbo0BU.cjs +3 -0
- package/examples/node_modules/tsx/dist/loader.cjs +1 -0
- package/examples/node_modules/tsx/dist/loader.mjs +1 -0
- package/examples/node_modules/tsx/dist/node-features-_8ZFwP_x.mjs +1 -0
- package/examples/node_modules/tsx/dist/node-features-roYmp9jK.cjs +1 -0
- package/examples/node_modules/tsx/dist/package-CeBgXWuR.mjs +1 -0
- package/examples/node_modules/tsx/dist/package-Dxt5kIHw.cjs +1 -0
- package/examples/node_modules/tsx/dist/patch-repl.cjs +1 -0
- package/examples/node_modules/tsx/dist/patch-repl.mjs +1 -0
- package/examples/node_modules/tsx/dist/preflight.cjs +1 -0
- package/examples/node_modules/tsx/dist/preflight.mjs +1 -0
- package/examples/node_modules/tsx/dist/register-2sWVXuRQ.cjs +1 -0
- package/examples/node_modules/tsx/dist/register-B7jrtLTO.mjs +1 -0
- package/examples/node_modules/tsx/dist/register-CFH5oNdT.mjs +4 -0
- package/examples/node_modules/tsx/dist/register-D46fvsV_.cjs +4 -0
- package/examples/node_modules/tsx/dist/repl.cjs +3 -0
- package/examples/node_modules/tsx/dist/repl.mjs +3 -0
- package/examples/node_modules/tsx/dist/require-D4F1Lv60.cjs +1 -0
- package/examples/node_modules/tsx/dist/require-DQxpCAr4.mjs +1 -0
- package/examples/node_modules/tsx/dist/suppress-warnings.cjs +1 -0
- package/examples/node_modules/tsx/dist/suppress-warnings.mjs +1 -0
- package/examples/node_modules/tsx/dist/temporary-directory-B83uKxJF.cjs +1 -0
- package/examples/node_modules/tsx/dist/temporary-directory-CwHp0_NW.mjs +1 -0
- package/examples/node_modules/tsx/dist/types-Cxp8y2TL.d.ts +5 -0
- package/examples/node_modules/tsx/package.json +68 -0
- package/examples/offline-signing.js +0 -2
- package/examples/offline-signing.ts +0 -1
- package/examples/package-lock.json +422 -73
- package/examples/package.json +1 -1
- package/examples/wallet-offline.js +1 -9
- package/examples/wallet-offline.ts +1 -9
- package/generate-sdk.js +4 -6
- package/package.json +2 -2
- package/src/abi/interface.js +13 -7
- package/src/abi/js-abi-coder.js +23 -18
- package/src/constants.d.ts +0 -5
- package/src/constants.js +0 -7
- package/src/contract/contract-factory.js +9 -3
- package/src/contract/contract.js +9 -3
- package/src/errors/index.js +12 -0
- package/src/index.d.ts +0 -3
- package/src/providers/extra-providers.js +20 -6
- package/src/providers/json-rpc-provider.js +15 -5
- package/src/providers/provider.d.ts +0 -2
- package/src/providers/provider.js +1 -3
- package/src/utils/address.d.ts +0 -14
- package/src/utils/address.js +12 -49
- package/src/utils/hashing.d.ts +0 -6
- package/src/utils/hashing.js +8 -23
- package/src/utils/index.d.ts +0 -3
- package/src/utils/rlp.js +7 -4
- package/src/wallet/wallet.d.ts +2 -13
- package/src/wallet/wallet.js +116 -97
- package/test/security/malformed-input.test.js +295 -1
- package/test/unit/address-wallet.test.js +188 -129
- package/test/unit/address-wallet.test.ts +187 -128
- package/test/unit/hashing.test.js +0 -11
- package/test/unit/hashing.test.ts +0 -11
- package/test/unit/providers.test.js +3 -1
- package/test/unit/providers.test.ts +3 -1
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
const { describe, test, before } = require('node:test');
|
|
2
|
+
const assert = require('node:assert/strict');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
// Tests are required to live under `tests/` per project convention.
|
|
7
|
+
// These are the "non-transactional" tests: offline operations + read-only relay/RPC calls.
|
|
8
|
+
|
|
9
|
+
const qcsdk = require('..');
|
|
10
|
+
|
|
11
|
+
const MAINNET_CHAIN_ID = 123123;
|
|
12
|
+
const READ_RELAY_URL = 'https://sdk.readrelay.quantumcoinapi.com';
|
|
13
|
+
const WRITE_RELAY_URL = 'https://sdk.writerelay.quantumcoinapi.com';
|
|
14
|
+
const PUBLIC_RPC_URL = 'https://public.rpc.quantumcoinapi.com';
|
|
15
|
+
|
|
16
|
+
const VALID_ADDRESS_EXAMPLE =
|
|
17
|
+
'0x6f605c4142f1cb037f967101a5b28ccd00b27cce4516190356baaf284d20e667';
|
|
18
|
+
const VALID_ADDRESS_EXAMPLE_UPPER =
|
|
19
|
+
'0X6F605C4142F1CB037F967101A5B28CCD00B27CCE4516190356BAAF284D20E667';
|
|
20
|
+
const TO_ADDRESS_EXAMPLE =
|
|
21
|
+
'0x8293cd9b6ac502d2fe077b0c157dad39f36a5e546525b053151dced633634612';
|
|
22
|
+
const ACCOUNT_ADDRESS_EXAMPLE =
|
|
23
|
+
'0x0000000000000000000000000000000000000000000000000000000000001000';
|
|
24
|
+
const ACCOUNT_TX_LIST_EXAMPLE =
|
|
25
|
+
'0x0000000000000000000000000000000000000000000000000000000000002000';
|
|
26
|
+
const TX_HASH_EXAMPLE =
|
|
27
|
+
'0xe6fbabc178adaaab6b9dbda086de53deaced1d6fe40e7db9539fe9e85695d1be';
|
|
28
|
+
|
|
29
|
+
// Example seed words (48) from `example/example.js`
|
|
30
|
+
const SEED_WORD_LIST =
|
|
31
|
+
'servetize,redmation,suaveton,dreadtolk,rondial,pondicle,miscoil,teaguery,dylodecid,portnel,mantical,slapware,sluthike,tactise,crierial,tajluvki,pranicum,sockcup,stacksong,duerling,genogram,peasate,pulubly,skimpop,feldtail,saprostal,crabrock,radiment,dolocsin,strigemen,juryeuk,fextial,merunized,tangienti,stylocyte,plumvieve,bobstike,nosecrown,acudemy,gripstick,lacreous,marculade,sporculum,outslope,bioburden,trompong,sidelay,finchage'
|
|
32
|
+
.split(',');
|
|
33
|
+
|
|
34
|
+
// Example wallet created with external wallet (from examples)
|
|
35
|
+
const EXAMPLE_WALLET_ENCRYPTED_JSON =
|
|
36
|
+
'{"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}';
|
|
37
|
+
const EXAMPLE_WALLET_PASSPHRASE = 'QuantumCoinExample123!';
|
|
38
|
+
|
|
39
|
+
// Fixture for "wallet test" (same as example wallet)
|
|
40
|
+
const TEST_WALLET_ENCRYPTED_JSON = EXAMPLE_WALLET_ENCRYPTED_JSON;
|
|
41
|
+
const TEST_WALLET_PASSPHRASE = EXAMPLE_WALLET_PASSPHRASE;
|
|
42
|
+
|
|
43
|
+
// Fixture for seed-words address test
|
|
44
|
+
const TEST_SEED_WORDS = [
|
|
45
|
+
'cylamidal', 'suculate', 'sealmate', 'radiploid', 'equifaxis', 'and', 'antipoise', 'stitchesy', 'perelade', 'lite',
|
|
46
|
+
'gourtarel', 'thursat', 'overdrome', 'cogulate', 'nonviva', 'stewnut', 'floribund', 'enduivist', 'decatary', 'elvenwort',
|
|
47
|
+
'indoucate', 'ravelent', 'vocalus', 'wetshirt', 'rutatory', 'percect', 'breaktout', 'corpation', 'myricorus', 'veofreat',
|
|
48
|
+
'junkard', 'supercarp', 'sukerus', 'tautang', 'facetype', 'shishkin', 'insulal', 'hobstone', 'stumbed', 'tecutonic',
|
|
49
|
+
'jumplike', 'hegwirth', 'idea', 'bhagatpur', 'pavastava', 'kukuluan', 'mageiline', 'extranite',
|
|
50
|
+
];
|
|
51
|
+
const TEST_SEED_ADDRESS = '0x3Ce22c0e2714196734E42B0D4D5AD11284260502A560e46c2Cd857391564142F'.toLowerCase();
|
|
52
|
+
|
|
53
|
+
// First 32 and 36 words from TEST_SEED_WORDS (for deterministic address tests)
|
|
54
|
+
const TEST_SEED_WORDS_32 = TEST_SEED_WORDS.slice(0, 32);
|
|
55
|
+
const TEST_SEED_WORDS_36 = TEST_SEED_WORDS.slice(0, 36);
|
|
56
|
+
// Expected addresses for first 32/36 words (deterministic from test run)
|
|
57
|
+
const TEST_SEED_ADDRESS_32 = '0x38b12df2d4762a04a183f936c47747a1f13d0b0ba72066b43b4b6d7f776e9e25';
|
|
58
|
+
const TEST_SEED_ADDRESS_36 = '0x030e264c853bd859c53fae3ad6ef0e011dc799685e2b05d5efa7ac50f10ca075';
|
|
59
|
+
|
|
60
|
+
// Default test password for encrypt/decrypt in seed-wallet roundtrip tests
|
|
61
|
+
const SEED_WALLET_TEST_PASSPHRASE = TEST_WALLET_PASSPHRASE;
|
|
62
|
+
|
|
63
|
+
async function rpc(method, params) {
|
|
64
|
+
const response = await fetch(PUBLIC_RPC_URL, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: { 'Content-Type': 'application/json' },
|
|
67
|
+
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
|
|
68
|
+
});
|
|
69
|
+
assert.ok(response.ok, `RPC HTTP ${response.status}`);
|
|
70
|
+
return response.json();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isHex0x(str) {
|
|
74
|
+
return typeof str === 'string' && /^0x[0-9a-fA-F]*$/.test(str);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isHex(str) {
|
|
78
|
+
return typeof str === 'string' && /^[0-9a-fA-F]+$/.test(str);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** True if CIRCL WASM is loaded, newWallet() returns a wallet, and verifyWallet passes. */
|
|
82
|
+
function isCirclAvailable() {
|
|
83
|
+
const w = qcsdk.newWallet();
|
|
84
|
+
return (
|
|
85
|
+
typeof w === 'object' &&
|
|
86
|
+
w != null &&
|
|
87
|
+
w.privateKey != null &&
|
|
88
|
+
w.address != null &&
|
|
89
|
+
qcsdk.verifyWallet(w) === true
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hexToBytes(hex) {
|
|
94
|
+
assert.ok(typeof hex === 'string');
|
|
95
|
+
const h = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
96
|
+
assert.equal(h.length % 2, 0);
|
|
97
|
+
const out = [];
|
|
98
|
+
for (let i = 0; i < h.length; i += 2) out.push(parseInt(h.slice(i, i + 2), 16));
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
describe('non-transactional', () => {
|
|
103
|
+
test('exports: all classes are constructible (and not callable without new)', () => {
|
|
104
|
+
const classExports = [
|
|
105
|
+
'AccountDetails',
|
|
106
|
+
'AccountDetailsResult',
|
|
107
|
+
'AccountTransactionCompact',
|
|
108
|
+
'AccountTransactionsResult',
|
|
109
|
+
'BlockDetails',
|
|
110
|
+
'Config',
|
|
111
|
+
'EventLogEncodeResult',
|
|
112
|
+
'LatestBlockDetailsResult',
|
|
113
|
+
'ListAccountTransactionsResponse',
|
|
114
|
+
'PackUnpackResult',
|
|
115
|
+
'SendResult',
|
|
116
|
+
'TransactionDetails',
|
|
117
|
+
'TransactionDetailsResult',
|
|
118
|
+
'TransactionReceipt',
|
|
119
|
+
'TransactionSigningRequest',
|
|
120
|
+
'Wallet',
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
for (const name of classExports) {
|
|
124
|
+
assert.equal(typeof qcsdk[name], 'function', `${name} export missing`);
|
|
125
|
+
assert.throws(() => qcsdk[name](), TypeError, `${name} should require new`);
|
|
126
|
+
// Basic "positive" constructability check
|
|
127
|
+
assert.ok(new qcsdk[name](), `${name} should be new-able`);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
before(async () => {
|
|
132
|
+
const cfg = new qcsdk.Config(READ_RELAY_URL, WRITE_RELAY_URL, MAINNET_CHAIN_ID, '', '');
|
|
133
|
+
const initResult = await qcsdk.initialize(cfg);
|
|
134
|
+
assert.equal(initResult, true, 'SDK initialize should succeed');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('initialize: calling initialize twice returns false', async () => {
|
|
138
|
+
const cfg = new qcsdk.Config(READ_RELAY_URL, WRITE_RELAY_URL, MAINNET_CHAIN_ID, '', '');
|
|
139
|
+
const init2 = await qcsdk.initialize(cfg);
|
|
140
|
+
assert.equal(init2, false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('isAddressValid: accepts valid 0x/0X and rejects invalid', () => {
|
|
144
|
+
assert.equal(qcsdk.isAddressValid(VALID_ADDRESS_EXAMPLE), true);
|
|
145
|
+
assert.equal(qcsdk.isAddressValid(VALID_ADDRESS_EXAMPLE_UPPER), true);
|
|
146
|
+
assert.equal(qcsdk.isAddressValid('asfasdfasdfs'), false);
|
|
147
|
+
assert.equal(qcsdk.isAddressValid(null), false);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('wallet: newWallet/verifyWallet/serializeWallet/deserializeWallet roundtrip', () => {
|
|
151
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
152
|
+
const w1 = qcsdk.newWallet();
|
|
153
|
+
assert.ok(w1);
|
|
154
|
+
assert.equal(typeof w1.address, 'string');
|
|
155
|
+
assert.ok(w1.privateKey && (w1.privateKey.byteLength !== undefined || typeof w1.privateKey.length === 'number'));
|
|
156
|
+
assert.ok(w1.publicKey && (w1.publicKey.byteLength !== undefined || typeof w1.publicKey.length === 'number'));
|
|
157
|
+
assert.ok(w1.privateKey.length > 0);
|
|
158
|
+
assert.ok(w1.publicKey.length > 0);
|
|
159
|
+
assert.equal(qcsdk.verifyWallet(w1), true);
|
|
160
|
+
assert.equal(qcsdk.isAddressValid(w1.address), true);
|
|
161
|
+
|
|
162
|
+
const serialized = qcsdk.serializeWallet(w1);
|
|
163
|
+
assert.ok(serialized && typeof serialized === 'string');
|
|
164
|
+
const w2 = qcsdk.deserializeWallet(serialized);
|
|
165
|
+
assert.ok(w2);
|
|
166
|
+
assert.equal(w2.address.toLowerCase(), w1.address.toLowerCase());
|
|
167
|
+
assert.equal(qcsdk.verifyWallet(w2), true);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('wallet encrypted: serializeEncryptedWallet/deserializeEncryptedWallet', () => {
|
|
171
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
172
|
+
const passphrase = 'QuantumCoinExample123!';
|
|
173
|
+
const w1 = qcsdk.newWallet();
|
|
174
|
+
const enc = qcsdk.serializeEncryptedWallet(w1, passphrase);
|
|
175
|
+
assert.ok(enc && typeof enc === 'string');
|
|
176
|
+
|
|
177
|
+
const w2 = qcsdk.deserializeEncryptedWallet(enc, passphrase);
|
|
178
|
+
assert.ok(w2);
|
|
179
|
+
assert.equal(w2.address.toLowerCase(), w1.address.toLowerCase());
|
|
180
|
+
assert.equal(qcsdk.verifyWallet(w2), true);
|
|
181
|
+
|
|
182
|
+
// Negative: wrong passphrase
|
|
183
|
+
const wBad = qcsdk.deserializeEncryptedWallet(enc, passphrase + 'wrong');
|
|
184
|
+
assert.equal(wBad, null);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('wallet test', () => {
|
|
188
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
189
|
+
const wallet = qcsdk.deserializeEncryptedWallet(TEST_WALLET_ENCRYPTED_JSON, TEST_WALLET_PASSPHRASE);
|
|
190
|
+
assert.ok(wallet, 'deserializeEncryptedWallet should return a wallet');
|
|
191
|
+
assert.equal(typeof wallet.address, 'string');
|
|
192
|
+
assert.equal(wallet.address.toLowerCase(), '0x1a846abe71c8b989e8337c55d608be81c28ab3b2e40c83eaa2a68d516049aec6');
|
|
193
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
194
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('seed words: newWalletSeed/openWalletFromSeedWords (static fixture)', () => {
|
|
198
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
199
|
+
const seedWords = qcsdk.newWalletSeed();
|
|
200
|
+
assert.ok(seedWords);
|
|
201
|
+
assert.ok(Array.isArray(seedWords) || typeof seedWords === 'string');
|
|
202
|
+
|
|
203
|
+
// Positive: open deterministic wallet from seed words fixture (48-word legacy / hybrideds)
|
|
204
|
+
const seedWallet = qcsdk.openWalletFromSeedWords(SEED_WORD_LIST);
|
|
205
|
+
assert.ok(seedWallet);
|
|
206
|
+
assert.equal(qcsdk.verifyWallet(seedWallet), true);
|
|
207
|
+
assert.equal(qcsdk.isAddressValid(seedWallet.address), true);
|
|
208
|
+
|
|
209
|
+
// Negative: invalid seed input
|
|
210
|
+
assert.equal(qcsdk.openWalletFromSeedWords(['not', 'enough']), null);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('seed words: openWalletFromSeedWords TEST_SEED_WORDS yields TEST_SEED_ADDRESS', () => {
|
|
214
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
215
|
+
const wallet = qcsdk.openWalletFromSeedWords(TEST_SEED_WORDS);
|
|
216
|
+
assert.ok(wallet, 'openWalletFromSeedWords should return a wallet');
|
|
217
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS);
|
|
218
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
219
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test('seed words: first 32 words from TEST_SEED_WORDS — verifyWallet and isAddressValid (deterministic)', () => {
|
|
223
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
224
|
+
const wallet = qcsdk.openWalletFromSeedWords(TEST_SEED_WORDS_32);
|
|
225
|
+
assert.ok(wallet, 'openWalletFromSeedWords(first 32) should return a wallet');
|
|
226
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
227
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
228
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS_32);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('seed words: first 36 words from TEST_SEED_WORDS — verifyWallet and isAddressValid (deterministic)', () => {
|
|
232
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
233
|
+
const wallet = qcsdk.openWalletFromSeedWords(TEST_SEED_WORDS_36);
|
|
234
|
+
assert.ok(wallet, 'openWalletFromSeedWords(first 36) should return a wallet');
|
|
235
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
236
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
237
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS_36);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// --- openWalletFromSeed tests (raw seed byte arrays) ---
|
|
241
|
+
|
|
242
|
+
// Hardcoded seed byte arrays derived from TEST_SEED_WORDS via seed-words.getSeedArrayFromWordList
|
|
243
|
+
const TEST_SEED_ARRAY_48 = [49,159,218,142,198,66,182,182,73,216,5,119,6,71,216,42,164,55,124,237,92,81,228,227,156,0,38,189,152,58,215,177,80,252,71,86,51,210,70,33,106,200,184,26,246,139,249,41,191,104,163,253,21,26,43,108,146,94,243,204,112,236,219,139,218,249,224,255,76,150,203,7,108,119,101,70,217,112,225,190,112,169,98,168,104,223,14,235,161,192,118,167,128,203,76,59];
|
|
244
|
+
const TEST_SEED_ARRAY_32 = [49,159,218,142,198,66,182,182,73,216,5,119,6,71,216,42,164,55,124,237,92,81,228,227,156,0,38,189,152,58,215,177,80,252,71,86,51,210,70,33,106,200,184,26,246,139,249,41,191,104,163,253,21,26,43,108,146,94,243,204,112,236,219,139];
|
|
245
|
+
const TEST_SEED_ARRAY_36 = [49,159,218,142,198,66,182,182,73,216,5,119,6,71,216,42,164,55,124,237,92,81,228,227,156,0,38,189,152,58,215,177,80,252,71,86,51,210,70,33,106,200,184,26,246,139,249,41,191,104,163,253,21,26,43,108,146,94,243,204,112,236,219,139,218,249,224,255,76,150,203,7];
|
|
246
|
+
|
|
247
|
+
test('openWalletFromSeed: 96-byte seed produces expected address (hybrideds)', () => {
|
|
248
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
249
|
+
const wallet = qcsdk.openWalletFromSeed(TEST_SEED_ARRAY_48);
|
|
250
|
+
assert.ok(wallet, 'openWalletFromSeed should return a wallet for 96-byte seed');
|
|
251
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS);
|
|
252
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
253
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test('openWalletFromSeed: 64-byte seed produces expected address (hybrid)', () => {
|
|
257
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
258
|
+
const wallet = qcsdk.openWalletFromSeed(TEST_SEED_ARRAY_32);
|
|
259
|
+
assert.ok(wallet, 'openWalletFromSeed should return a wallet for 64-byte seed');
|
|
260
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS_32);
|
|
261
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
262
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('openWalletFromSeed: 72-byte seed produces expected address (hybrid5)', () => {
|
|
266
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
267
|
+
const wallet = qcsdk.openWalletFromSeed(TEST_SEED_ARRAY_36);
|
|
268
|
+
assert.ok(wallet, 'openWalletFromSeed should return a wallet for 72-byte seed');
|
|
269
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS_36);
|
|
270
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
271
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test('openWalletFromSeed: matches openWalletFromSeedWords for all three schemes', () => {
|
|
275
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
276
|
+
for (const [seedArray, seedWords] of [
|
|
277
|
+
[TEST_SEED_ARRAY_48, TEST_SEED_WORDS],
|
|
278
|
+
[TEST_SEED_ARRAY_32, TEST_SEED_WORDS_32],
|
|
279
|
+
[TEST_SEED_ARRAY_36, TEST_SEED_WORDS_36],
|
|
280
|
+
]) {
|
|
281
|
+
const fromSeed = qcsdk.openWalletFromSeed(seedArray);
|
|
282
|
+
const fromWords = qcsdk.openWalletFromSeedWords(seedWords);
|
|
283
|
+
assert.ok(fromSeed, 'openWalletFromSeed should return a wallet');
|
|
284
|
+
assert.ok(fromWords, 'openWalletFromSeedWords should return a wallet');
|
|
285
|
+
assert.equal(fromSeed.address.toLowerCase(), fromWords.address.toLowerCase());
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test('openWalletFromSeed: accepts Uint8Array input', () => {
|
|
290
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
291
|
+
const wallet = qcsdk.openWalletFromSeed(new Uint8Array(TEST_SEED_ARRAY_48));
|
|
292
|
+
assert.ok(wallet, 'openWalletFromSeed should accept Uint8Array');
|
|
293
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test('openWalletFromSeed: null input returns null', () => {
|
|
297
|
+
assert.equal(qcsdk.openWalletFromSeed(null), null);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test('openWalletFromSeed: undefined input returns null', () => {
|
|
301
|
+
assert.equal(qcsdk.openWalletFromSeed(undefined), null);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test('openWalletFromSeed: empty array returns null', () => {
|
|
305
|
+
assert.equal(qcsdk.openWalletFromSeed([]), null);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test('openWalletFromSeed: wrong length array returns null', () => {
|
|
309
|
+
assert.equal(qcsdk.openWalletFromSeed([1, 2, 3, 4, 5]), null);
|
|
310
|
+
assert.equal(qcsdk.openWalletFromSeed(new Array(63).fill(0)), null);
|
|
311
|
+
assert.equal(qcsdk.openWalletFromSeed(new Array(65).fill(0)), null);
|
|
312
|
+
assert.equal(qcsdk.openWalletFromSeed(new Array(71).fill(0)), null);
|
|
313
|
+
assert.equal(qcsdk.openWalletFromSeed(new Array(73).fill(0)), null);
|
|
314
|
+
assert.equal(qcsdk.openWalletFromSeed(new Array(95).fill(0)), null);
|
|
315
|
+
assert.equal(qcsdk.openWalletFromSeed(new Array(97).fill(0)), null);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test('openWalletFromSeed: non-array input returns null', () => {
|
|
319
|
+
assert.equal(qcsdk.openWalletFromSeed('not an array'), null);
|
|
320
|
+
assert.equal(qcsdk.openWalletFromSeed(12345), null);
|
|
321
|
+
assert.equal(qcsdk.openWalletFromSeed({}), null);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// --- serializeSeedAsEncryptedWallet tests ---
|
|
325
|
+
|
|
326
|
+
test('serializeSeedAsEncryptedWallet: 96-byte seed roundtrip — address and keys match', () => {
|
|
327
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
328
|
+
const json = qcsdk.serializeSeedAsEncryptedWallet(TEST_SEED_ARRAY_48, SEED_WALLET_TEST_PASSPHRASE);
|
|
329
|
+
assert.ok(json && typeof json === 'string', 'should return a JSON string');
|
|
330
|
+
const wallet = qcsdk.deserializeEncryptedWallet(json, SEED_WALLET_TEST_PASSPHRASE);
|
|
331
|
+
assert.ok(wallet, 'deserializeEncryptedWallet should return a wallet');
|
|
332
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS);
|
|
333
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
334
|
+
const ref = qcsdk.openWalletFromSeed(TEST_SEED_ARRAY_48);
|
|
335
|
+
assert.ok(ref);
|
|
336
|
+
assert.equal(wallet.publicKey.length, ref.publicKey.length);
|
|
337
|
+
for (let i = 0; i < wallet.publicKey.length; i++) assert.equal(wallet.publicKey[i], ref.publicKey[i]);
|
|
338
|
+
assert.equal(wallet.privateKey.length, ref.privateKey.length);
|
|
339
|
+
for (let i = 0; i < wallet.privateKey.length; i++) assert.equal(wallet.privateKey[i], ref.privateKey[i]);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test('serializeSeedAsEncryptedWallet: 64-byte seed roundtrip — address and keys match', () => {
|
|
343
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
344
|
+
const json = qcsdk.serializeSeedAsEncryptedWallet(TEST_SEED_ARRAY_32, SEED_WALLET_TEST_PASSPHRASE);
|
|
345
|
+
assert.ok(json && typeof json === 'string', 'should return a JSON string');
|
|
346
|
+
const wallet = qcsdk.deserializeEncryptedWallet(json, SEED_WALLET_TEST_PASSPHRASE);
|
|
347
|
+
assert.ok(wallet, 'deserializeEncryptedWallet should return a wallet');
|
|
348
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS_32);
|
|
349
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
350
|
+
const ref = qcsdk.openWalletFromSeed(TEST_SEED_ARRAY_32);
|
|
351
|
+
assert.ok(ref);
|
|
352
|
+
assert.equal(wallet.publicKey.length, ref.publicKey.length);
|
|
353
|
+
for (let i = 0; i < wallet.publicKey.length; i++) assert.equal(wallet.publicKey[i], ref.publicKey[i]);
|
|
354
|
+
assert.equal(wallet.privateKey.length, ref.privateKey.length);
|
|
355
|
+
for (let i = 0; i < wallet.privateKey.length; i++) assert.equal(wallet.privateKey[i], ref.privateKey[i]);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test('serializeSeedAsEncryptedWallet: 72-byte seed roundtrip — address and keys match', () => {
|
|
359
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded');
|
|
360
|
+
const json = qcsdk.serializeSeedAsEncryptedWallet(TEST_SEED_ARRAY_36, SEED_WALLET_TEST_PASSPHRASE);
|
|
361
|
+
assert.ok(json && typeof json === 'string', 'should return a JSON string');
|
|
362
|
+
const wallet = qcsdk.deserializeEncryptedWallet(json, SEED_WALLET_TEST_PASSPHRASE);
|
|
363
|
+
assert.ok(wallet, 'deserializeEncryptedWallet should return a wallet');
|
|
364
|
+
assert.equal(wallet.address.toLowerCase(), TEST_SEED_ADDRESS_36);
|
|
365
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
366
|
+
const ref = qcsdk.openWalletFromSeed(TEST_SEED_ARRAY_36);
|
|
367
|
+
assert.ok(ref);
|
|
368
|
+
assert.equal(wallet.publicKey.length, ref.publicKey.length);
|
|
369
|
+
for (let i = 0; i < wallet.publicKey.length; i++) assert.equal(wallet.publicKey[i], ref.publicKey[i]);
|
|
370
|
+
assert.equal(wallet.privateKey.length, ref.privateKey.length);
|
|
371
|
+
for (let i = 0; i < wallet.privateKey.length; i++) assert.equal(wallet.privateKey[i], ref.privateKey[i]);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test('serializeSeedAsEncryptedWallet: null seed returns null', () => {
|
|
375
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(null, SEED_WALLET_TEST_PASSPHRASE), null);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test('serializeSeedAsEncryptedWallet: wrong-length seed returns null', () => {
|
|
379
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(new Array(5).fill(0), SEED_WALLET_TEST_PASSPHRASE), null);
|
|
380
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(new Array(63).fill(0), SEED_WALLET_TEST_PASSPHRASE), null);
|
|
381
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(new Array(97).fill(0), SEED_WALLET_TEST_PASSPHRASE), null);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test('serializeSeedAsEncryptedWallet: null passphrase returns null', () => {
|
|
385
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(TEST_SEED_ARRAY_32, null), null);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
test('serializeSeedAsEncryptedWallet: short passphrase returns null', () => {
|
|
389
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(TEST_SEED_ARRAY_32, 'short'), null);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
test('serializeSeedAsEncryptedWallet: non-string passphrase returns null', () => {
|
|
393
|
+
assert.equal(qcsdk.serializeSeedAsEncryptedWallet(TEST_SEED_ARRAY_32, 12345), null);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Hardcoded encrypted wallet JSON (from openWalletFromSeedWords + serializeEncryptedWallet with SEED_WALLET_TEST_PASSPHRASE).
|
|
397
|
+
// Deserialize and verify addresses match. Uses fixtures in tests/ (encrypted-48.json, encrypted-32.json, encrypted-36.json).
|
|
398
|
+
test('seed words: deserializeEncryptedWallet from serialized 48/32/36 seed wallets — addresses match', () => {
|
|
399
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
400
|
+
const testsDir = __dirname;
|
|
401
|
+
const enc48 = fs.readFileSync(path.join(testsDir, 'encrypted-48.json'), 'utf8').trim();
|
|
402
|
+
const enc32 = fs.readFileSync(path.join(testsDir, 'encrypted-32.json'), 'utf8').trim();
|
|
403
|
+
const enc36 = fs.readFileSync(path.join(testsDir, 'encrypted-36.json'), 'utf8').trim();
|
|
404
|
+
for (const [enc, expectedAddress] of [
|
|
405
|
+
[enc48, TEST_SEED_ADDRESS],
|
|
406
|
+
[enc32, TEST_SEED_ADDRESS_32],
|
|
407
|
+
[enc36, TEST_SEED_ADDRESS_36],
|
|
408
|
+
]) {
|
|
409
|
+
const wallet = qcsdk.deserializeEncryptedWallet(enc, SEED_WALLET_TEST_PASSPHRASE);
|
|
410
|
+
assert.ok(wallet, 'deserializeEncryptedWallet should return a wallet');
|
|
411
|
+
assert.equal(wallet.address.toLowerCase(), expectedAddress);
|
|
412
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
413
|
+
assert.equal(qcsdk.isAddressValid(wallet.address), true);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test('publicKeyFromPrivateKey/addressFromPublicKey and signature helpers', () => {
|
|
418
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
419
|
+
const wallet = qcsdk.newWallet();
|
|
420
|
+
assert.ok(wallet);
|
|
421
|
+
assert.equal(qcsdk.verifyWallet(wallet), true);
|
|
422
|
+
|
|
423
|
+
const pubHex = qcsdk.publicKeyFromPrivateKey(wallet.privateKey);
|
|
424
|
+
assert.ok(pubHex && typeof pubHex === 'string');
|
|
425
|
+
assert.ok(isHex(pubHex), 'publicKeyFromPrivateKey returns hex (no 0x prefix)');
|
|
426
|
+
|
|
427
|
+
// Compare derived public key bytes to wallet publicKey bytes
|
|
428
|
+
const pubBytes = hexToBytes(pubHex);
|
|
429
|
+
assert.equal(pubBytes.length, wallet.publicKey.length);
|
|
430
|
+
for (let i = 0; i < pubBytes.length; i++) assert.equal(pubBytes[i], wallet.publicKey[i]);
|
|
431
|
+
|
|
432
|
+
// addressFromPublicKey should match wallet address
|
|
433
|
+
const addr = qcsdk.addressFromPublicKey(wallet.publicKey);
|
|
434
|
+
assert.equal(addr.toLowerCase(), wallet.address.toLowerCase());
|
|
435
|
+
|
|
436
|
+
// combinePublicKeySignature + publicKeyFromSignature roundtrip (use CIRCL hybrideds when available)
|
|
437
|
+
const digest = new TextEncoder().encode('verifyverifyverifyverifyverifyok'); // 32 bytes
|
|
438
|
+
assert.equal(digest.length, 32);
|
|
439
|
+
const g = typeof globalThis !== 'undefined' ? globalThis : typeof global !== 'undefined' ? global : {};
|
|
440
|
+
const circl = g.circl;
|
|
441
|
+
let sig;
|
|
442
|
+
if (circl && circl.hybrideds) {
|
|
443
|
+
const privU8 = wallet.privateKey instanceof Uint8Array ? wallet.privateKey : new Uint8Array(wallet.privateKey);
|
|
444
|
+
const sigRes = circl.hybrideds.signCompact(privU8, digest);
|
|
445
|
+
if (sigRes && sigRes.error) throw new Error('CIRCL sign failed: ' + sigRes.error);
|
|
446
|
+
sig = sigRes.result instanceof Uint8Array ? Array.from(sigRes.result) : sigRes.result;
|
|
447
|
+
} else {
|
|
448
|
+
// Skip roundtrip if CIRCL not loaded (e.g. WASM not yet CIRCL build)
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const combinedHex = qcsdk.combinePublicKeySignature(wallet.publicKey, sig);
|
|
452
|
+
assert.ok(combinedHex && typeof combinedHex === 'string' && isHex(combinedHex));
|
|
453
|
+
|
|
454
|
+
const combinedBytes = hexToBytes(combinedHex);
|
|
455
|
+
const recoveredPubHex = qcsdk.publicKeyFromSignature(digest, combinedBytes);
|
|
456
|
+
assert.ok(recoveredPubHex && typeof recoveredPubHex === 'string' && isHex(recoveredPubHex));
|
|
457
|
+
assert.equal(recoveredPubHex.toLowerCase(), pubHex.toLowerCase());
|
|
458
|
+
|
|
459
|
+
// Negative: wrong digest size
|
|
460
|
+
assert.equal(qcsdk.publicKeyFromSignature([1, 2, 3], combinedBytes), null);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test('RLP: encodeRlp/decodeRlp roundtrip and negative decode', () => {
|
|
464
|
+
// Note: current WASM DecodeRlp returns a JSON string where decoded bytes appear as boolean arrays.
|
|
465
|
+
// We validate that encode->decode is structurally consistent rather than matching the original JS value.
|
|
466
|
+
const enc = qcsdk.encodeRlp(['hello', 123, true]);
|
|
467
|
+
assert.equal(enc.error, '');
|
|
468
|
+
assert.ok(isHex0x(enc.result));
|
|
469
|
+
|
|
470
|
+
const dec = qcsdk.decodeRlp(enc.result);
|
|
471
|
+
assert.equal(dec.error, '');
|
|
472
|
+
const decoded = JSON.parse(dec.result);
|
|
473
|
+
assert.ok(Array.isArray(decoded));
|
|
474
|
+
assert.equal(decoded.length, 3);
|
|
475
|
+
assert.ok(Array.isArray(decoded[0]) && decoded[0].length === 5); // "hello" bytes -> 5 trues
|
|
476
|
+
assert.ok(Array.isArray(decoded[1]) && decoded[1].length >= 1);
|
|
477
|
+
assert.ok(Array.isArray(decoded[2]) && decoded[2].length >= 1);
|
|
478
|
+
assert.ok(decoded.flat(2).every((b) => typeof b === 'boolean'));
|
|
479
|
+
|
|
480
|
+
const bad = qcsdk.decodeRlp('not-hex');
|
|
481
|
+
assert.notEqual(bad.error, '');
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test('ABI pack/unpack: packMethodData/unpackMethodData via RPC eth_call', async () => {
|
|
485
|
+
// Minimal ERC20-like ABI used in examples
|
|
486
|
+
const erc20ABI = JSON.stringify([
|
|
487
|
+
{
|
|
488
|
+
name: 'balanceOf',
|
|
489
|
+
type: 'function',
|
|
490
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
491
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
492
|
+
stateMutability: 'view',
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
name: 'name',
|
|
496
|
+
type: 'function',
|
|
497
|
+
inputs: [],
|
|
498
|
+
outputs: [{ name: '', type: 'string' }],
|
|
499
|
+
stateMutability: 'view',
|
|
500
|
+
},
|
|
501
|
+
]);
|
|
502
|
+
|
|
503
|
+
const tokenAddress =
|
|
504
|
+
'0x1Bd75060B22686a9f32Af80BC02348c1BAeDBba06f47ad723885c92a6566B65d';
|
|
505
|
+
const holderAddress =
|
|
506
|
+
'0xd51773b5dde3f8e4d29ae42b5046510e2a11fd0c8e4175853d6227896eb445c6';
|
|
507
|
+
|
|
508
|
+
const pack = qcsdk.packMethodData(erc20ABI, 'balanceOf', holderAddress);
|
|
509
|
+
assert.equal(pack.error, '');
|
|
510
|
+
assert.ok(isHex0x(pack.result));
|
|
511
|
+
|
|
512
|
+
const call = await rpc('eth_call', [{ to: tokenAddress, data: pack.result }, 'latest']);
|
|
513
|
+
assert.ok(call && (call.result || call.error));
|
|
514
|
+
assert.ok(call.result && isHex0x(call.result), 'eth_call should return hex');
|
|
515
|
+
|
|
516
|
+
const unpack = qcsdk.unpackMethodData(erc20ABI, 'balanceOf', call.result);
|
|
517
|
+
assert.equal(unpack.error, '');
|
|
518
|
+
const parsed = JSON.parse(unpack.result);
|
|
519
|
+
assert.ok(Array.isArray(parsed));
|
|
520
|
+
assert.equal(typeof parsed[0], 'string');
|
|
521
|
+
|
|
522
|
+
// Negative: invalid ABI JSON
|
|
523
|
+
const badPack = qcsdk.packMethodData('not-json', 'balanceOf', holderAddress);
|
|
524
|
+
assert.notEqual(badPack.error, '');
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test('Event logs: encodeEventLog/decodeEventLog (Transfer)', () => {
|
|
528
|
+
const transferABI = JSON.stringify([
|
|
529
|
+
{
|
|
530
|
+
name: 'Transfer',
|
|
531
|
+
type: 'event',
|
|
532
|
+
anonymous: false,
|
|
533
|
+
inputs: [
|
|
534
|
+
{ name: 'from', type: 'address', indexed: true },
|
|
535
|
+
{ name: 'to', type: 'address', indexed: true },
|
|
536
|
+
{ name: 'value', type: 'uint256', indexed: false },
|
|
537
|
+
],
|
|
538
|
+
},
|
|
539
|
+
]);
|
|
540
|
+
|
|
541
|
+
const fromAddress =
|
|
542
|
+
'0xd51773b5dde3f8e4d29ae42b5046510e2a11fd0c8e4175853d6227896eb445c6';
|
|
543
|
+
const toAddress =
|
|
544
|
+
'0x1Bd75060B22686a9f32Af80BC02348c1BAeDBba06f47ad723885c92a6566B65d';
|
|
545
|
+
const value = '1000000000000000000';
|
|
546
|
+
|
|
547
|
+
const enc = qcsdk.encodeEventLog(transferABI, 'Transfer', fromAddress, toAddress, value);
|
|
548
|
+
assert.equal(enc.error, '');
|
|
549
|
+
assert.ok(enc.result);
|
|
550
|
+
assert.equal(Array.isArray(enc.result.topics), true);
|
|
551
|
+
assert.equal(enc.result.topics.length, 3);
|
|
552
|
+
assert.ok(isHex0x(enc.result.data));
|
|
553
|
+
|
|
554
|
+
const dec = qcsdk.decodeEventLog(transferABI, 'Transfer', enc.result.topics, enc.result.data);
|
|
555
|
+
assert.equal(dec.error, '');
|
|
556
|
+
const decoded = JSON.parse(dec.result);
|
|
557
|
+
assert.equal(decoded.from.toLowerCase(), fromAddress.toLowerCase());
|
|
558
|
+
assert.equal(decoded.to.toLowerCase(), toAddress.toLowerCase());
|
|
559
|
+
assert.equal(decoded.value, value);
|
|
560
|
+
|
|
561
|
+
// Negative: invalid ABI
|
|
562
|
+
const bad = qcsdk.decodeEventLog('not-json', 'Transfer', enc.result.topics, enc.result.data);
|
|
563
|
+
assert.notEqual(bad.error, '');
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
test('contract address calculation: createAddress + createAddress2 basic validity and determinism', () => {
|
|
567
|
+
const w = qcsdk.newWallet();
|
|
568
|
+
const a0 = qcsdk.createAddress(w.address, 0);
|
|
569
|
+
const a0b = qcsdk.createAddress(w.address, 0);
|
|
570
|
+
const a1 = qcsdk.createAddress(w.address, 1);
|
|
571
|
+
assert.ok(a0 && typeof a0 === 'string');
|
|
572
|
+
assert.ok(isHex0x(a0));
|
|
573
|
+
assert.equal(a0, a0b);
|
|
574
|
+
assert.notEqual(a0, a1);
|
|
575
|
+
|
|
576
|
+
// CREATE2
|
|
577
|
+
const salt = '0x' + '22'.repeat(32);
|
|
578
|
+
const initHash = '0x' + '11'.repeat(32);
|
|
579
|
+
const c2a = qcsdk.createAddress2(w.address, salt, initHash);
|
|
580
|
+
const c2b = qcsdk.createAddress2(w.address, salt, initHash);
|
|
581
|
+
assert.ok(c2a && isHex0x(c2a));
|
|
582
|
+
assert.equal(c2a, c2b);
|
|
583
|
+
|
|
584
|
+
// Negative: invalid nonce type / invalid params
|
|
585
|
+
assert.equal(qcsdk.createAddress(w.address, '0'), null);
|
|
586
|
+
assert.equal(qcsdk.createAddress2(null, salt, initHash), null);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
test('signing: signSendCoinTransaction and signRawTransaction validate inputs and produce tx data', async () => {
|
|
590
|
+
assert.ok(isCirclAvailable(), 'CIRCL WASM must be loaded and verifyWallet(newWallet()) must pass');
|
|
591
|
+
const wallet = qcsdk.newWallet();
|
|
592
|
+
assert.ok(wallet);
|
|
593
|
+
|
|
594
|
+
const signSend = await qcsdk.signSendCoinTransaction(wallet, TO_ADDRESS_EXAMPLE, '0', 0);
|
|
595
|
+
assert.equal(signSend.resultCode, 0);
|
|
596
|
+
assert.ok(isHex0x(signSend.txnHash));
|
|
597
|
+
assert.ok(isHex0x(signSend.txnData));
|
|
598
|
+
|
|
599
|
+
const txReq = new qcsdk.TransactionSigningRequest(
|
|
600
|
+
wallet,
|
|
601
|
+
TO_ADDRESS_EXAMPLE,
|
|
602
|
+
'0x0',
|
|
603
|
+
0,
|
|
604
|
+
null,
|
|
605
|
+
21000,
|
|
606
|
+
null,
|
|
607
|
+
MAINNET_CHAIN_ID,
|
|
608
|
+
);
|
|
609
|
+
const signRaw = qcsdk.signRawTransaction(txReq);
|
|
610
|
+
assert.equal(signRaw.resultCode, 0);
|
|
611
|
+
assert.ok(isHex0x(signRaw.txnHash));
|
|
612
|
+
assert.ok(isHex0x(signRaw.txnData));
|
|
613
|
+
|
|
614
|
+
// Negative: invalid to address and invalid remarks length
|
|
615
|
+
const signSendBad = await qcsdk.signSendCoinTransaction(wallet, 'bad', '1', 0);
|
|
616
|
+
assert.notEqual(signSendBad.resultCode, 0);
|
|
617
|
+
|
|
618
|
+
const longRemarks = '0x' + 'aa'.repeat(33); // > 32 bytes
|
|
619
|
+
const txReqBad = new qcsdk.TransactionSigningRequest(
|
|
620
|
+
wallet,
|
|
621
|
+
TO_ADDRESS_EXAMPLE,
|
|
622
|
+
'0x0',
|
|
623
|
+
0,
|
|
624
|
+
null,
|
|
625
|
+
21000,
|
|
626
|
+
longRemarks,
|
|
627
|
+
MAINNET_CHAIN_ID,
|
|
628
|
+
);
|
|
629
|
+
const signRawBad = qcsdk.signRawTransaction(txReqBad);
|
|
630
|
+
assert.notEqual(signRawBad.resultCode, 0);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
test('relay read-only APIs: getLatestBlockDetails/getAccountDetails/listAccountTransactions/getTransactionDetails', async () => {
|
|
634
|
+
const latest = await qcsdk.getLatestBlockDetails();
|
|
635
|
+
assert.ok(latest);
|
|
636
|
+
assert.equal(typeof latest.resultCode, 'number');
|
|
637
|
+
assert.equal(latest.resultCode, 0);
|
|
638
|
+
assert.ok(latest.blockDetails && typeof latest.blockDetails.blockNumber === 'number');
|
|
639
|
+
|
|
640
|
+
const acct = await qcsdk.getAccountDetails(ACCOUNT_ADDRESS_EXAMPLE);
|
|
641
|
+
assert.ok(acct);
|
|
642
|
+
assert.equal(typeof acct.resultCode, 'number');
|
|
643
|
+
// If the relay is healthy, this should be 0 for a valid address.
|
|
644
|
+
assert.equal(acct.resultCode, 0);
|
|
645
|
+
assert.ok(acct.accountDetails);
|
|
646
|
+
assert.equal(acct.accountDetails.address.toLowerCase(), ACCOUNT_ADDRESS_EXAMPLE.toLowerCase());
|
|
647
|
+
|
|
648
|
+
const txList = await qcsdk.listAccountTransactions(ACCOUNT_TX_LIST_EXAMPLE, 0);
|
|
649
|
+
assert.ok(txList);
|
|
650
|
+
assert.equal(typeof txList.resultCode, 'number');
|
|
651
|
+
assert.equal(txList.resultCode, 0);
|
|
652
|
+
assert.ok(txList.listAccountTransactionsResponse);
|
|
653
|
+
assert.equal(typeof txList.listAccountTransactionsResponse.pageCount, 'number');
|
|
654
|
+
|
|
655
|
+
const txd = await qcsdk.getTransactionDetails(TX_HASH_EXAMPLE);
|
|
656
|
+
assert.ok(txd);
|
|
657
|
+
assert.equal(typeof txd.resultCode, 'number');
|
|
658
|
+
// This should normally succeed; if the transaction no longer exists, it may be a 404.
|
|
659
|
+
if (txd.resultCode === 0) {
|
|
660
|
+
assert.ok(txd.transactionDetails);
|
|
661
|
+
assert.ok(isHex0x(txd.transactionDetails.hash));
|
|
662
|
+
} else {
|
|
663
|
+
// Negative-but-expected fallback: it must be a "not found" style response.
|
|
664
|
+
assert.ok(txd.response && typeof txd.response.status === 'number');
|
|
665
|
+
assert.equal(txd.response.status, 404);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Negative: invalid address/hash inputs
|
|
669
|
+
const badAcct = await qcsdk.getAccountDetails('bad');
|
|
670
|
+
assert.notEqual(badAcct.resultCode, 0);
|
|
671
|
+
const badList = await qcsdk.listAccountTransactions('bad', 0);
|
|
672
|
+
assert.notEqual(badList.resultCode, 0);
|
|
673
|
+
const badTx = await qcsdk.getTransactionDetails('bad');
|
|
674
|
+
assert.notEqual(badTx.resultCode, 0);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
test('transactional API negative validation (no network send): postTransaction/sendCoins', async () => {
|
|
678
|
+
const postNull = await qcsdk.postTransaction(null);
|
|
679
|
+
assert.ok(postNull);
|
|
680
|
+
assert.notEqual(postNull.resultCode, 0);
|
|
681
|
+
|
|
682
|
+
const sendBad = await qcsdk.sendCoins(null, TO_ADDRESS_EXAMPLE, '1', 0);
|
|
683
|
+
assert.notEqual(sendBad.resultCode, 0);
|
|
684
|
+
});
|
|
685
|
+
});
|
|
686
|
+
|