mmn-client-js 1.0.5 → 1.0.7
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 +22 -7
- package/dist/index.esm.js +205 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +205 -78
- 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,31 +12,81 @@ 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`;
|
|
37
86
|
const res = await this.makeRequest('GET', path);
|
|
38
87
|
return res.data.transaction;
|
|
39
88
|
}
|
|
40
|
-
async getTransactionByWallet(wallet, page = 1, limit = 50, filter) {
|
|
89
|
+
async getTransactionByWallet(wallet, page = 1, limit = 50, filter, sortBy = 'transaction_timestamp', sortOrder = 'desc') {
|
|
41
90
|
if (!wallet) {
|
|
42
91
|
throw new Error('wallet address cannot be empty');
|
|
43
92
|
}
|
|
@@ -50,8 +99,8 @@ class IndexerClient {
|
|
|
50
99
|
const params = {
|
|
51
100
|
page: page - 1,
|
|
52
101
|
limit,
|
|
53
|
-
sort_by:
|
|
54
|
-
sort_order:
|
|
102
|
+
sort_by: sortBy,
|
|
103
|
+
sort_order: sortOrder,
|
|
55
104
|
};
|
|
56
105
|
switch (filter) {
|
|
57
106
|
case API_FILTER_PARAMS.ALL:
|
|
@@ -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,36 @@ 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
|
+
console.log('🚀 ~ MmnClient ~ makeRequest ~ response:', response);
|
|
7719
|
+
clearTimeout(timeoutId);
|
|
7720
|
+
if (!response.ok) {
|
|
7721
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
7722
|
+
}
|
|
7723
|
+
const result = await response.json();
|
|
7645
7724
|
if (result.error) {
|
|
7646
7725
|
throw new Error(`JSON-RPC Error ${result.error.code}: ${result.error.message}`);
|
|
7647
7726
|
}
|
|
7648
7727
|
return result.result;
|
|
7649
7728
|
}
|
|
7650
7729
|
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
|
-
}
|
|
7730
|
+
clearTimeout(timeoutId);
|
|
7665
7731
|
if (error instanceof Error) {
|
|
7732
|
+
if (error.name === 'AbortError') {
|
|
7733
|
+
throw new Error(`Request timeout after ${this.config.timeout || 30000}ms`);
|
|
7734
|
+
}
|
|
7666
7735
|
throw error;
|
|
7667
7736
|
}
|
|
7668
7737
|
throw new Error('Unknown error occurred');
|
|
@@ -7683,22 +7752,31 @@ class MmnClient {
|
|
|
7683
7752
|
throw new Error(`Ed25519 private key must be exactly ${CRYPTO_CONSTANTS.ED25519_PRIVATE_KEY_LENGTH} bytes`);
|
|
7684
7753
|
}
|
|
7685
7754
|
try {
|
|
7686
|
-
// Ed25519 OID: 1.3.101.112 (
|
|
7687
|
-
const ED25519_OID = BufferCompat.from(
|
|
7755
|
+
// Ed25519 OID: 1.3.101.112 (RFC 8410 - Algorithm Identifiers for Ed25519)
|
|
7756
|
+
const ED25519_OID = BufferCompat.from(CRYPTO_CONSTANTS.ED25519_OID_BYTES);
|
|
7688
7757
|
const VERSION_BYTES = BufferCompat.from([
|
|
7689
7758
|
CRYPTO_CONSTANTS.ASN1_INTEGER_TAG,
|
|
7690
|
-
0x01,
|
|
7759
|
+
0x01, // Length of integer (1 byte)
|
|
7691
7760
|
CRYPTO_CONSTANTS.PKCS8_VERSION,
|
|
7692
|
-
]);
|
|
7693
|
-
// Create algorithm identifier sequence
|
|
7761
|
+
]);
|
|
7762
|
+
// Create algorithm identifier sequence (AlgorithmIdentifier)
|
|
7694
7763
|
const algorithmId = BufferCompat.concat([
|
|
7695
|
-
BufferCompat.from([
|
|
7764
|
+
BufferCompat.from([
|
|
7765
|
+
CRYPTO_CONSTANTS.ASN1_SEQUENCE_TAG,
|
|
7766
|
+
CRYPTO_CONSTANTS.PKCS8_ALGORITHM_ID_LENGTH,
|
|
7767
|
+
]),
|
|
7696
7768
|
ED25519_OID,
|
|
7697
7769
|
]);
|
|
7698
|
-
// Create private key octet string
|
|
7770
|
+
// Create private key octet string (wrapped Ed25519 private key)
|
|
7699
7771
|
const privateKeyOctetString = BufferCompat.concat([
|
|
7700
|
-
BufferCompat.from([
|
|
7701
|
-
|
|
7772
|
+
BufferCompat.from([
|
|
7773
|
+
CRYPTO_CONSTANTS.ASN1_OCTET_STRING_TAG,
|
|
7774
|
+
CRYPTO_CONSTANTS.PKCS8_PRIVATE_KEY_OCTET_OUTER_LENGTH,
|
|
7775
|
+
]), // OCTET STRING, length 34
|
|
7776
|
+
BufferCompat.from([
|
|
7777
|
+
CRYPTO_CONSTANTS.ASN1_OCTET_STRING_TAG,
|
|
7778
|
+
CRYPTO_CONSTANTS.PKCS8_PRIVATE_KEY_OCTET_INNER_LENGTH,
|
|
7779
|
+
]), // inner OCTET STRING, length 32
|
|
7702
7780
|
raw,
|
|
7703
7781
|
]);
|
|
7704
7782
|
// Create PKCS#8 body
|
|
@@ -7727,17 +7805,28 @@ class MmnClient {
|
|
|
7727
7805
|
throw new Error(`Failed to convert private key to PKCS#8: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
7728
7806
|
}
|
|
7729
7807
|
}
|
|
7808
|
+
/**
|
|
7809
|
+
* Encode length in ASN.1 DER format
|
|
7810
|
+
* ASN.1 length encoding rules:
|
|
7811
|
+
* - Short form (0-127): single byte with the length value
|
|
7812
|
+
* - Long form (128+): first byte is 0x80 + number of length bytes, followed by length bytes
|
|
7813
|
+
* @param length - The length value to encode
|
|
7814
|
+
* @returns ASN.1 DER encoded length bytes
|
|
7815
|
+
*/
|
|
7730
7816
|
encodeLength(length) {
|
|
7731
|
-
if (length <
|
|
7817
|
+
if (length < CRYPTO_CONSTANTS.ASN1_LENGTH) {
|
|
7732
7818
|
return BufferCompat.from([length]);
|
|
7733
7819
|
}
|
|
7734
7820
|
const bytes = [];
|
|
7735
7821
|
let len = length;
|
|
7736
7822
|
while (len > 0) {
|
|
7737
|
-
bytes.unshift(len &
|
|
7823
|
+
bytes.unshift(len & PRNG_CONSTANTS.BYTE_MASK);
|
|
7738
7824
|
len >>= 8;
|
|
7739
7825
|
}
|
|
7740
|
-
return BufferCompat.from([
|
|
7826
|
+
return BufferCompat.from([
|
|
7827
|
+
CRYPTO_CONSTANTS.ASN1_LENGTH | bytes.length,
|
|
7828
|
+
...bytes,
|
|
7829
|
+
]);
|
|
7741
7830
|
}
|
|
7742
7831
|
/**
|
|
7743
7832
|
* Generate secure entropy using multiple sources for maximum compatibility
|
|
@@ -7754,19 +7843,25 @@ class MmnClient {
|
|
|
7754
7843
|
const random = Math.random();
|
|
7755
7844
|
// Create initial seed from timestamp and random
|
|
7756
7845
|
let seed = now + performance + random;
|
|
7757
|
-
// Generate bytes using
|
|
7846
|
+
// Generate bytes using Linear Congruential Generator (LCG) with multiple entropy sources
|
|
7847
|
+
// This provides a fallback Pseudorandom Number Generator (PRNG) when crypto.getRandomValues is not available
|
|
7758
7848
|
for (let i = 0; i < targetLength; i++) {
|
|
7759
|
-
//
|
|
7760
|
-
seed =
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
//
|
|
7849
|
+
// Xₙ₊₁ = (a * Xₙ + c) mod m
|
|
7850
|
+
seed =
|
|
7851
|
+
(seed * PRNG_CONSTANTS.LCG_MULTIPLIER + PRNG_CONSTANTS.LCG_INCREMENT) %
|
|
7852
|
+
PRNG_CONSTANTS.LCG_MODULUS;
|
|
7853
|
+
// Mix with timestamp to add time-based entropy
|
|
7854
|
+
seed ^= (now + i) * PRNG_CONSTANTS.TIMESTAMP_MULTIPLIER;
|
|
7855
|
+
// Mix with Math.random() for additional browser-provided randomness
|
|
7856
|
+
seed ^= Math.floor(Math.random() * PRNG_CONSTANTS.LCG_MODULUS);
|
|
7857
|
+
// Additional cryptographic mixing using SHA256 if CryptoJS is available
|
|
7764
7858
|
if (typeof CryptoJS !== 'undefined') {
|
|
7765
7859
|
const hashInput = seed.toString() + i.toString() + now.toString();
|
|
7766
7860
|
const hash = CryptoJS.SHA256(hashInput).toString();
|
|
7767
|
-
|
|
7861
|
+
// Extract first 8 hex characters (32 bits) from hash for mixing
|
|
7862
|
+
seed ^= parseInt(hash.substring(0, PRNG_CONSTANTS.HASH_SUBSTRING_LENGTH), 16);
|
|
7768
7863
|
}
|
|
7769
|
-
entropy.push((seed >>>
|
|
7864
|
+
entropy.push((seed >>> PRNG_CONSTANTS.BYTE_SHIFT) & PRNG_CONSTANTS.BYTE_MASK);
|
|
7770
7865
|
}
|
|
7771
7866
|
return entropy;
|
|
7772
7867
|
}
|
|
@@ -7971,24 +8066,56 @@ exports.ETransferType = void 0;
|
|
|
7971
8066
|
class ZkClient {
|
|
7972
8067
|
constructor(config) {
|
|
7973
8068
|
this.endpoint = config.endpoint;
|
|
7974
|
-
this.
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
...(config.headers || {}),
|
|
7981
|
-
},
|
|
7982
|
-
});
|
|
8069
|
+
this.timeout = config.timeout || 30000;
|
|
8070
|
+
this.headers = {
|
|
8071
|
+
Accept: 'application/json',
|
|
8072
|
+
'Content-Type': 'application/json',
|
|
8073
|
+
...(config.headers || {}),
|
|
8074
|
+
};
|
|
7983
8075
|
}
|
|
7984
8076
|
async makeRequest(method, path, params, body) {
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
8077
|
+
let url = `${this.endpoint}/${path}`;
|
|
8078
|
+
// Add query parameters for GET requests
|
|
8079
|
+
if (params && Object.keys(params).length > 0) {
|
|
8080
|
+
const searchParams = new URLSearchParams();
|
|
8081
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
8082
|
+
searchParams.append(key, String(value));
|
|
8083
|
+
});
|
|
8084
|
+
url += `?${searchParams.toString()}`;
|
|
8085
|
+
}
|
|
8086
|
+
// Create AbortController for timeout
|
|
8087
|
+
const controller = new AbortController();
|
|
8088
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
8089
|
+
try {
|
|
8090
|
+
const requestOptions = {
|
|
8091
|
+
method,
|
|
8092
|
+
mode: 'cors',
|
|
8093
|
+
credentials: 'omit',
|
|
8094
|
+
signal: controller.signal,
|
|
8095
|
+
headers: this.headers,
|
|
8096
|
+
};
|
|
8097
|
+
// Add body for POST requests
|
|
8098
|
+
if (method === 'POST' && body) {
|
|
8099
|
+
requestOptions.body = JSON.stringify(body);
|
|
8100
|
+
}
|
|
8101
|
+
const response = await fetch(url, requestOptions);
|
|
8102
|
+
clearTimeout(timeoutId);
|
|
8103
|
+
if (!response.ok) {
|
|
8104
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
8105
|
+
}
|
|
8106
|
+
const data = await response.json();
|
|
8107
|
+
return data;
|
|
8108
|
+
}
|
|
8109
|
+
catch (error) {
|
|
8110
|
+
clearTimeout(timeoutId);
|
|
8111
|
+
if (error instanceof Error) {
|
|
8112
|
+
if (error.name === 'AbortError') {
|
|
8113
|
+
throw new Error(`Request timeout after ${this.timeout}ms`);
|
|
8114
|
+
}
|
|
8115
|
+
throw error;
|
|
8116
|
+
}
|
|
8117
|
+
throw new Error('Request failed');
|
|
8118
|
+
}
|
|
7992
8119
|
}
|
|
7993
8120
|
async getZkProofs({ userId, ephemeralPublicKey, jwt, address, }) {
|
|
7994
8121
|
const path = `prove`;
|