quantumcoin 7.0.9 → 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 +1 -5
- package/README.md +18 -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 +424 -73
- package/examples/package.json +2 -2
- package/examples/wallet-offline.js +10 -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 +11 -13
- package/src/wallet/wallet.js +135 -96
- package/test/security/malformed-input.test.js +295 -1
- package/test/unit/address-wallet.test.js +277 -128
- package/test/unit/address-wallet.test.ts +276 -127
- 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
package/src/utils/hashing.js
CHANGED
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const crypto = require("crypto");
|
|
10
|
-
const { MessagePrefix } = require("../constants");
|
|
11
10
|
const { arrayify, bytesToHex, utf8ToBytes } = require("../internal/hex");
|
|
12
|
-
const { concat } = require("./encoding");
|
|
13
11
|
|
|
14
12
|
const _MASK64 = (1n << 64n) - 1n;
|
|
15
13
|
|
|
@@ -192,18 +190,6 @@ function ripemd160(data) {
|
|
|
192
190
|
return _hash("ripemd160", data);
|
|
193
191
|
}
|
|
194
192
|
|
|
195
|
-
/**
|
|
196
|
-
* EIP-191 personal-sign message digest (ethers.js hashMessage pattern).
|
|
197
|
-
* Prefixes message with MessagePrefix and decimal length, then keccak256.
|
|
198
|
-
* If message is a string, it is converted to UTF-8 bytes first.
|
|
199
|
-
* @param {string|Uint8Array} message
|
|
200
|
-
* @returns {string} Hex digest
|
|
201
|
-
*/
|
|
202
|
-
function hashMessage(message) {
|
|
203
|
-
const msgBytes = typeof message === "string" ? utf8ToBytes(message) : arrayify(message);
|
|
204
|
-
return keccak256(concat([utf8ToBytes(MessagePrefix), utf8ToBytes(String(msgBytes.length)), msgBytes]));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
193
|
/**
|
|
208
194
|
* ethers-style id(text) => keccak256(utf8Bytes(text))
|
|
209
195
|
* @param {string} text
|
|
@@ -230,8 +216,8 @@ function randomBytes(length) {
|
|
|
230
216
|
* @returns {string}
|
|
231
217
|
*/
|
|
232
218
|
function computeHmac(algorithm, key, data) {
|
|
233
|
-
const k = arrayify(key);
|
|
234
|
-
const d = arrayify(data);
|
|
219
|
+
const k = typeof key === "string" ? utf8ToBytes(key) : arrayify(key);
|
|
220
|
+
const d = typeof data === "string" ? utf8ToBytes(data) : arrayify(data);
|
|
235
221
|
const h = crypto.createHmac(algorithm, Buffer.from(k)).update(Buffer.from(d)).digest();
|
|
236
222
|
return bytesToHex(new Uint8Array(h));
|
|
237
223
|
}
|
|
@@ -246,8 +232,8 @@ function computeHmac(algorithm, key, data) {
|
|
|
246
232
|
* @returns {string}
|
|
247
233
|
*/
|
|
248
234
|
function pbkdf2(password, salt, iterations, keylen, algorithm) {
|
|
249
|
-
const p = arrayify(password);
|
|
250
|
-
const s = arrayify(salt);
|
|
235
|
+
const p = typeof password === "string" ? utf8ToBytes(password) : arrayify(password);
|
|
236
|
+
const s = typeof salt === "string" ? utf8ToBytes(salt) : arrayify(salt);
|
|
251
237
|
const a = algorithm || "sha256";
|
|
252
238
|
const out = crypto.pbkdf2Sync(Buffer.from(p), Buffer.from(s), iterations, keylen, a);
|
|
253
239
|
return bytesToHex(new Uint8Array(out));
|
|
@@ -264,8 +250,8 @@ function pbkdf2(password, salt, iterations, keylen, algorithm) {
|
|
|
264
250
|
* @returns {Promise<string>}
|
|
265
251
|
*/
|
|
266
252
|
function scrypt(password, salt, N, r, p, dkLen) {
|
|
267
|
-
const pw = arrayify(password);
|
|
268
|
-
const sa = arrayify(salt);
|
|
253
|
+
const pw = typeof password === "string" ? utf8ToBytes(password) : arrayify(password);
|
|
254
|
+
const sa = typeof salt === "string" ? utf8ToBytes(salt) : arrayify(salt);
|
|
269
255
|
return new Promise((resolve, reject) => {
|
|
270
256
|
crypto.scrypt(
|
|
271
257
|
Buffer.from(pw),
|
|
@@ -291,15 +277,14 @@ function scrypt(password, salt, N, r, p, dkLen) {
|
|
|
291
277
|
* @returns {string}
|
|
292
278
|
*/
|
|
293
279
|
function scryptSync(password, salt, N, r, p, dkLen) {
|
|
294
|
-
const pw = arrayify(password);
|
|
295
|
-
const sa = arrayify(salt);
|
|
280
|
+
const pw = typeof password === "string" ? utf8ToBytes(password) : arrayify(password);
|
|
281
|
+
const sa = typeof salt === "string" ? utf8ToBytes(salt) : arrayify(salt);
|
|
296
282
|
const out = crypto.scryptSync(Buffer.from(pw), Buffer.from(sa), dkLen, { N, r, p, maxmem: 257 * 1024 * 1024 }); //257 instead of 256 for buffer for compat for N=262144, r=8, p=1
|
|
297
283
|
return bytesToHex(new Uint8Array(out));
|
|
298
284
|
}
|
|
299
285
|
|
|
300
286
|
module.exports = {
|
|
301
287
|
keccak256,
|
|
302
|
-
hashMessage,
|
|
303
288
|
sha256,
|
|
304
289
|
sha512,
|
|
305
290
|
ripemd160,
|
package/src/utils/index.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ declare const _exports: {
|
|
|
12
12
|
encodeRlp(value: any): string;
|
|
13
13
|
decodeRlp(data: string): any;
|
|
14
14
|
keccak256(data: string | Uint8Array): string;
|
|
15
|
-
hashMessage(message: string | Uint8Array): string;
|
|
16
15
|
sha256(data: string | Uint8Array): string;
|
|
17
16
|
sha512(data: string | Uint8Array): string;
|
|
18
17
|
ripemd160(data: string | Uint8Array): string;
|
|
@@ -59,8 +58,6 @@ declare const _exports: {
|
|
|
59
58
|
}): string;
|
|
60
59
|
getCreate2Address(from: string, salt: string, initCodeHash: string): string;
|
|
61
60
|
computeAddress(key: string | Uint8Array): string;
|
|
62
|
-
verifyMessage(message: string | Uint8Array, signature: string): string;
|
|
63
|
-
recoverAddress(message: string | Uint8Array, signature: string): string;
|
|
64
61
|
FixedNumber: typeof import("./fixednumber").FixedNumber;
|
|
65
62
|
};
|
|
66
63
|
export = _exports;
|
package/src/utils/rlp.js
CHANGED
|
@@ -110,7 +110,10 @@ function _readLen(bytes, offset, lenOfLen) {
|
|
|
110
110
|
return len;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
const MAX_RLP_DEPTH = 64;
|
|
114
|
+
|
|
115
|
+
function _decode(bytes, start, end, depth) {
|
|
116
|
+
if (depth > MAX_RLP_DEPTH) throw new Error("RLP: maximum nesting depth exceeded");
|
|
114
117
|
if (start >= end) throw new Error("RLP: empty input");
|
|
115
118
|
const prefix = bytes[start];
|
|
116
119
|
|
|
@@ -149,7 +152,7 @@ function _decode(bytes, start, end) {
|
|
|
149
152
|
const out = [];
|
|
150
153
|
let pos = dataStart;
|
|
151
154
|
while (pos < dataEnd) {
|
|
152
|
-
const decoded = _decode(bytes, pos, dataEnd);
|
|
155
|
+
const decoded = _decode(bytes, pos, dataEnd, depth + 1);
|
|
153
156
|
out.push(decoded.value);
|
|
154
157
|
pos = decoded.next;
|
|
155
158
|
}
|
|
@@ -166,7 +169,7 @@ function _decode(bytes, start, end) {
|
|
|
166
169
|
const out = [];
|
|
167
170
|
let pos = dataStart;
|
|
168
171
|
while (pos < dataEnd) {
|
|
169
|
-
const decoded = _decode(bytes, pos, dataEnd);
|
|
172
|
+
const decoded = _decode(bytes, pos, dataEnd, depth + 1);
|
|
170
173
|
out.push(decoded.value);
|
|
171
174
|
pos = decoded.next;
|
|
172
175
|
}
|
|
@@ -191,7 +194,7 @@ function encodeRlp(value) {
|
|
|
191
194
|
function decodeRlp(data) {
|
|
192
195
|
if (typeof data !== "string") throw new TypeError("RLP data must be a hex string");
|
|
193
196
|
const bytes = arrayify(data);
|
|
194
|
-
const decoded = _decode(bytes, 0, bytes.length);
|
|
197
|
+
const decoded = _decode(bytes, 0, bytes.length, 0);
|
|
195
198
|
if (decoded.next !== bytes.length) throw new Error("RLP: trailing data");
|
|
196
199
|
return decoded.value;
|
|
197
200
|
}
|
package/src/wallet/wallet.d.ts
CHANGED
|
@@ -38,14 +38,9 @@ export class BaseWallet extends AbstractSigner {
|
|
|
38
38
|
_qcWallet: any;
|
|
39
39
|
/** @type {string} */
|
|
40
40
|
address: string;
|
|
41
|
+
readonly publicKey: string;
|
|
42
|
+
readonly seed: string | null;
|
|
41
43
|
getAddress(): Promise<string>;
|
|
42
|
-
/**
|
|
43
|
-
* Sign a message synchronously.
|
|
44
|
-
* Signature format: combined publicKey+signature as a hex string.
|
|
45
|
-
* @param {string|Uint8Array} message
|
|
46
|
-
* @returns {string}
|
|
47
|
-
*/
|
|
48
|
-
signMessageSync(message: string | Uint8Array): string;
|
|
49
44
|
/**
|
|
50
45
|
* Sign a transaction using quantum-coin-js-sdk signRawTransaction().
|
|
51
46
|
* @param {import("../providers/provider").TransactionRequest} tx
|
|
@@ -77,12 +72,6 @@ export class Wallet extends BaseWallet {
|
|
|
77
72
|
* @returns {Wallet}
|
|
78
73
|
*/
|
|
79
74
|
static createRandom(provider?: import("../providers/provider").AbstractProvider | undefined, keyType?: number | null): Wallet;
|
|
80
|
-
/**
|
|
81
|
-
* Creates a new random seed word list (32 words for keyType 3, 36 for keyType 5).
|
|
82
|
-
* @param {number|null=} keyType Optional key type: null (default=3), 3, or 5
|
|
83
|
-
* @returns {string[]}
|
|
84
|
-
*/
|
|
85
|
-
static createRandomSeed(keyType?: number | null): string[];
|
|
86
75
|
/**
|
|
87
76
|
* Creates a wallet from raw seed bytes.
|
|
88
77
|
* @param {number[]} seed Raw seed bytes: 64 (keyType 3), 72 (keyType 5), or 96 (legacy)
|
|
@@ -148,6 +137,15 @@ export class Wallet extends BaseWallet {
|
|
|
148
137
|
* @returns {string}
|
|
149
138
|
*/
|
|
150
139
|
encryptSync(password: string | Uint8Array): string;
|
|
140
|
+
/**
|
|
141
|
+
* Encrypts raw seed bytes into a wallet JSON string (version 5 pre-expansion format).
|
|
142
|
+
* The resulting JSON can be opened with `Wallet.fromEncryptedJsonSync()` or
|
|
143
|
+
* Desktop/Mobile/Web/CLI wallet applications.
|
|
144
|
+
* @param {number[]|Uint8Array} seed Raw seed bytes: 64 (keyType 3), 72 (keyType 5), or 96 (legacy)
|
|
145
|
+
* @param {string|Uint8Array} password Passphrase (at least 12 characters)
|
|
146
|
+
* @returns {string}
|
|
147
|
+
*/
|
|
148
|
+
static encryptSeedSync(seed: number[] | Uint8Array, password: string | Uint8Array): string;
|
|
151
149
|
/**
|
|
152
150
|
* Returns a new wallet connected to a provider.
|
|
153
151
|
* @param {import("../providers/provider").AbstractProvider} provider
|
package/src/wallet/wallet.js
CHANGED
|
@@ -10,24 +10,52 @@
|
|
|
10
10
|
|
|
11
11
|
const qcsdk = require("quantum-coin-js-sdk");
|
|
12
12
|
const { JsonRpcProvider } = require("../providers/json-rpc-provider");
|
|
13
|
-
const { assertArgument, makeError } = require("../errors");
|
|
13
|
+
const { assertArgument, assertSecretArgument, makeError } = require("../errors");
|
|
14
14
|
const { arrayify, bytesToHex, hexToBytes, isHexString, normalizeHex } = require("../internal/hex");
|
|
15
|
-
const { hashMessage } = require("../utils/hashing");
|
|
16
15
|
const { getAddress } = require("../utils/address");
|
|
17
16
|
const { WeiPerEther } = require("../constants");
|
|
18
17
|
|
|
19
18
|
function _requireInitialized() {
|
|
20
19
|
// eslint-disable-next-line global-require
|
|
21
|
-
const { isInitialized } = require("../../config");
|
|
22
|
-
if (
|
|
23
|
-
|
|
20
|
+
const { isInitialized, getInitializationPromise } = require("../../config");
|
|
21
|
+
if (isInitialized()) return;
|
|
22
|
+
if (getInitializationPromise() != null) {
|
|
23
|
+
throw makeError(
|
|
24
|
+
"QuantumCoin SDK is still initializing. Await the Initialize() promise before using SDK methods.",
|
|
25
|
+
"UNKNOWN_ERROR",
|
|
26
|
+
{ operation: "requireInitialized" },
|
|
27
|
+
);
|
|
24
28
|
}
|
|
29
|
+
throw makeError("QuantumCoin SDK not initialized. Call Initialize() first.", "UNKNOWN_ERROR", { operation: "wallet" });
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
function _bytesToNumberArray(bytes) {
|
|
28
33
|
return Array.from(bytes);
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
const _maxSafeInt = 0x1fffffffffffffn; // 2^53 - 1
|
|
37
|
+
|
|
38
|
+
function _getBigInt(value, name) {
|
|
39
|
+
if (typeof value === "bigint") return value;
|
|
40
|
+
if (typeof value === "number") {
|
|
41
|
+
assertArgument(Number.isInteger(value), "underflow", name, value);
|
|
42
|
+
assertArgument(value >= -Number(_maxSafeInt) && value <= Number(_maxSafeInt), "overflow", name, value);
|
|
43
|
+
return BigInt(value);
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "string") {
|
|
46
|
+
if (value === "0x" || value === "0X") return 0n;
|
|
47
|
+
try { return BigInt(value); }
|
|
48
|
+
catch { assertArgument(false, "invalid BigNumberish string", name, value); }
|
|
49
|
+
}
|
|
50
|
+
assertArgument(false, "invalid BigNumberish", name, value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function _getNumber(value, name) {
|
|
54
|
+
const bi = _getBigInt(value, name);
|
|
55
|
+
assertArgument(bi >= -_maxSafeInt && bi <= _maxSafeInt, "overflow", name, value);
|
|
56
|
+
return Number(bi);
|
|
57
|
+
}
|
|
58
|
+
|
|
31
59
|
/**
|
|
32
60
|
* SigningKey wrapper (PQC private/public key bytes).
|
|
33
61
|
*/
|
|
@@ -37,9 +65,18 @@ class SigningKey {
|
|
|
37
65
|
* @param {Uint8Array} publicKeyBytes
|
|
38
66
|
*/
|
|
39
67
|
constructor(privateKeyBytes, publicKeyBytes) {
|
|
40
|
-
this
|
|
68
|
+
Object.defineProperty(this, "privateKeyBytes", {
|
|
69
|
+
enumerable: false,
|
|
70
|
+
configurable: false,
|
|
71
|
+
writable: false,
|
|
72
|
+
value: new Uint8Array(privateKeyBytes),
|
|
73
|
+
});
|
|
41
74
|
this.publicKeyBytes = new Uint8Array(publicKeyBytes);
|
|
42
75
|
}
|
|
76
|
+
|
|
77
|
+
toJSON() {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
43
80
|
}
|
|
44
81
|
|
|
45
82
|
/**
|
|
@@ -71,56 +108,52 @@ class BaseWallet extends AbstractSigner {
|
|
|
71
108
|
constructor(signingKey, provider, precomputed, qcWallet) {
|
|
72
109
|
super(provider || null);
|
|
73
110
|
_requireInitialized();
|
|
74
|
-
|
|
75
|
-
this
|
|
111
|
+
|
|
112
|
+
Object.defineProperty(this, "signingKey", {
|
|
113
|
+
enumerable: false,
|
|
114
|
+
configurable: false,
|
|
115
|
+
writable: false,
|
|
116
|
+
value: signingKey,
|
|
117
|
+
});
|
|
118
|
+
Object.defineProperty(this, "_qcWallet", {
|
|
119
|
+
enumerable: false,
|
|
120
|
+
configurable: true,
|
|
121
|
+
writable: true,
|
|
122
|
+
value: qcWallet || null,
|
|
123
|
+
});
|
|
76
124
|
|
|
77
125
|
/** @type {string} */
|
|
78
126
|
this.address = precomputed?.address || "";
|
|
79
127
|
|
|
80
128
|
Object.defineProperty(this, "privateKey", {
|
|
81
|
-
enumerable:
|
|
129
|
+
enumerable: false,
|
|
82
130
|
get: () => bytesToHex(this.signingKey.privateKeyBytes),
|
|
83
131
|
});
|
|
132
|
+
|
|
133
|
+
Object.defineProperty(this, "publicKey", {
|
|
134
|
+
enumerable: true,
|
|
135
|
+
get: () => bytesToHex(this.signingKey.publicKeyBytes),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
Object.defineProperty(this, "_seed", {
|
|
139
|
+
enumerable: false,
|
|
140
|
+
configurable: true,
|
|
141
|
+
writable: true,
|
|
142
|
+
value: null,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
Object.defineProperty(this, "seed", {
|
|
146
|
+
enumerable: false,
|
|
147
|
+
get: () => this._seed,
|
|
148
|
+
});
|
|
84
149
|
}
|
|
85
150
|
|
|
86
|
-
|
|
87
|
-
return this.address;
|
|
151
|
+
toJSON() {
|
|
152
|
+
return { address: this.address };
|
|
88
153
|
}
|
|
89
154
|
|
|
90
|
-
|
|
91
|
-
|
|
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);
|
|
155
|
+
async getAddress() {
|
|
156
|
+
return this.address;
|
|
124
157
|
}
|
|
125
158
|
|
|
126
159
|
/**
|
|
@@ -133,27 +166,8 @@ class BaseWallet extends AbstractSigner {
|
|
|
133
166
|
assertArgument(tx && typeof tx === "object", "invalid tx", "tx", tx);
|
|
134
167
|
|
|
135
168
|
const toAddress = tx.to == null ? null : getAddress(tx.to);
|
|
136
|
-
const valueInWei =
|
|
137
|
-
|
|
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;
|
|
169
|
+
const valueInWei = tx.value == null ? 0n : _getBigInt(tx.value, "tx.value");
|
|
170
|
+
const gasLimit = tx.gasLimit == null ? 21000 : _getNumber(tx.gasLimit, "tx.gasLimit");
|
|
157
171
|
|
|
158
172
|
const data = tx.data == null ? null : normalizeHex(tx.data);
|
|
159
173
|
const remarks = tx.remarks == null ? null : normalizeHex(tx.remarks);
|
|
@@ -299,18 +313,47 @@ class Wallet extends BaseWallet {
|
|
|
299
313
|
}
|
|
300
314
|
|
|
301
315
|
/**
|
|
302
|
-
* Encrypts and serializes this wallet to JSON.
|
|
316
|
+
* Encrypts and serializes this wallet to JSON.
|
|
303
317
|
* @param {string|Uint8Array} password
|
|
304
318
|
* @returns {string}
|
|
305
319
|
*/
|
|
306
320
|
encryptSync(password) {
|
|
307
321
|
_requireInitialized();
|
|
308
|
-
|
|
322
|
+
if (this._seed != null) {
|
|
323
|
+
return Wallet.encryptSeedSync(hexToBytes(this._seed), password);
|
|
324
|
+
}
|
|
325
|
+
const pw = typeof password === "string"
|
|
326
|
+
? password.normalize("NFC")
|
|
327
|
+
: Buffer.from(arrayify(password)).toString("utf8").normalize("NFC");
|
|
328
|
+
assertSecretArgument(pw.length >= 12, "password must be at least 12 characters", "password");
|
|
309
329
|
const json = qcsdk.serializeEncryptedWallet(this._qcWallet, pw);
|
|
310
330
|
if (typeof json !== "string") throw makeError("serializeEncryptedWallet failed", "UNKNOWN_ERROR", {});
|
|
311
331
|
return json;
|
|
312
332
|
}
|
|
313
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Encrypts raw seed bytes into a wallet JSON string (version 5 pre-expansion format).
|
|
336
|
+
* The resulting JSON can be opened with `Wallet.fromEncryptedJsonSync()` or
|
|
337
|
+
* Desktop/Mobile/Web/CLI wallet applications.
|
|
338
|
+
* @param {number[]|Uint8Array} seed Raw seed bytes: 64 (keyType 3), 72 (keyType 5), or 96 (legacy)
|
|
339
|
+
* @param {string|Uint8Array} password Passphrase (at least 12 characters)
|
|
340
|
+
* @returns {string}
|
|
341
|
+
*/
|
|
342
|
+
static encryptSeedSync(seed, password) {
|
|
343
|
+
_requireInitialized();
|
|
344
|
+
const seedArr = seed instanceof Uint8Array ? Array.from(seed) : seed;
|
|
345
|
+
assertArgument(Array.isArray(seedArr), "seed must be an array of numbers or Uint8Array", "seed", seed);
|
|
346
|
+
const allowedLengths = [64, 72, 96];
|
|
347
|
+
assertArgument(allowedLengths.includes(seedArr.length), "seed must be 64, 72, or 96 bytes", "seed", seedArr.length);
|
|
348
|
+
const pw = typeof password === "string"
|
|
349
|
+
? password.normalize("NFC")
|
|
350
|
+
: Buffer.from(arrayify(password)).toString("utf8").normalize("NFC");
|
|
351
|
+
assertSecretArgument(pw.length >= 12, "password must be at least 12 characters", "password");
|
|
352
|
+
const json = qcsdk.serializeSeedAsEncryptedWallet(seedArr, pw);
|
|
353
|
+
if (typeof json !== "string") throw makeError("serializeSeedAsEncryptedWallet failed", "UNKNOWN_ERROR", {});
|
|
354
|
+
return json;
|
|
355
|
+
}
|
|
356
|
+
|
|
314
357
|
/**
|
|
315
358
|
* Returns the recommended signing context for this wallet.
|
|
316
359
|
* Setting fullSign to true may incur additional gas cost.
|
|
@@ -335,7 +378,10 @@ class Wallet extends BaseWallet {
|
|
|
335
378
|
* @returns {Wallet}
|
|
336
379
|
*/
|
|
337
380
|
connect(provider) {
|
|
338
|
-
|
|
381
|
+
const w = new Wallet(this.signingKey, provider);
|
|
382
|
+
w._qcWallet = this._qcWallet;
|
|
383
|
+
w._seed = this._seed;
|
|
384
|
+
return w;
|
|
339
385
|
}
|
|
340
386
|
|
|
341
387
|
/**
|
|
@@ -349,29 +395,11 @@ class Wallet extends BaseWallet {
|
|
|
349
395
|
if (keyType != null) {
|
|
350
396
|
assertArgument(keyType === 3 || keyType === 5, "keyType must be null, 3, or 5", "keyType", keyType);
|
|
351
397
|
}
|
|
352
|
-
const
|
|
353
|
-
if (!qcWallet || typeof qcWallet === "number") {
|
|
354
|
-
throw makeError("newWallet failed", "UNKNOWN_ERROR", { result: qcWallet });
|
|
355
|
-
}
|
|
356
|
-
return Wallet._fromQcWallet(qcWallet, provider || null);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Creates a new random seed word list (32 words for keyType 3, 36 for keyType 5).
|
|
361
|
-
* Use the returned words with `Wallet.fromPhrase()` to create a wallet.
|
|
362
|
-
* @param {number|null=} keyType Optional key type: null (default=3), 3, or 5
|
|
363
|
-
* @returns {string[]}
|
|
364
|
-
*/
|
|
365
|
-
static createRandomSeed(keyType) {
|
|
366
|
-
_requireInitialized();
|
|
367
|
-
if (keyType != null) {
|
|
368
|
-
assertArgument(keyType === 3 || keyType === 5, "keyType must be null, 3, or 5", "keyType", keyType);
|
|
369
|
-
}
|
|
370
|
-
const words = qcsdk.newWalletSeed(keyType ?? null);
|
|
398
|
+
const words = qcsdk.newWalletSeedWords(keyType ?? null);
|
|
371
399
|
if (!words || !Array.isArray(words)) {
|
|
372
|
-
throw makeError("
|
|
400
|
+
throw makeError("newWalletSeedWords failed", "UNKNOWN_ERROR", { result: words });
|
|
373
401
|
}
|
|
374
|
-
return words;
|
|
402
|
+
return Wallet.fromPhrase(words, provider);
|
|
375
403
|
}
|
|
376
404
|
|
|
377
405
|
/**
|
|
@@ -445,8 +473,8 @@ class Wallet extends BaseWallet {
|
|
|
445
473
|
_requireInitialized();
|
|
446
474
|
const privBytes = typeof privateKey === "string" ? hexToBytes(privateKey) : arrayify(privateKey);
|
|
447
475
|
const pubBytes = typeof publicKey === "string" ? hexToBytes(publicKey) : arrayify(publicKey);
|
|
448
|
-
|
|
449
|
-
|
|
476
|
+
assertSecretArgument(privBytes.length > 0, "privateKey must not be empty", "privateKey");
|
|
477
|
+
assertSecretArgument(pubBytes.length > 0, "publicKey must not be empty", "publicKey");
|
|
450
478
|
|
|
451
479
|
const privArr = _bytesToNumberArray(privBytes);
|
|
452
480
|
const pubArr = _bytesToNumberArray(pubBytes);
|
|
@@ -469,15 +497,20 @@ class Wallet extends BaseWallet {
|
|
|
469
497
|
* @returns {Wallet}
|
|
470
498
|
*/
|
|
471
499
|
static _fromQcWallet(qcWallet, provider) {
|
|
472
|
-
// Preserve key material from quantum-coin-js-sdk Wallet.
|
|
473
|
-
// newWallet() returns Uint8Array keys; other constructors may return number[].
|
|
474
500
|
const privSrc = qcWallet.privateKey;
|
|
475
501
|
const pubSrc = qcWallet.publicKey;
|
|
476
502
|
|
|
503
|
+
if (!privSrc || (privSrc instanceof Uint8Array && privSrc.length === 0) || (Array.isArray(privSrc) && privSrc.length === 0)) {
|
|
504
|
+
throw makeError("qcWallet.privateKey is empty or missing", "UNKNOWN_ERROR", {});
|
|
505
|
+
}
|
|
506
|
+
if (!pubSrc || (pubSrc instanceof Uint8Array && pubSrc.length === 0) || (Array.isArray(pubSrc) && pubSrc.length === 0)) {
|
|
507
|
+
throw makeError("qcWallet.publicKey is empty or missing", "UNKNOWN_ERROR", {});
|
|
508
|
+
}
|
|
509
|
+
|
|
477
510
|
const privBytes =
|
|
478
|
-
privSrc instanceof Uint8Array ? new Uint8Array(privSrc) : Uint8Array.from(Array.from(privSrc
|
|
511
|
+
privSrc instanceof Uint8Array ? new Uint8Array(privSrc) : Uint8Array.from(Array.from(privSrc).map((n) => (Number(n) & 0xff)));
|
|
479
512
|
const pubBytes =
|
|
480
|
-
pubSrc instanceof Uint8Array ? new Uint8Array(pubSrc) : Uint8Array.from(Array.from(pubSrc
|
|
513
|
+
pubSrc instanceof Uint8Array ? new Uint8Array(pubSrc) : Uint8Array.from(Array.from(pubSrc).map((n) => (Number(n) & 0xff)));
|
|
481
514
|
const key = new SigningKey(privBytes, pubBytes);
|
|
482
515
|
|
|
483
516
|
const w = new Wallet(key, provider || null);
|
|
@@ -486,6 +519,12 @@ class Wallet extends BaseWallet {
|
|
|
486
519
|
if (typeof qcWallet.address === "string") {
|
|
487
520
|
w.address = normalizeHex(qcWallet.address);
|
|
488
521
|
}
|
|
522
|
+
if (qcWallet.preExpansionSeed != null) {
|
|
523
|
+
const seedSrc = qcWallet.preExpansionSeed;
|
|
524
|
+
const seedBytes =
|
|
525
|
+
seedSrc instanceof Uint8Array ? seedSrc : Uint8Array.from(Array.from(seedSrc).map((n) => (Number(n) & 0xff)));
|
|
526
|
+
w._seed = bytesToHex(seedBytes);
|
|
527
|
+
}
|
|
489
528
|
return w;
|
|
490
529
|
}
|
|
491
530
|
}
|