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
@@ -1,489 +1,500 @@
1
- /**
2
- * @fileoverview Wallet and signer implementations.
3
- *
4
- * The QuantumCoin.js wallet model mirrors ethers.js v6:
5
- * - AbstractSigner -> BaseWallet -> Wallet
6
- * - NonceManager wrapper
7
- *
8
- * Cryptographic operations are delegated to `quantum-coin-js-sdk` and its
9
- * PQC signing library.
10
- */
11
-
12
- const qcsdk = require("quantum-coin-js-sdk");
13
- const path = require("node:path");
14
- const { JsonRpcProvider } = require("../providers/json-rpc-provider");
15
- const { assertArgument, makeError } = require("../errors");
16
- const { arrayify, bytesToHex, hexToBytes, isHexString, normalizeHex, utf8ToBytes } = require("../internal/hex");
17
- const { sha256 } = require("../utils/hashing");
18
- const { getAddress } = require("../utils/address");
19
- const { WeiPerEther } = require("../constants");
20
-
21
- function _requireInitialized() {
22
- // eslint-disable-next-line global-require
23
- const { isInitialized } = require("../../config");
24
- if (!isInitialized()) {
25
- throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", { operation: "wallet" });
26
- }
27
- }
28
-
29
- function _getPqc() {
30
- // Prefer the PQC SDK installed as a direct dependency.
31
- // (Some environments may also bundle it under quantum-coin-js-sdk.)
32
- try {
33
- // eslint-disable-next-line global-require
34
- return require("quantum-coin-pqc-js-sdk");
35
- } catch (e1) {
36
- try {
37
- // Prefer the PQC SDK version bundled with quantum-coin-js-sdk, since that
38
- // combination is known to work together.
39
- const sdkEntry = require.resolve("quantum-coin-js-sdk");
40
- const sdkDir = path.dirname(sdkEntry);
41
- // eslint-disable-next-line global-require, import/no-dynamic-require
42
- return require(path.join(sdkDir, "node_modules", "quantum-coin-pqc-js-sdk"));
43
- } catch (e2) {
44
- throw makeError("PQC SDK not found. Ensure quantum-coin-pqc-js-sdk is installed.", "MODULE_NOT_FOUND", {
45
- operation: "wallet._getPqc",
46
- errors: [String(e1 && e1.message ? e1.message : e1), String(e2 && e2.message ? e2.message : e2)],
47
- });
48
- }
49
- }
50
- }
51
-
52
- function _bytesToNumberArray(bytes) {
53
- return Array.from(bytes);
54
- }
55
-
56
- function _hexToNumberArray(hex) {
57
- return _bytesToNumberArray(hexToBytes(hex));
58
- }
59
-
60
- /**
61
- * SigningKey wrapper (PQC private/public key bytes).
62
- */
63
- class SigningKey {
64
- /**
65
- * @param {Uint8Array} privateKeyBytes
66
- * @param {Uint8Array} publicKeyBytes
67
- */
68
- constructor(privateKeyBytes, publicKeyBytes) {
69
- this.privateKeyBytes = new Uint8Array(privateKeyBytes);
70
- this.publicKeyBytes = new Uint8Array(publicKeyBytes);
71
- }
72
- }
73
-
74
- /**
75
- * AbstractSigner base (minimal).
76
- */
77
- class AbstractSigner {
78
- /**
79
- * @param {import("../providers/provider").AbstractProvider|null} provider
80
- */
81
- constructor(provider) {
82
- this.provider = provider || null;
83
- }
84
-
85
- async getAddress() {
86
- throw makeError("getAddress not implemented", "NOT_IMPLEMENTED", {});
87
- }
88
- }
89
-
90
- /**
91
- * BaseWallet - core signing implementation.
92
- */
93
- class BaseWallet extends AbstractSigner {
94
- /**
95
- * @param {SigningKey} signingKey
96
- * @param {import("../providers/provider").AbstractProvider|null=} provider
97
- * @param {{ address: string }=} precomputed
98
- * @param {any=} qcWallet Internal quantum-coin-js-sdk Wallet (optional)
99
- */
100
- constructor(signingKey, provider, precomputed, qcWallet) {
101
- super(provider || null);
102
- _requireInitialized();
103
- this.signingKey = signingKey;
104
- this._qcWallet = qcWallet || null;
105
-
106
- /** @type {string} */
107
- this.address = precomputed?.address || "";
108
-
109
- Object.defineProperty(this, "privateKey", {
110
- enumerable: true,
111
- get: () => bytesToHex(this.signingKey.privateKeyBytes),
112
- });
113
- }
114
-
115
- async getAddress() {
116
- return this.address;
117
- }
118
-
119
- /**
120
- * Sign a message synchronously.
121
- * Signature format: combined publicKey+signature as a hex string.
122
- * @param {string|Uint8Array} message
123
- * @returns {string}
124
- */
125
- signMessageSync(message) {
126
- _requireInitialized();
127
- const pqc = _getPqc();
128
- const msgBytes = typeof message === "string" ? utf8ToBytes(message) : arrayify(message);
129
- const digestHex = sha256(msgBytes);
130
- const digest = _hexToNumberArray(digestHex);
131
- const sig = pqc.cryptoSign(digest, _bytesToNumberArray(this.signingKey.privateKeyBytes));
132
- const combined = qcsdk.combinePublicKeySignature(
133
- _bytesToNumberArray(this.signingKey.publicKeyBytes),
134
- sig,
135
- );
136
- if (typeof combined !== "string") throw makeError("combinePublicKeySignature failed", "UNKNOWN_ERROR", {});
137
- return normalizeHex(combined);
138
- }
139
-
140
- /**
141
- * Sign a transaction using quantum-coin-js-sdk signRawTransaction().
142
- * @param {import("../providers/provider").TransactionRequest} tx
143
- * @returns {Promise<string>}
144
- */
145
- async signTransaction(tx) {
146
- _requireInitialized();
147
- assertArgument(tx && typeof tx === "object", "invalid tx", "tx", tx);
148
-
149
- const toAddress = tx.to == null ? null : getAddress(tx.to);
150
- const valueInWei =
151
- tx.value == null
152
- ? 0n
153
- : typeof tx.value === "bigint"
154
- ? tx.value
155
- : typeof tx.value === "number"
156
- ? BigInt(tx.value)
157
- : typeof tx.value === "string"
158
- ? BigInt(tx.value.startsWith("0x") ? tx.value : tx.value)
159
- : 0n;
160
-
161
- const gasLimit =
162
- tx.gasLimit == null
163
- ? 21000
164
- : typeof tx.gasLimit === "bigint"
165
- ? Number(tx.gasLimit)
166
- : typeof tx.gasLimit === "number"
167
- ? tx.gasLimit
168
- : typeof tx.gasLimit === "string"
169
- ? Number(BigInt(tx.gasLimit))
170
- : 21000;
171
-
172
- const data = tx.data == null ? null : normalizeHex(tx.data);
173
- const remarks = tx.remarks == null ? null : normalizeHex(tx.remarks);
174
-
175
- if (remarks != null) {
176
- assertArgument(isHexString(remarks), "remarks must be hex string", "remarks", remarks);
177
- const remarkBytes = hexToBytes(remarks);
178
- assertArgument(remarkBytes.length <= 32, "remarks too long (max 32 bytes)", "remarks", remarks);
179
- }
180
-
181
- // Nonce must be provided or resolved from provider.
182
- let nonce = tx.nonce;
183
- if (nonce == null) {
184
- if (!this.provider) throw makeError("missing provider to resolve nonce", "UNKNOWN_ERROR", { operation: "signTransaction" });
185
- // Prefer pending to avoid nonce collisions with in-flight transactions.
186
- try {
187
- nonce = await this.provider.getTransactionCount(this.address, "pending");
188
- } catch {
189
- nonce = await this.provider.getTransactionCount(this.address, "latest");
190
- }
191
- }
192
- assertArgument(Number.isInteger(nonce) && nonce >= 0, "invalid nonce", "nonce", nonce);
193
-
194
- const chainId = tx.chainId != null ? tx.chainId : (this.provider && this.provider.chainId != null ? this.provider.chainId : null);
195
-
196
- /** @type {any} */
197
- const qcWallet =
198
- this._qcWallet ||
199
- new qcsdk.Wallet(
200
- this.address,
201
- _bytesToNumberArray(this.signingKey.privateKeyBytes),
202
- _bytesToNumberArray(this.signingKey.publicKeyBytes),
203
- );
204
-
205
- const req = new qcsdk.TransactionSigningRequest(
206
- qcWallet,
207
- toAddress,
208
- valueInWei,
209
- nonce,
210
- data,
211
- gasLimit,
212
- remarks,
213
- chainId,
214
- );
215
- const signResult = qcsdk.signRawTransaction(req);
216
- // quantum-coin-js-sdk returns a SignResult object: { resultCode, txnHash, txnData }
217
- if (!signResult || typeof signResult !== "object") {
218
- throw makeError("signRawTransaction failed", "UNKNOWN_ERROR", {});
219
- }
220
- if (typeof signResult.resultCode === "number" && signResult.resultCode !== 0) {
221
- throw makeError("signRawTransaction failed", "UNKNOWN_ERROR", {
222
- resultCode: signResult.resultCode,
223
- hash: signResult.txnHash || null,
224
- });
225
- }
226
- const raw = signResult.txnData;
227
- if (typeof raw !== "string") throw makeError("signRawTransaction did not return txnData", "UNKNOWN_ERROR", {});
228
- return normalizeHex(raw);
229
- }
230
-
231
- /**
232
- * Signs and sends a transaction.
233
- * @param {import("../providers/provider").TransactionRequest} tx
234
- * @returns {Promise<import("../providers/provider").TransactionResponse>}
235
- */
236
- async sendTransaction(tx) {
237
- if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "sendTransaction" });
238
- const raw = await this.signTransaction({ ...tx, from: this.address });
239
- return this.provider.sendTransaction(raw);
240
- }
241
- }
242
-
243
- /**
244
- * Wallet - convenience methods around BaseWallet.
245
- */
246
- class Wallet extends BaseWallet {
247
- /**
248
- * @param {string|Uint8Array|SigningKey} key
249
- * @param {import("../providers/provider").AbstractProvider=} provider
250
- */
251
- constructor(key, provider) {
252
- _requireInitialized();
253
-
254
- let signingKey;
255
- let qcAddress;
256
-
257
- if (key instanceof SigningKey) {
258
- signingKey = key;
259
- // Compute address from public key
260
- const addr = qcsdk.addressFromPublicKey(_bytesToNumberArray(signingKey.publicKeyBytes));
261
- if (typeof addr !== "string") throw makeError("addressFromPublicKey failed", "UNKNOWN_ERROR", {});
262
- qcAddress = normalizeHex(addr);
263
- } else {
264
- const privBytes = typeof key === "string" ? hexToBytes(key) : arrayify(key);
265
- const pubHex = qcsdk.publicKeyFromPrivateKey(_bytesToNumberArray(privBytes));
266
- if (typeof pubHex !== "string") throw makeError("publicKeyFromPrivateKey failed", "UNKNOWN_ERROR", {});
267
- const pubBytes = hexToBytes(pubHex);
268
- const addr = qcsdk.addressFromPublicKey(_bytesToNumberArray(pubBytes));
269
- if (typeof addr !== "string") throw makeError("addressFromPublicKey failed", "UNKNOWN_ERROR", {});
270
- qcAddress = normalizeHex(addr);
271
- signingKey = new SigningKey(privBytes, pubBytes);
272
- }
273
-
274
- /** @type {any} */
275
- const qcWallet = new qcsdk.Wallet(
276
- qcAddress,
277
- _bytesToNumberArray(signingKey.privateKeyBytes),
278
- _bytesToNumberArray(signingKey.publicKeyBytes),
279
- );
280
-
281
- super(signingKey, provider || null, { address: qcAddress }, qcWallet);
282
- }
283
-
284
- /**
285
- * Returns wallet address (sync).
286
- * @returns {string}
287
- */
288
- getAddress() {
289
- return this.address;
290
- }
291
-
292
- /**
293
- * Returns wallet balance.
294
- * @param {string=} blockTag
295
- * @returns {Promise<bigint>}
296
- */
297
- async getBalance(blockTag) {
298
- if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "getBalance" });
299
- void blockTag;
300
- return this.provider.getBalance(this.address);
301
- }
302
-
303
- /**
304
- * Returns wallet nonce.
305
- * @param {string=} blockTag
306
- * @returns {Promise<number>}
307
- */
308
- async getTransactionCount(blockTag) {
309
- if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "getTransactionCount" });
310
- return this.provider.getTransactionCount(this.address, blockTag);
311
- }
312
-
313
- /**
314
- * Encrypts and serializes this wallet to JSON.
315
- * @param {string|Uint8Array} password
316
- * @returns {string}
317
- */
318
- encryptSync(password) {
319
- _requireInitialized();
320
- const pw = typeof password === "string" ? password : Buffer.from(arrayify(password)).toString("utf8");
321
- const json = qcsdk.serializeEncryptedWallet(this._qcWallet, pw);
322
- if (typeof json !== "string") throw makeError("serializeEncryptedWallet failed", "UNKNOWN_ERROR", {});
323
- return json;
324
- }
325
-
326
- /**
327
- * Returns a new wallet connected to a provider.
328
- * @param {import("../providers/provider").AbstractProvider} provider
329
- * @returns {Wallet}
330
- */
331
- connect(provider) {
332
- return new Wallet(this.signingKey, provider);
333
- }
334
-
335
- /**
336
- * Creates a new random wallet.
337
- * @param {import("../providers/provider").AbstractProvider=} provider
338
- * @returns {Wallet}
339
- */
340
- static createRandom(provider) {
341
- _requireInitialized();
342
- const qcWallet = qcsdk.newWallet();
343
- if (!qcWallet) throw makeError("newWallet failed", "UNKNOWN_ERROR", {});
344
- return Wallet._fromQcWallet(qcWallet, provider || null);
345
- }
346
-
347
- /**
348
- * Creates a wallet from an encrypted JSON string.
349
- * @param {string} json
350
- * @param {string} password
351
- * @param {import("../providers/provider").AbstractProvider=} provider
352
- * @returns {Wallet}
353
- */
354
- static fromEncryptedJsonSync(json, password, provider) {
355
- _requireInitialized();
356
- const qcWallet = qcsdk.deserializeEncryptedWallet(json, password);
357
- if (!qcWallet) throw makeError("deserializeEncryptedWallet failed", "UNKNOWN_ERROR", {});
358
- return Wallet._fromQcWallet(qcWallet, provider || null);
359
- }
360
-
361
- /**
362
- * Creates a wallet from a seed phrase (48 words).
363
- * @param {string|string[]} phrase
364
- * @param {import("../providers/provider").AbstractProvider=} provider
365
- * @returns {Wallet}
366
- */
367
- static fromPhrase(phrase, provider) {
368
- _requireInitialized();
369
- let words = phrase;
370
- if (typeof phrase === "string") {
371
- words = phrase
372
- .split(/[,\s]+/g)
373
- .map((w) => w.trim())
374
- .filter(Boolean);
375
- }
376
- assertArgument(Array.isArray(words), "phrase must be a string or string[]", "phrase", phrase);
377
- assertArgument(words.length === 48, "seed phrase must contain exactly 48 words", "phrase", words.length);
378
- const qcWallet = qcsdk.openWalletFromSeedWords(words);
379
- if (!qcWallet) throw makeError("openWalletFromSeedWords failed", "UNKNOWN_ERROR", {});
380
- return Wallet._fromQcWallet(qcWallet, provider || null);
381
- }
382
-
383
- /**
384
- * Internal helper: build a Wallet from a quantum-coin-js-sdk Wallet object.
385
- * @param {any} qcWallet
386
- * @param {import("../providers/provider").AbstractProvider|null} provider
387
- * @returns {Wallet}
388
- */
389
- static _fromQcWallet(qcWallet, provider) {
390
- // Preserve key material from quantum-coin-js-sdk Wallet.
391
- // newWallet() returns Uint8Array keys; other constructors may return number[].
392
- const privSrc = qcWallet.privateKey;
393
- const pubSrc = qcWallet.publicKey;
394
-
395
- const privBytes =
396
- privSrc instanceof Uint8Array ? new Uint8Array(privSrc) : Uint8Array.from(Array.from(privSrc || []).map((n) => (Number(n) & 0xff)));
397
- const pubBytes =
398
- pubSrc instanceof Uint8Array ? new Uint8Array(pubSrc) : Uint8Array.from(Array.from(pubSrc || []).map((n) => (Number(n) & 0xff)));
399
- const key = new SigningKey(privBytes, pubBytes);
400
-
401
- const w = new Wallet(key, provider || null);
402
- // Ensure we keep the exact underlying qcWallet for operations like encrypt/signRawTransaction.
403
- w._qcWallet = qcWallet;
404
- if (typeof qcWallet.address === "string") {
405
- w.address = normalizeHex(qcWallet.address);
406
- }
407
- return w;
408
- }
409
- }
410
-
411
- /**
412
- * NonceManager wrapper.
413
- */
414
- class NonceManager extends AbstractSigner {
415
- /**
416
- * @param {AbstractSigner} signer
417
- */
418
- constructor(signer) {
419
- super(signer.provider || null);
420
- this.signer = signer;
421
- this._nonce = null;
422
- }
423
-
424
- async getAddress() {
425
- return this.signer.getAddress();
426
- }
427
-
428
- async getTransactionCount(blockTag) {
429
- if (this._nonce != null) return this._nonce;
430
- if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "getTransactionCount" });
431
- const address = await this.getAddress();
432
- this._nonce = await this.provider.getTransactionCount(address, blockTag);
433
- return this._nonce;
434
- }
435
-
436
- async sendTransaction(tx) {
437
- const nonce = await this.getTransactionCount("latest");
438
- const result = await this.signer.sendTransaction({ ...tx, nonce });
439
- this._nonce = nonce + 1;
440
- return result;
441
- }
442
-
443
- reset() {
444
- this._nonce = null;
445
- }
446
-
447
- increment() {
448
- if (this._nonce == null) this._nonce = 0;
449
- this._nonce++;
450
- }
451
- }
452
-
453
- /**
454
- * JsonRpcSigner placeholder (ethers-like).
455
- * This SDK encourages using Wallet directly for signing.
456
- */
457
- class JsonRpcSigner extends AbstractSigner {
458
- constructor(provider, address) {
459
- super(provider);
460
- this._address = address;
461
- }
462
- async getAddress() {
463
- return this._address;
464
- }
465
- }
466
-
467
- /**
468
- * VoidSigner (cannot sign, only provides address).
469
- */
470
- class VoidSigner extends AbstractSigner {
471
- constructor(address, provider) {
472
- super(provider || null);
473
- this._address = getAddress(address);
474
- }
475
- async getAddress() {
476
- return this._address;
477
- }
478
- }
479
-
480
- module.exports = {
481
- SigningKey,
482
- AbstractSigner,
483
- BaseWallet,
484
- Wallet,
485
- NonceManager,
486
- JsonRpcSigner,
487
- VoidSigner,
488
- };
489
-
1
+ /**
2
+ * @fileoverview Wallet and signer implementations.
3
+ *
4
+ * The QuantumCoin.js wallet model mirrors ethers.js v6:
5
+ * - AbstractSigner -> BaseWallet -> Wallet
6
+ * - NonceManager wrapper
7
+ *
8
+ * Cryptographic operations are delegated to `quantum-coin-js-sdk`.
9
+ */
10
+
11
+ const qcsdk = require("quantum-coin-js-sdk");
12
+ const { JsonRpcProvider } = require("../providers/json-rpc-provider");
13
+ const { assertArgument, makeError } = require("../errors");
14
+ const { arrayify, bytesToHex, hexToBytes, isHexString, normalizeHex } = require("../internal/hex");
15
+ const { hashMessage } = require("../utils/hashing");
16
+ const { getAddress } = require("../utils/address");
17
+ const { WeiPerEther } = require("../constants");
18
+
19
+ function _requireInitialized() {
20
+ // eslint-disable-next-line global-require
21
+ const { isInitialized } = require("../../config");
22
+ if (!isInitialized()) {
23
+ throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", { operation: "wallet" });
24
+ }
25
+ }
26
+
27
+ function _bytesToNumberArray(bytes) {
28
+ return Array.from(bytes);
29
+ }
30
+
31
+ /**
32
+ * SigningKey wrapper (PQC private/public key bytes).
33
+ */
34
+ class SigningKey {
35
+ /**
36
+ * @param {Uint8Array} privateKeyBytes
37
+ * @param {Uint8Array} publicKeyBytes
38
+ */
39
+ constructor(privateKeyBytes, publicKeyBytes) {
40
+ this.privateKeyBytes = new Uint8Array(privateKeyBytes);
41
+ this.publicKeyBytes = new Uint8Array(publicKeyBytes);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * AbstractSigner base (minimal).
47
+ */
48
+ class AbstractSigner {
49
+ /**
50
+ * @param {import("../providers/provider").AbstractProvider|null} provider
51
+ */
52
+ constructor(provider) {
53
+ this.provider = provider || null;
54
+ }
55
+
56
+ async getAddress() {
57
+ throw makeError("getAddress not implemented", "NOT_IMPLEMENTED", {});
58
+ }
59
+ }
60
+
61
+ /**
62
+ * BaseWallet - core signing implementation.
63
+ */
64
+ class BaseWallet extends AbstractSigner {
65
+ /**
66
+ * @param {SigningKey} signingKey
67
+ * @param {import("../providers/provider").AbstractProvider|null=} provider
68
+ * @param {{ address: string }=} precomputed
69
+ * @param {any=} qcWallet Internal quantum-coin-js-sdk Wallet (optional)
70
+ */
71
+ constructor(signingKey, provider, precomputed, qcWallet) {
72
+ super(provider || null);
73
+ _requireInitialized();
74
+ this.signingKey = signingKey;
75
+ this._qcWallet = qcWallet || null;
76
+
77
+ /** @type {string} */
78
+ this.address = precomputed?.address || "";
79
+
80
+ Object.defineProperty(this, "privateKey", {
81
+ enumerable: true,
82
+ get: () => bytesToHex(this.signingKey.privateKeyBytes),
83
+ });
84
+ }
85
+
86
+ async getAddress() {
87
+ return this.address;
88
+ }
89
+
90
+ /**
91
+ * Sign a message synchronously.
92
+ * Signature format: combined publicKey+signature as a hex string.
93
+ * @param {string|Uint8Array} message
94
+ * @returns {string}
95
+ */
96
+ signMessageSync(message) {
97
+ _requireInitialized();
98
+ const digestHex = hashMessage(message);
99
+ const digest = hexToBytes(digestHex);
100
+ const signResult = qcsdk.sign(this.signingKey.privateKeyBytes, digest, null);
101
+ if (signResult.resultCode !== 0) {
102
+ throw makeError("sign failed", "UNKNOWN_ERROR", { resultCode: signResult.resultCode });
103
+ }
104
+ const sigBytes = signResult.signature;
105
+ if (!sigBytes) throw makeError("sign returned no signature", "UNKNOWN_ERROR", {});
106
+ const sigArr = Array.from(sigBytes instanceof Uint8Array ? sigBytes : sigBytes);
107
+ let combined = qcsdk.combinePublicKeySignature(
108
+ _bytesToNumberArray(this.signingKey.publicKeyBytes),
109
+ sigArr,
110
+ );
111
+ if (combined != null && typeof combined === "object") {
112
+ if (typeof combined.String === "function") combined = combined.String();
113
+ else if (combined instanceof Uint8Array) combined = bytesToHex(combined);
114
+ else if (Array.isArray(combined)) combined = bytesToHex(new Uint8Array(combined));
115
+ else if (typeof combined.length === "number" && combined.length >= 0) combined = bytesToHex(new Uint8Array(Array.from(combined)));
116
+ }
117
+ if (combined == null || typeof combined !== "string") {
118
+ throw makeError("combinePublicKeySignature failed (SDK may not support this key type for message signing)", "UNKNOWN_ERROR", {
119
+ combinedType: typeof combined,
120
+ sigLength: sigArr.length,
121
+ });
122
+ }
123
+ return normalizeHex(combined);
124
+ }
125
+
126
+ /**
127
+ * Sign a transaction using quantum-coin-js-sdk signRawTransaction().
128
+ * @param {import("../providers/provider").TransactionRequest} tx
129
+ * @returns {Promise<string>}
130
+ */
131
+ async signTransaction(tx) {
132
+ _requireInitialized();
133
+ assertArgument(tx && typeof tx === "object", "invalid tx", "tx", tx);
134
+
135
+ const toAddress = tx.to == null ? null : getAddress(tx.to);
136
+ const valueInWei =
137
+ tx.value == null
138
+ ? 0n
139
+ : typeof tx.value === "bigint"
140
+ ? tx.value
141
+ : typeof tx.value === "number"
142
+ ? BigInt(tx.value)
143
+ : typeof tx.value === "string"
144
+ ? BigInt(tx.value.startsWith("0x") ? tx.value : tx.value)
145
+ : 0n;
146
+
147
+ const gasLimit =
148
+ tx.gasLimit == null
149
+ ? 21000
150
+ : typeof tx.gasLimit === "bigint"
151
+ ? Number(tx.gasLimit)
152
+ : typeof tx.gasLimit === "number"
153
+ ? tx.gasLimit
154
+ : typeof tx.gasLimit === "string"
155
+ ? Number(BigInt(tx.gasLimit))
156
+ : 21000;
157
+
158
+ const data = tx.data == null ? null : normalizeHex(tx.data);
159
+ const remarks = tx.remarks == null ? null : normalizeHex(tx.remarks);
160
+
161
+ if (remarks != null) {
162
+ assertArgument(isHexString(remarks), "remarks must be hex string", "remarks", remarks);
163
+ const remarkBytes = hexToBytes(remarks);
164
+ assertArgument(remarkBytes.length <= 32, "remarks too long (max 32 bytes)", "remarks", remarks);
165
+ }
166
+
167
+ // Nonce must be provided or resolved from provider.
168
+ let nonce = tx.nonce;
169
+ if (nonce == null) {
170
+ if (!this.provider) throw makeError("missing provider to resolve nonce", "UNKNOWN_ERROR", { operation: "signTransaction" });
171
+ // Prefer pending to avoid nonce collisions with in-flight transactions.
172
+ try {
173
+ nonce = await this.provider.getTransactionCount(this.address, "pending");
174
+ } catch {
175
+ nonce = await this.provider.getTransactionCount(this.address, "latest");
176
+ }
177
+ }
178
+ assertArgument(Number.isInteger(nonce) && nonce >= 0, "invalid nonce", "nonce", nonce);
179
+
180
+ const chainId = tx.chainId != null ? tx.chainId : (this.provider && this.provider.chainId != null ? this.provider.chainId : null);
181
+ const signingContext = tx.signingContext ?? null;
182
+
183
+ /** @type {any} */
184
+ const qcWallet =
185
+ this._qcWallet ||
186
+ new qcsdk.Wallet(
187
+ this.address,
188
+ _bytesToNumberArray(this.signingKey.privateKeyBytes),
189
+ _bytesToNumberArray(this.signingKey.publicKeyBytes),
190
+ );
191
+
192
+ const req = new qcsdk.TransactionSigningRequest(
193
+ qcWallet,
194
+ toAddress,
195
+ valueInWei,
196
+ nonce,
197
+ data,
198
+ gasLimit,
199
+ remarks,
200
+ chainId,
201
+ signingContext,
202
+ );
203
+ const signResult = qcsdk.signRawTransaction(req);
204
+ // quantum-coin-js-sdk returns a SignResult object: { resultCode, txnHash, txnData }
205
+ if (!signResult || typeof signResult !== "object") {
206
+ throw makeError("signRawTransaction failed", "UNKNOWN_ERROR", {});
207
+ }
208
+ if (typeof signResult.resultCode === "number" && signResult.resultCode !== 0) {
209
+ throw makeError("signRawTransaction failed", "UNKNOWN_ERROR", {
210
+ resultCode: signResult.resultCode,
211
+ hash: signResult.txnHash || null,
212
+ });
213
+ }
214
+ const raw = signResult.txnData;
215
+ if (typeof raw !== "string") throw makeError("signRawTransaction did not return txnData", "UNKNOWN_ERROR", {});
216
+ return normalizeHex(raw);
217
+ }
218
+
219
+ /**
220
+ * Signs and sends a transaction.
221
+ * @param {import("../providers/provider").TransactionRequest} tx
222
+ * @returns {Promise<import("../providers/provider").TransactionResponse>}
223
+ */
224
+ async sendTransaction(tx) {
225
+ if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "sendTransaction" });
226
+ const raw = await this.signTransaction({ ...tx, from: this.address });
227
+ return this.provider.sendTransaction(raw);
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Wallet - convenience methods around BaseWallet.
233
+ */
234
+ class Wallet extends BaseWallet {
235
+ /**
236
+ * @param {string|Uint8Array|SigningKey} key
237
+ * @param {import("../providers/provider").AbstractProvider=} provider
238
+ */
239
+ constructor(key, provider) {
240
+ _requireInitialized();
241
+
242
+ let signingKey;
243
+ let qcAddress;
244
+
245
+ if (key instanceof SigningKey) {
246
+ signingKey = key;
247
+ // Compute address from public key
248
+ const addr = qcsdk.addressFromPublicKey(_bytesToNumberArray(signingKey.publicKeyBytes));
249
+ if (typeof addr !== "string") throw makeError("addressFromPublicKey failed", "UNKNOWN_ERROR", {});
250
+ qcAddress = normalizeHex(addr);
251
+ } else {
252
+ const privBytes = typeof key === "string" ? hexToBytes(key) : arrayify(key);
253
+ const pubHex = qcsdk.publicKeyFromPrivateKey(_bytesToNumberArray(privBytes));
254
+ if (typeof pubHex !== "string") throw makeError("publicKeyFromPrivateKey failed", "UNKNOWN_ERROR", {});
255
+ const pubBytes = hexToBytes(pubHex);
256
+ const addr = qcsdk.addressFromPublicKey(_bytesToNumberArray(pubBytes));
257
+ if (typeof addr !== "string") throw makeError("addressFromPublicKey failed", "UNKNOWN_ERROR", {});
258
+ qcAddress = normalizeHex(addr);
259
+ signingKey = new SigningKey(privBytes, pubBytes);
260
+ }
261
+
262
+ /** @type {any} */
263
+ const qcWallet = new qcsdk.Wallet(
264
+ qcAddress,
265
+ _bytesToNumberArray(signingKey.privateKeyBytes),
266
+ _bytesToNumberArray(signingKey.publicKeyBytes),
267
+ );
268
+
269
+ super(signingKey, provider || null, { address: qcAddress }, qcWallet);
270
+ }
271
+
272
+ /**
273
+ * Returns wallet address (sync).
274
+ * @returns {string}
275
+ */
276
+ getAddress() {
277
+ return this.address;
278
+ }
279
+
280
+ /**
281
+ * Returns wallet balance.
282
+ * @param {string=} blockTag
283
+ * @returns {Promise<bigint>}
284
+ */
285
+ async getBalance(blockTag) {
286
+ if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "getBalance" });
287
+ void blockTag;
288
+ return this.provider.getBalance(this.address);
289
+ }
290
+
291
+ /**
292
+ * Returns wallet nonce.
293
+ * @param {string=} blockTag
294
+ * @returns {Promise<number>}
295
+ */
296
+ async getTransactionCount(blockTag) {
297
+ if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "getTransactionCount" });
298
+ return this.provider.getTransactionCount(this.address, blockTag);
299
+ }
300
+
301
+ /**
302
+ * Encrypts and serializes this wallet to JSON.
303
+ * @param {string|Uint8Array} password
304
+ * @returns {string}
305
+ */
306
+ encryptSync(password) {
307
+ _requireInitialized();
308
+ const pw = typeof password === "string" ? password : Buffer.from(arrayify(password)).toString("utf8");
309
+ const json = qcsdk.serializeEncryptedWallet(this._qcWallet, pw);
310
+ if (typeof json !== "string") throw makeError("serializeEncryptedWallet failed", "UNKNOWN_ERROR", {});
311
+ return json;
312
+ }
313
+
314
+ /**
315
+ * Returns a new wallet connected to a provider.
316
+ * @param {import("../providers/provider").AbstractProvider} provider
317
+ * @returns {Wallet}
318
+ */
319
+ connect(provider) {
320
+ return new Wallet(this.signingKey, provider);
321
+ }
322
+
323
+ /**
324
+ * Creates a new random wallet.
325
+ * @param {import("../providers/provider").AbstractProvider=} provider
326
+ * @returns {Wallet}
327
+ */
328
+ static createRandom(provider) {
329
+ _requireInitialized();
330
+ const qcWallet = qcsdk.newWallet();
331
+ if (!qcWallet) throw makeError("newWallet failed", "UNKNOWN_ERROR", {});
332
+ return Wallet._fromQcWallet(qcWallet, provider || null);
333
+ }
334
+
335
+ /**
336
+ * Creates a wallet from an encrypted JSON string.
337
+ * @param {string} json
338
+ * @param {string} password
339
+ * @param {import("../providers/provider").AbstractProvider=} provider
340
+ * @returns {Wallet}
341
+ */
342
+ static fromEncryptedJsonSync(json, password, provider) {
343
+ _requireInitialized();
344
+ const qcWallet = qcsdk.deserializeEncryptedWallet(json, password);
345
+ if (!qcWallet) throw makeError("deserializeEncryptedWallet failed", "UNKNOWN_ERROR", {});
346
+ return Wallet._fromQcWallet(qcWallet, provider || null);
347
+ }
348
+
349
+ /**
350
+ * Creates a wallet from a seed phrase (32, 36, or 48 words).
351
+ * @param {string|string[]} phrase
352
+ * @param {import("../providers/provider").AbstractProvider=} provider
353
+ * @returns {Wallet}
354
+ */
355
+ static fromPhrase(phrase, provider) {
356
+ _requireInitialized();
357
+ let words = phrase;
358
+ if (typeof phrase === "string") {
359
+ words = phrase
360
+ .split(/[,\s]+/g)
361
+ .map((w) => w.trim())
362
+ .filter(Boolean);
363
+ }
364
+ assertArgument(Array.isArray(words), "phrase must be a string or string[]", "phrase", phrase);
365
+ const allowedLengths = [32, 36, 48];
366
+ assertArgument(
367
+ allowedLengths.includes(words.length),
368
+ "seed phrase must contain 32, 36, or 48 words",
369
+ "phrase",
370
+ words.length,
371
+ );
372
+ const qcWallet = qcsdk.openWalletFromSeedWords(words);
373
+ if (!qcWallet) throw makeError("openWalletFromSeedWords failed", "UNKNOWN_ERROR", {});
374
+ return Wallet._fromQcWallet(qcWallet, provider || null);
375
+ }
376
+
377
+ /**
378
+ * Creates a wallet from raw private and public key bytes.
379
+ * @param {Uint8Array|string} privateKey Private key bytes or hex string
380
+ * @param {Uint8Array|string} publicKey Public key bytes or hex string
381
+ * @param {import("../providers/provider").AbstractProvider=} provider
382
+ * @returns {Wallet}
383
+ */
384
+ static fromKeys(privateKey, publicKey, provider) {
385
+ _requireInitialized();
386
+ const privBytes = typeof privateKey === "string" ? hexToBytes(privateKey) : arrayify(privateKey);
387
+ const pubBytes = typeof publicKey === "string" ? hexToBytes(publicKey) : arrayify(publicKey);
388
+ assertArgument(privBytes.length > 0, "privateKey must not be empty", "privateKey", privateKey);
389
+ assertArgument(pubBytes.length > 0, "publicKey must not be empty", "publicKey", publicKey);
390
+ const key = new SigningKey(privBytes, pubBytes);
391
+ return new Wallet(key, provider || null);
392
+ }
393
+
394
+ /**
395
+ * Internal helper: build a Wallet from a quantum-coin-js-sdk Wallet object.
396
+ * @param {any} qcWallet
397
+ * @param {import("../providers/provider").AbstractProvider|null} provider
398
+ * @returns {Wallet}
399
+ */
400
+ static _fromQcWallet(qcWallet, provider) {
401
+ // Preserve key material from quantum-coin-js-sdk Wallet.
402
+ // newWallet() returns Uint8Array keys; other constructors may return number[].
403
+ const privSrc = qcWallet.privateKey;
404
+ const pubSrc = qcWallet.publicKey;
405
+
406
+ const privBytes =
407
+ privSrc instanceof Uint8Array ? new Uint8Array(privSrc) : Uint8Array.from(Array.from(privSrc || []).map((n) => (Number(n) & 0xff)));
408
+ const pubBytes =
409
+ pubSrc instanceof Uint8Array ? new Uint8Array(pubSrc) : Uint8Array.from(Array.from(pubSrc || []).map((n) => (Number(n) & 0xff)));
410
+ const key = new SigningKey(privBytes, pubBytes);
411
+
412
+ const w = new Wallet(key, provider || null);
413
+ // Ensure we keep the exact underlying qcWallet for operations like encrypt/signRawTransaction.
414
+ w._qcWallet = qcWallet;
415
+ if (typeof qcWallet.address === "string") {
416
+ w.address = normalizeHex(qcWallet.address);
417
+ }
418
+ return w;
419
+ }
420
+ }
421
+
422
+ /**
423
+ * NonceManager wrapper.
424
+ */
425
+ class NonceManager extends AbstractSigner {
426
+ /**
427
+ * @param {AbstractSigner} signer
428
+ */
429
+ constructor(signer) {
430
+ super(signer.provider || null);
431
+ this.signer = signer;
432
+ this._nonce = null;
433
+ }
434
+
435
+ async getAddress() {
436
+ return this.signer.getAddress();
437
+ }
438
+
439
+ async getTransactionCount(blockTag) {
440
+ if (this._nonce != null) return this._nonce;
441
+ if (!this.provider) throw makeError("missing provider", "UNKNOWN_ERROR", { operation: "getTransactionCount" });
442
+ const address = await this.getAddress();
443
+ this._nonce = await this.provider.getTransactionCount(address, blockTag);
444
+ return this._nonce;
445
+ }
446
+
447
+ async sendTransaction(tx) {
448
+ const nonce = await this.getTransactionCount("latest");
449
+ const result = await this.signer.sendTransaction({ ...tx, nonce });
450
+ this._nonce = nonce + 1;
451
+ return result;
452
+ }
453
+
454
+ reset() {
455
+ this._nonce = null;
456
+ }
457
+
458
+ increment() {
459
+ if (this._nonce == null) this._nonce = 0;
460
+ this._nonce++;
461
+ }
462
+ }
463
+
464
+ /**
465
+ * JsonRpcSigner placeholder (ethers-like).
466
+ * This SDK encourages using Wallet directly for signing.
467
+ */
468
+ class JsonRpcSigner extends AbstractSigner {
469
+ constructor(provider, address) {
470
+ super(provider);
471
+ this._address = address;
472
+ }
473
+ async getAddress() {
474
+ return this._address;
475
+ }
476
+ }
477
+
478
+ /**
479
+ * VoidSigner (cannot sign, only provides address).
480
+ */
481
+ class VoidSigner extends AbstractSigner {
482
+ constructor(address, provider) {
483
+ super(provider || null);
484
+ this._address = getAddress(address);
485
+ }
486
+ async getAddress() {
487
+ return this._address;
488
+ }
489
+ }
490
+
491
+ module.exports = {
492
+ SigningKey,
493
+ AbstractSigner,
494
+ BaseWallet,
495
+ Wallet,
496
+ NonceManager,
497
+ JsonRpcSigner,
498
+ VoidSigner,
499
+ };
500
+