mmn-client-js 1.0.6 → 1.0.8
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/dist/index.d.ts +21 -6
- package/dist/index.esm.js +201 -75
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +201 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var axios = require('axios');
|
|
4
3
|
var bs58 = require('bs58');
|
|
5
4
|
var nacl = require('tweetnacl');
|
|
6
5
|
|
|
@@ -13,24 +12,74 @@ class IndexerClient {
|
|
|
13
12
|
constructor(config) {
|
|
14
13
|
this.endpoint = config.endpoint;
|
|
15
14
|
this.chainId = config.chainId;
|
|
16
|
-
this.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
...(config.headers || {}),
|
|
23
|
-
},
|
|
24
|
-
});
|
|
15
|
+
this.timeout = config.timeout || 30000;
|
|
16
|
+
// Minimal headers to avoid CORS preflight issues
|
|
17
|
+
this.headers = {
|
|
18
|
+
Accept: 'application/json',
|
|
19
|
+
...(config.headers || {}),
|
|
20
|
+
};
|
|
25
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Make HTTP request with automatic CORS handling
|
|
24
|
+
* Works out-of-the-box without CORS configuration
|
|
25
|
+
* @param method - HTTP method (GET or POST)
|
|
26
|
+
* @param path - API endpoint path
|
|
27
|
+
* @param params - URL query parameters
|
|
28
|
+
* @param body - Request body for POST requests
|
|
29
|
+
* @returns Promise resolving to response data
|
|
30
|
+
*/
|
|
26
31
|
async makeRequest(method, path, params, body) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Build full URL
|
|
33
|
+
let url = `${this.endpoint}/${path}`;
|
|
34
|
+
// Add query parameters
|
|
35
|
+
if (params && Object.keys(params).length > 0) {
|
|
36
|
+
const searchParams = new URLSearchParams();
|
|
37
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
38
|
+
searchParams.append(key, String(value));
|
|
39
|
+
});
|
|
40
|
+
url += `?${searchParams.toString()}`;
|
|
41
|
+
}
|
|
42
|
+
// Create AbortController for timeout
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
45
|
+
try {
|
|
46
|
+
// Simple fetch with automatic CORS handling
|
|
47
|
+
const requestOptions = {
|
|
48
|
+
method,
|
|
49
|
+
mode: 'cors',
|
|
50
|
+
credentials: 'omit',
|
|
51
|
+
signal: controller.signal,
|
|
52
|
+
headers: {
|
|
53
|
+
Accept: 'application/json',
|
|
54
|
+
...this.headers,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
// Add body and Content-Type for POST requests
|
|
58
|
+
if (method === 'POST' && body) {
|
|
59
|
+
requestOptions.body = JSON.stringify(body);
|
|
60
|
+
requestOptions.headers['Content-Type'] =
|
|
61
|
+
'application/json';
|
|
62
|
+
}
|
|
63
|
+
const response = await fetch(url, requestOptions);
|
|
64
|
+
clearTimeout(timeoutId);
|
|
65
|
+
// Handle response errors
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
68
|
+
}
|
|
69
|
+
// Parse JSON response
|
|
70
|
+
const data = await response.json();
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
clearTimeout(timeoutId);
|
|
75
|
+
if (error instanceof Error) {
|
|
76
|
+
if (error.name === 'AbortError') {
|
|
77
|
+
throw new Error(`Request timeout after ${this.timeout}ms`);
|
|
78
|
+
}
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
throw new Error('Request failed');
|
|
82
|
+
}
|
|
34
83
|
}
|
|
35
84
|
async getTransactionByHash(hash) {
|
|
36
85
|
const path = `${this.chainId}/tx/${hash}/detail`;
|
|
@@ -7606,9 +7655,28 @@ const CRYPTO_CONSTANTS = {
|
|
|
7606
7655
|
ED25519_PUBLIC_KEY_LENGTH: 32,
|
|
7607
7656
|
MNEMONIC_ENTROPY_BITS: 128,
|
|
7608
7657
|
PKCS8_VERSION: 0,
|
|
7658
|
+
// ASN.1 DER encoding
|
|
7609
7659
|
ASN1_SEQUENCE_TAG: 0x30,
|
|
7610
7660
|
ASN1_OCTET_STRING_TAG: 0x04,
|
|
7611
7661
|
ASN1_INTEGER_TAG: 0x02,
|
|
7662
|
+
ASN1_LENGTH: 0x80,
|
|
7663
|
+
// Ed25519 OID bytes: 1.3.101.112 (RFC 8410)
|
|
7664
|
+
ED25519_OID_BYTES: [0x06, 0x03, 0x2b, 0x65, 0x70],
|
|
7665
|
+
// PKCS#8 structure length constants
|
|
7666
|
+
PKCS8_ALGORITHM_ID_LENGTH: 0x0b, // SEQUENCE length for algorithm identifier
|
|
7667
|
+
PKCS8_PRIVATE_KEY_OCTET_OUTER_LENGTH: 0x22, // Outer OCTET STRING length (34 bytes)
|
|
7668
|
+
PKCS8_PRIVATE_KEY_OCTET_INNER_LENGTH: 0x20, // Inner OCTET STRING length (32 bytes)
|
|
7669
|
+
};
|
|
7670
|
+
// PRNG (Pseudo-Random Number Generator) constants
|
|
7671
|
+
const PRNG_CONSTANTS = {
|
|
7672
|
+
// Numerical Recipes LCG
|
|
7673
|
+
LCG_MULTIPLIER: 1664525, // LCG multiplier (from Numerical Recipes)
|
|
7674
|
+
LCG_INCREMENT: 1013904223, // LCG increment
|
|
7675
|
+
LCG_MODULUS: 4294967296, // 2^32 modulus for LCG
|
|
7676
|
+
TIMESTAMP_MULTIPLIER: 2654435761, // Golden Ratio constant
|
|
7677
|
+
HASH_SUBSTRING_LENGTH: 8,
|
|
7678
|
+
BYTE_SHIFT: 24,
|
|
7679
|
+
BYTE_MASK: 0xff,
|
|
7612
7680
|
};
|
|
7613
7681
|
const TX_TYPE = {
|
|
7614
7682
|
TRANSFER: 0,
|
|
@@ -7622,15 +7690,10 @@ class MmnClient {
|
|
|
7622
7690
|
timeout: 30000,
|
|
7623
7691
|
headers: {
|
|
7624
7692
|
'Content-Type': 'application/json',
|
|
7693
|
+
Accept: 'application/json',
|
|
7625
7694
|
},
|
|
7626
7695
|
...config,
|
|
7627
7696
|
};
|
|
7628
|
-
this.axiosInstance = axios.create({
|
|
7629
|
-
baseURL: this.config.baseUrl,
|
|
7630
|
-
timeout: this.config.timeout || 30000,
|
|
7631
|
-
headers: this.config.headers || {},
|
|
7632
|
-
...(this.config.axiosConfig || {}),
|
|
7633
|
-
});
|
|
7634
7697
|
}
|
|
7635
7698
|
async makeRequest(method, params) {
|
|
7636
7699
|
const request = {
|
|
@@ -7639,30 +7702,35 @@ class MmnClient {
|
|
|
7639
7702
|
params,
|
|
7640
7703
|
id: ++this.requestId,
|
|
7641
7704
|
};
|
|
7705
|
+
// Create AbortController for timeout
|
|
7706
|
+
const controller = new AbortController();
|
|
7707
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout || 30000);
|
|
7642
7708
|
try {
|
|
7643
|
-
const
|
|
7644
|
-
|
|
7709
|
+
const requestOptions = {
|
|
7710
|
+
method: 'POST',
|
|
7711
|
+
mode: 'cors',
|
|
7712
|
+
credentials: 'omit',
|
|
7713
|
+
signal: controller.signal,
|
|
7714
|
+
headers: this.config.headers || {},
|
|
7715
|
+
body: JSON.stringify(request),
|
|
7716
|
+
};
|
|
7717
|
+
const response = await fetch(this.config.baseUrl, requestOptions);
|
|
7718
|
+
clearTimeout(timeoutId);
|
|
7719
|
+
if (!response.ok) {
|
|
7720
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
7721
|
+
}
|
|
7722
|
+
const result = await response.json();
|
|
7645
7723
|
if (result.error) {
|
|
7646
7724
|
throw new Error(`JSON-RPC Error ${result.error.code}: ${result.error.message}`);
|
|
7647
7725
|
}
|
|
7648
7726
|
return result.result;
|
|
7649
7727
|
}
|
|
7650
7728
|
catch (error) {
|
|
7651
|
-
|
|
7652
|
-
if (error.response) {
|
|
7653
|
-
// Server responded with error status
|
|
7654
|
-
throw new Error(`HTTP ${error.response.status}: ${error.response.statusText}`);
|
|
7655
|
-
}
|
|
7656
|
-
else if (error.request) {
|
|
7657
|
-
// Request was made but no response received
|
|
7658
|
-
throw new Error('Network error: No response received');
|
|
7659
|
-
}
|
|
7660
|
-
else {
|
|
7661
|
-
// Something else happened
|
|
7662
|
-
throw new Error(`Request error: ${error.message}`);
|
|
7663
|
-
}
|
|
7664
|
-
}
|
|
7729
|
+
clearTimeout(timeoutId);
|
|
7665
7730
|
if (error instanceof Error) {
|
|
7731
|
+
if (error.name === 'AbortError') {
|
|
7732
|
+
throw new Error(`Request timeout after ${this.config.timeout || 30000}ms`);
|
|
7733
|
+
}
|
|
7666
7734
|
throw error;
|
|
7667
7735
|
}
|
|
7668
7736
|
throw new Error('Unknown error occurred');
|
|
@@ -7683,22 +7751,31 @@ class MmnClient {
|
|
|
7683
7751
|
throw new Error(`Ed25519 private key must be exactly ${CRYPTO_CONSTANTS.ED25519_PRIVATE_KEY_LENGTH} bytes`);
|
|
7684
7752
|
}
|
|
7685
7753
|
try {
|
|
7686
|
-
// Ed25519 OID: 1.3.101.112 (
|
|
7687
|
-
const ED25519_OID = BufferCompat.from(
|
|
7754
|
+
// Ed25519 OID: 1.3.101.112 (RFC 8410 - Algorithm Identifiers for Ed25519)
|
|
7755
|
+
const ED25519_OID = BufferCompat.from(CRYPTO_CONSTANTS.ED25519_OID_BYTES);
|
|
7688
7756
|
const VERSION_BYTES = BufferCompat.from([
|
|
7689
7757
|
CRYPTO_CONSTANTS.ASN1_INTEGER_TAG,
|
|
7690
|
-
0x01,
|
|
7758
|
+
0x01, // Length of integer (1 byte)
|
|
7691
7759
|
CRYPTO_CONSTANTS.PKCS8_VERSION,
|
|
7692
|
-
]);
|
|
7693
|
-
// Create algorithm identifier sequence
|
|
7760
|
+
]);
|
|
7761
|
+
// Create algorithm identifier sequence (AlgorithmIdentifier)
|
|
7694
7762
|
const algorithmId = BufferCompat.concat([
|
|
7695
|
-
BufferCompat.from([
|
|
7763
|
+
BufferCompat.from([
|
|
7764
|
+
CRYPTO_CONSTANTS.ASN1_SEQUENCE_TAG,
|
|
7765
|
+
CRYPTO_CONSTANTS.PKCS8_ALGORITHM_ID_LENGTH,
|
|
7766
|
+
]),
|
|
7696
7767
|
ED25519_OID,
|
|
7697
7768
|
]);
|
|
7698
|
-
// Create private key octet string
|
|
7769
|
+
// Create private key octet string (wrapped Ed25519 private key)
|
|
7699
7770
|
const privateKeyOctetString = BufferCompat.concat([
|
|
7700
|
-
BufferCompat.from([
|
|
7701
|
-
|
|
7771
|
+
BufferCompat.from([
|
|
7772
|
+
CRYPTO_CONSTANTS.ASN1_OCTET_STRING_TAG,
|
|
7773
|
+
CRYPTO_CONSTANTS.PKCS8_PRIVATE_KEY_OCTET_OUTER_LENGTH,
|
|
7774
|
+
]), // OCTET STRING, length 34
|
|
7775
|
+
BufferCompat.from([
|
|
7776
|
+
CRYPTO_CONSTANTS.ASN1_OCTET_STRING_TAG,
|
|
7777
|
+
CRYPTO_CONSTANTS.PKCS8_PRIVATE_KEY_OCTET_INNER_LENGTH,
|
|
7778
|
+
]), // inner OCTET STRING, length 32
|
|
7702
7779
|
raw,
|
|
7703
7780
|
]);
|
|
7704
7781
|
// Create PKCS#8 body
|
|
@@ -7727,17 +7804,28 @@ class MmnClient {
|
|
|
7727
7804
|
throw new Error(`Failed to convert private key to PKCS#8: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
7728
7805
|
}
|
|
7729
7806
|
}
|
|
7807
|
+
/**
|
|
7808
|
+
* Encode length in ASN.1 DER format
|
|
7809
|
+
* ASN.1 length encoding rules:
|
|
7810
|
+
* - Short form (0-127): single byte with the length value
|
|
7811
|
+
* - Long form (128+): first byte is 0x80 + number of length bytes, followed by length bytes
|
|
7812
|
+
* @param length - The length value to encode
|
|
7813
|
+
* @returns ASN.1 DER encoded length bytes
|
|
7814
|
+
*/
|
|
7730
7815
|
encodeLength(length) {
|
|
7731
|
-
if (length <
|
|
7816
|
+
if (length < CRYPTO_CONSTANTS.ASN1_LENGTH) {
|
|
7732
7817
|
return BufferCompat.from([length]);
|
|
7733
7818
|
}
|
|
7734
7819
|
const bytes = [];
|
|
7735
7820
|
let len = length;
|
|
7736
7821
|
while (len > 0) {
|
|
7737
|
-
bytes.unshift(len &
|
|
7822
|
+
bytes.unshift(len & PRNG_CONSTANTS.BYTE_MASK);
|
|
7738
7823
|
len >>= 8;
|
|
7739
7824
|
}
|
|
7740
|
-
return BufferCompat.from([
|
|
7825
|
+
return BufferCompat.from([
|
|
7826
|
+
CRYPTO_CONSTANTS.ASN1_LENGTH | bytes.length,
|
|
7827
|
+
...bytes,
|
|
7828
|
+
]);
|
|
7741
7829
|
}
|
|
7742
7830
|
/**
|
|
7743
7831
|
* Generate secure entropy using multiple sources for maximum compatibility
|
|
@@ -7754,19 +7842,25 @@ class MmnClient {
|
|
|
7754
7842
|
const random = Math.random();
|
|
7755
7843
|
// Create initial seed from timestamp and random
|
|
7756
7844
|
let seed = now + performance + random;
|
|
7757
|
-
// Generate bytes using
|
|
7845
|
+
// Generate bytes using Linear Congruential Generator (LCG) with multiple entropy sources
|
|
7846
|
+
// This provides a fallback Pseudorandom Number Generator (PRNG) when crypto.getRandomValues is not available
|
|
7758
7847
|
for (let i = 0; i < targetLength; i++) {
|
|
7759
|
-
//
|
|
7760
|
-
seed =
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
//
|
|
7848
|
+
// Xₙ₊₁ = (a * Xₙ + c) mod m
|
|
7849
|
+
seed =
|
|
7850
|
+
(seed * PRNG_CONSTANTS.LCG_MULTIPLIER + PRNG_CONSTANTS.LCG_INCREMENT) %
|
|
7851
|
+
PRNG_CONSTANTS.LCG_MODULUS;
|
|
7852
|
+
// Mix with timestamp to add time-based entropy
|
|
7853
|
+
seed ^= (now + i) * PRNG_CONSTANTS.TIMESTAMP_MULTIPLIER;
|
|
7854
|
+
// Mix with Math.random() for additional browser-provided randomness
|
|
7855
|
+
seed ^= Math.floor(Math.random() * PRNG_CONSTANTS.LCG_MODULUS);
|
|
7856
|
+
// Additional cryptographic mixing using SHA256 if CryptoJS is available
|
|
7764
7857
|
if (typeof CryptoJS !== 'undefined') {
|
|
7765
7858
|
const hashInput = seed.toString() + i.toString() + now.toString();
|
|
7766
7859
|
const hash = CryptoJS.SHA256(hashInput).toString();
|
|
7767
|
-
|
|
7860
|
+
// Extract first 8 hex characters (32 bits) from hash for mixing
|
|
7861
|
+
seed ^= parseInt(hash.substring(0, PRNG_CONSTANTS.HASH_SUBSTRING_LENGTH), 16);
|
|
7768
7862
|
}
|
|
7769
|
-
entropy.push((seed >>>
|
|
7863
|
+
entropy.push((seed >>> PRNG_CONSTANTS.BYTE_SHIFT) & PRNG_CONSTANTS.BYTE_MASK);
|
|
7770
7864
|
}
|
|
7771
7865
|
return entropy;
|
|
7772
7866
|
}
|
|
@@ -7971,24 +8065,56 @@ exports.ETransferType = void 0;
|
|
|
7971
8065
|
class ZkClient {
|
|
7972
8066
|
constructor(config) {
|
|
7973
8067
|
this.endpoint = config.endpoint;
|
|
7974
|
-
this.
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
...(config.headers || {}),
|
|
7981
|
-
},
|
|
7982
|
-
});
|
|
8068
|
+
this.timeout = config.timeout || 30000;
|
|
8069
|
+
this.headers = {
|
|
8070
|
+
Accept: 'application/json',
|
|
8071
|
+
'Content-Type': 'application/json',
|
|
8072
|
+
...(config.headers || {}),
|
|
8073
|
+
};
|
|
7983
8074
|
}
|
|
7984
8075
|
async makeRequest(method, path, params, body) {
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
8076
|
+
let url = `${this.endpoint}/${path}`;
|
|
8077
|
+
// Add query parameters for GET requests
|
|
8078
|
+
if (params && Object.keys(params).length > 0) {
|
|
8079
|
+
const searchParams = new URLSearchParams();
|
|
8080
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
8081
|
+
searchParams.append(key, String(value));
|
|
8082
|
+
});
|
|
8083
|
+
url += `?${searchParams.toString()}`;
|
|
8084
|
+
}
|
|
8085
|
+
// Create AbortController for timeout
|
|
8086
|
+
const controller = new AbortController();
|
|
8087
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
8088
|
+
try {
|
|
8089
|
+
const requestOptions = {
|
|
8090
|
+
method,
|
|
8091
|
+
mode: 'cors',
|
|
8092
|
+
credentials: 'omit',
|
|
8093
|
+
signal: controller.signal,
|
|
8094
|
+
headers: this.headers,
|
|
8095
|
+
};
|
|
8096
|
+
// Add body for POST requests
|
|
8097
|
+
if (method === 'POST' && body) {
|
|
8098
|
+
requestOptions.body = JSON.stringify(body);
|
|
8099
|
+
}
|
|
8100
|
+
const response = await fetch(url, requestOptions);
|
|
8101
|
+
clearTimeout(timeoutId);
|
|
8102
|
+
if (!response.ok) {
|
|
8103
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
8104
|
+
}
|
|
8105
|
+
const data = await response.json();
|
|
8106
|
+
return data;
|
|
8107
|
+
}
|
|
8108
|
+
catch (error) {
|
|
8109
|
+
clearTimeout(timeoutId);
|
|
8110
|
+
if (error instanceof Error) {
|
|
8111
|
+
if (error.name === 'AbortError') {
|
|
8112
|
+
throw new Error(`Request timeout after ${this.timeout}ms`);
|
|
8113
|
+
}
|
|
8114
|
+
throw error;
|
|
8115
|
+
}
|
|
8116
|
+
throw new Error('Request failed');
|
|
8117
|
+
}
|
|
7992
8118
|
}
|
|
7993
8119
|
async getZkProofs({ userId, ephemeralPublicKey, jwt, address, }) {
|
|
7994
8120
|
const path = `prove`;
|